What methods are available to achieve accessing parent instance Vector cell from another class?
My question is about the lines commented with "??":
class Test {
static function main() {
var a:A = new A();
var b:B = new B(a, 115);
}
}
class A {
public var cells:haxe.ds.Vector<Float>;
public function new() {
cells = new haxe.ds.Vector(1000);
}
}
class B {
public var a:A; // the "parent"
public var my_offset:Int;
public var my_cells:haxe.ds.Vector<Float>; //??
public function new(a:A, offset:Int) {
my_offset = offset;
my_cells[2] = 0.5; //?? actually a.cells[my_offset + 2];
}
}
Is it possible to:
access parent Vector memory directly?
use a macro?
use an abstract?
"Try Haxe" link
You could create an abstract type that wraps a Vector, automatically adding the desired offset by defining #:arrayAccess() methods:
class Main {
static function main() {
var cells = new haxe.ds.Vector(1000);
cells[115] = 1.5;
var cellsWithOffset = new VectorWithOffset(cells, 115);
trace(cellsWithOffset[0]); // 1.5
}
}
abstract VectorWithOffset<T>(VectorWithOffsetData<T>) {
public function new(vector:haxe.ds.Vector<T>, offset:Int) {
this = {vector: vector, offset: offset};
}
#:arrayAccess inline function get(i:Int):T {
return this.vector[i + this.offset];
}
#:arrayAccess inline function set(i:Int, v:T):T {
return this.vector[i + this.offset] = v;
}
}
typedef VectorWithOffsetData<T> = {
var vector:haxe.ds.Vector<T>;
var offset:Int;
}
Note: the abstract doesn't need to necessarily wrap a structure, it could also be a class. You can't wrap Vector directly though, as the offset needs to be stored somewhere, and abstracts can't have member variables of their own.
Related
I have a problem, I am working on a larger project, and I made a small project to test this problem.
The problem being:
I have made a button which spawns enemy's. When an enemy hits allyCopy it bounces back in the opposite direction. But the problem is that EVERY instance of enemy bounces back when a single one hits the test object.
My code:
my main class:
package {
import flash.display.*;
import flash.ui.*;
import flash.events.*;
public class MainClass extends MovieClip {
public var speed:int = 3;
public static var enemyArray:Array = [];
public var randNumber:Number = 0;
public static var allyCopy1 = new allyCopy();
public function MainClass() {
stage.addEventListener(Event.ENTER_FRAME, update);
spawnButton1.addEventListener(MouseEvent.CLICK, spawnEnemy);
allyCopy1.addEventListener(MouseEvent.MOUSE_DOWN, dragOn, true);
allyCopy1.addEventListener(MouseEvent.MOUSE_UP, dragOff, true);
addChild(allyCopy1);
allyCopy1.x = 60,25;
allyCopy1.y = 208,05;
}
public function update(e:Event)
{
/*for (var i:Number = 0; i < enemyArray.length; i++)
{
enemyArray[i].x -= speed;
}*/
}
public function dragOn (e:MouseEvent)
{
allyCopy1.startDrag();
trace("drag");
}
public function dragOff (e:MouseEvent)
{
allyCopy1.stopDrag();
}
public function spawnEnemy(e:MouseEvent)
{
randNumber = Math.random();
trace(randNumber);
var enemy1 = new enemy ();
addChild(enemy1);
enemyArray.push(enemy1);
if (randNumber <= .5)
{
enemy1.x = 526.25;
enemy1.y = 68.05;
} else
{
enemy1.x = 526.25;
enemy1.y = 200.05;
}
}
}
}
The enemy class:
package {
import flash.display.*;
import flash.events.*;
public class enemy extends MovieClip {
public static var hp:int = 100;
public static var speed = 3;
public function enemy() {
addEventListener(MouseEvent.CLICK, killEnemy);
addEventListener(Event.ENTER_FRAME, update);
}
public function update (e:Event) {
x -= speed;
if ( x <= 0)
{
MainClass.enemyArray.pop();
trace(MainClass.enemyArray);
}
if(MainClass.allyCopy1.hitTestObject(this))
{
speed = -3;
}
}
public function killEnemy (e:MouseEvent)
{
this.parent.removeChild(this);
trace(MainClass.enemyArray);
MainClass.enemyArray.pop();
}
}
}
Well the problem is that speed is static variable. This means that it's not separate for each enemy, but it's common (shared) for all instances. So if you change it, it changes everywhere..
Don't do variables static that often - it's pretty bad practice. The very same thing will happen with life - if you decrease the life of one enemy, it will decrease the life of all enemies (all instances of that class).
Im making an inventory and Im adding stacks but ive hit an issue
below is what I want compared to what works
I just want to find the index of the object I pass through
myArray[0] = [item:object,StackAmmount:int]
var myArray:Array = new Array();
myArray[0] = ["name1",1];
myArray[1] = ["name2",1];
myArray[2] = ["name3",1];
trace("Name" , myArray[0][0]);
//traces "name1"
trace("Stack" , myArray[0][1]);
//traces "1"
trace("Index of Object" , myArray.indexOf("name2"));
//traces -1
// Not Working (NOT FOUND)
//How can I find the index of "item1" or "item2" in the above example
var myOtherArray:Array = new Array();
myOtherArray[0] = "name1";
myOtherArray[1] = "name2";
myOtherArray[2] = "name3";
trace("Name" , myOtherArray[0]);
//traces "name1"
trace("Index of Object" , myOtherArray.indexOf("name2"));
//traces 1
//Working
perhaps there is a better way of dealing with stacks?
Paste Bin Link: http://pastebin.com/CQZWFmST
I would use a custom class, therefore a 1D vector would be enough. The class would contain the name of the item, and the stack. You could subclass this class to override the maxStack variable of the item, and then the searches would be easier aswell, you could just iterate through the vector and check the name.
public class InventoryItem
{
protected var _name:String;
protected var _stack:int;
protected var _maxStack:int;
public function InventoryItem():void {
}
public function get name():String {
return _name;
}
public function get stack():int {
return _stack;
}
public function set stack(value:int):void {
_stack = value;
}
public function get maxStack():int {
return _maxStack;
}
}
...
public class InventoryWeapon extends InventoryItem
{
public function InventoryWeapon(__name:String, startStack:int) {
_maxStack = 64;
_name = __name;
_stack = startStack;
}
}
I have encountered quite a challenging one and I'd love to get some support.
Here is the scenario :
The main Game class instances the Level1 Class in charge for spawning enemies through nested For loops and push them to an array.
It then checks for collisions between the Bullet and Enemy and if it find a collision it calls a method in the Enemy class that removes removeChild and Splice itself from the array.
The thing is it works for the first few enemies, and then it will pick the wrong Enemy to destroy, and stop completely to function.
I tried using indexOf to be sure I am referring to the right object, but to no avail.
I think the Pslice and removeChild are pointing to different objects.
This mess happended when I moved the removeChild and splice from the Game Class to the Enmy class
Link to the work in progress : https://dl.dropboxusercontent.com/s/69hcmzygnkx7h1e/space_shooter.swf
I'd like some help on this one.
Thank you !!!
Main class : Game.AS
package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.text.*;
import flash.geom.Point;
public class Game extends MovieClip
{
public var _instance : Game;
public var player:Player;
public static var level1:Level1;
public var bullet:Bullet;
private var bullets_arr:Array;
var fire_on : Boolean;
var fire_counter : int;
public function Game()
{
level1=new Level1(this.stage);
player = new Player ;
addChild(player);
player.y = 600;
bullets_arr = [];
addEventListener(Event.ENTER_FRAME,Main);
stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseDownHandler);
stage.addEventListener(MouseEvent.MOUSE_UP,mouseUpHandler);
}
function mouseDownHandler($e:MouseEvent):void
{
fire_on = true;
}
function mouseUpHandler($e:MouseEvent):void
{
fire_on = false;
fire_counter = 0;
}
function fire():void
{
bullet = new Bullet ;
addChild(bullet);
bullet.x = player.x;
bullet.y = player.y - 32;
bullets_arr.push(bullet);
}
public function Main(e: Event):void
{
player.x = mouseX;
if (bullets_arr)
{
for (var m:int = 0; m < bullets_arr.length; m++)
{
bullets_arr[m].y -= 20;
if(Game.level1.enemies_arr)
{
for (var n:int = 0; n < Game.level1.enemies_arr.length; n++)
{
if (Game.level1.enemies_arr[n].hitTestObject(bullets_arr[m]))
{
if(bullets_arr[m].parent)
{
bullets_arr[m].parent.removeChild(bullets_arr[m]);
bullets_arr.splice(bullets_arr[m],1);
Game.level1.enemies_arr[n].Damage(10, Game.level1.enemies_arr[n]);
}
}
}
}
}
}
if(fire_on)
{
fire_counter++;
if(fire_counter == 01)
{
fire();
}
else if(fire_counter >2)
{
fire_counter =0;
}
}
}
}
}
Level1.as where the enemies are spawned and pushed to the array.
package
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
public class Level1 extends MovieClip
{
var i:int;
var j:int;
var frame :int;
public var enemy:Enemy;
public var enemies_arr:Array;
public function Level1(target:Stage)
{
frame = 0;
enemies_arr = [];
for (var i:int = 0; i < 5; i++)
{
for (var j:int = 0; j < 3; j++)
{
enemy = new Enemy;
enemy.x = j*100 + 260;
enemy.y = i*40 - 150;
target.addChild(enemy);
enemies_arr.push(enemy);
trace(enemy.parent);
}
}
}
}
}
The Enemy class Enemy.AS
package
{
import flash.display.MovieClip;
public class Enemy extends MovieClip
{
var Health : int;
function Enemy()
{
Health =2;
}
public function Damage(Damage:int, enemyHit:Enemy)
{
Health -= Damage;
if (Health <1)
{
Die(enemyHit);
}
}
private function Die(enemyHit:Enemy)
{
if(enemyHit.parent)
{
this.parent.removeChild(this);
Game.level1.enemies_arr.splice(Game.level1.enemies_arr.indexOf(enemyHit,1));
}
}
}
}
You should traverse both Game.level1.enemies_arr and bullets_arr backwards. The point is, splice() shortens the array, shifts the elements that are in greater positions than the spliced one(s) to lesser indexes, and the loop counter is not automatically adjusted. The error is pretty common, but is often overlooked. Also, with bullets_arr you can get out of the array causing a 1009 error if your last bullet out of bullets_arr will hit an enemy.
A small nitpick: You are checking for the array's existence within a loop, and for another array's existence once within the enter frame listener. In fact you should either initialize them with at least new Array() or [] before you add an event listener to the Main object, or wherever this is assigned to, or check like if (!bullets_arr) bullets_arr=new Array(); and leave it at that, so one check of the array's existence will be needed.
public function Main(e: Event):void
{
player.x = mouseX;
if (!bullets_arr) bullets_arr=new Array();
if (!Game.level1.enemies_arr) throw new Error('Hey programmer, initialize your arrays!');
// ^ bad practice to throw exceptions in listeners, but if you get one, you've coded something wrongly.
for (var m:int=bullets_arr.length-1;m>=0;m--) {
var bm:Bullet=bullets_arr[m]; // TODO fix type
// the local variable is a cleaner and faster approach
bm.y-=20;
for (var n:int=Game.level1.enemies_arr.length-1;n>=0;n--) {
if (!bm) break; // bullet was destroyed, why checking more enemies vs that?
if (Game.level1.enemies_arr[n].hitTestObject(bm)) {
bm.parent.removeChild(bm);
bullets_arr.splice(m,1); // splice is done by index, not by object
bm=null; // oops, missed this. The bullet hit something and is now lost
// so we null the local var, so we can break out the loop.
Game.level1.enemies_arr[n].Damage(10, Game.level1.enemies_arr[n]);
}
}
}
// rest of your code follows here
}
I finally found the problem, it was very stupid of me :
I just mistyped the Die function in the Enemy class :
I have written :splice(Game.level1.enemies_arr.indexOf(enemyHit,1)) instead of splice(Game.level1.enemies_arr.indexOf(enemyHit),1)
Anyway I learnt a lot of think by trying to fix this error.
Thanks
package
{
import flash.events.Event;
import flash.display.MovieClip;
// class
public class GameGrid extends MovieClip
{
private var gameHeight:Number = 600;
private var gameWeight:Number = 800;
private var gridHeight:Number = 50;
private var gridWeight:Number = 50;
private var rowNumber:int = 12;
private var columnNumber:int = 16;
private var backgroundGrid:Array = new Array(12,16);
private var foregroundGrid:Array = new Array(12,16);
function GameGrid(){
}
function addBackGrid(rowN:int,colN:int,mcObject:MovieClip)
{
backgroundGrid[rowN,colN].push(mcObject);
}
function addForeGrid(rowN:int,colN:int,mcObject:MovieClip)
{
foregroundGrid[rowN,colN].push(mcObject);
}
function calculateRowDiff(rowA:int,rowB:int):Number
{
return Math.abs(rowA-rowB);
}
function calculateColDiff(colA:int,colB:int):Number
{
return Math.abs(colA-colB);
}
function calculateCorDiff(colA:int,colB:int,rowA:int,rowB:int):Number
{
return Math.sqrt((calculateRowDiff(rowA,rowB) * calculateRowDiff(rowA,rowB)) + (calculateColDiff(colA,colB) * calculateColDiff(colA,colB)));
}
// add to stage
function paintbackgroundGrid()
{
for (var i:int=0; i<16; i++)
{
for (var j:int=0; j<12; j++)
{
MovieClip(backgroundGrid[i,j]).x = i * 50;
MovieClip(backgroundGrid[i,j]).y = j * 50;
stage.addChild(MovieClip(backgroundGrid[i,j]));
}
}
}
}
}
So what this GameGrid class do is to hold an Array of grids(or tiles which extends MovieCLip) that will be added to the main stage and will call the initializeItem function.
function InitializeItem(e:Event)
{
var gamemap = new GameGrid();
var mc:MovieClip = new MainCharacter();
gamemap.addBackGrid(1,1,mc);
gamemap.paintbackgroundGrid();
//trace("Year: "+gameTime.gameYear+" Month: "+gameTime.gameMonth+" Day: "+gameTime.gameDay+" "+gameTime.gameHour+":"+gameTime.gameMinute+":"+gameTime.gameSecond);
}
The initializeItem should create an instance of gamegrid, and add movieclips to their respective locations(stored using array) and display them.
and this is the error stacktrace:
ReferenceError: Error #1069: Property 1 not found on Number and there is no default value.
at GameGrid/addBackGrid()
The debugger suggest that the error came from the line backgroundGrid[rowN,colN].push(mcObject);
Is there a way I can hold a 2d array movieclips? I'm new to AS3 and it looks very similar to JAVA, what am I missing?
Try this
private var backgroundGrid = [];
function addBackGrid(rowN:int,colN:int,mcObject:MovieClip) {
if (backgroundGrid[rowN] == null) {
backgroundGrid[rowN] = [];
}
backgroundGrid[rowN][colN] = mcObject;
}
In as3, following code means create a array and the array contains two elements, one is 12, and the other is 16.
private var backgroundGrid:Array = new Array(12,16);
i extend ArrayCollection class for add push method
package com.cargo.collections
{
import mx.collections.ArrayCollection;
public class DataCollection extends ArrayCollection {
public function DataCollection(source:Array = null) {
super(source);
}
public function push(...parameters):uint {
var i:uint = source.push(parameters);
this.refresh();
return i;
}
}
}
but pushed data is array :/
var test:DataCollection = new DataCollection({id: 1});
test.source.push({id: 2});
test.push({id: 3});
output is
test = Array( {id: 1}, {id: 2}, Array({id: 3}) )
In your example ...parameters creates an array containing all the arguments passed to that function. This should work as expected:
public function push(...parameters):uint {
var i:uint = source.push(parameters[0]);
this.refresh();
return i;
}
Alternatively, if your purpose is to enable the pushing of multiple parameters you can use the Function.apply() method, which will translate a given array into multiple parameters:
public function push(...parameters):uint {
var i:uint = source.push.apply(null,parameters);
this.refresh();
return i;
}
This is the equivalent of saying
var i:uint = source.push(parameters[0],parameters[1],parameters[2]); // etc