How can I put MovieClip into 3D array? - actionscript-3

I want to create 3d array which holds movieclips and textfields. Here's my code:
public function init():void
{
//initalize the arrays
for (var _x:int = 0; _x <= MAX_X; _x++)
{
colArray = new Array();
for (var _y:int = 0; _y <= MAX_Y; _y++)
{
textArray = new Array();
for (var _z:int = 0; _z <= MAX_Z; _z++)
{
var txt:TextField = new TextField();
textArray.push(txt);
}
var mc:MovieClip = new MovieClip();
colArray.push(mc);
}
rowArray.push(colArray);
}
}
public function addBoxes(isUpdate:Boolean):void
{
for (var _y:int = 0; _y <= MAX_Y; _y++)
{
for (var _x:int = 0; _x <= MAX_X; _x++)
{
for (var _z:int = 0; _z <= MAX_Z; _z++)
{
// Create captions
var mcCaption:MovieClip = createMc("captionBox", false);
spSource.addChild(mcCaption);
mcCaption.addEventListener(MouseEvent.MOUSE_DOWN, mcCaptionHandler);
colArray[_x][_y][_z] = mcCaption;
mcCaption.x = nextXpos;
mcCaption.name = "beatCaption_" + _y;
// trace(colArray[_x][_y][_z]);
}
}
}
...
}
I want some text on my movieclips. How can I do that? My code is giving me error: TypeError: Error #1010: A term is undefined and has no properties.
Is this statement wrong?
colArray[_x][_y][_z] = mcCaption; // mcCaption is a movieclip

You don't have a 3D array, because textArray in the innermost cycle is not pushed into colArray but instead you stuff a MC in there. Also, you are asking a wrong array to retrieve a 3-depth object. In your code rowArray is 2D array (would be 3D if you'd stuff textArray in there), colArray is a 1D array of MCs, and then you are trying to refer colArray[_x][_y][_z] - this one resolves to:
colArray[_x] = empty Movieclip, created at init()
colArray[_x][_y] = undefined (the MC is empty, there's no property _y regardless of its value
colArray[_x][_y][_z] = runtime error, you're trying to query undefined's properties.
So, you have to check if your init() is correctly written, because if you need a 3D array, you are not making one right now. My guess is this:
public function init():void
{
//initalize the arrays
for (var _x:int = 0; _x <= MAX_X; _x++)
{
colArray = new Array();
for (var _y:int = 0; _y <= MAX_Y; _y++)
{
textArray = new Array();
for (var _z:int = 0; _z <= MAX_Z; _z++)
{
textArray.push(null); // placeholder
}
colArray.push(textArray);
}
rowArray.push(colArray);
}
}
The nulls pushed in the innermost loop will then be replaced if you use rowArray[_x][_y][_z] = mcCaption;

Related

Need to remove a child using hit test object function

i am trying to make a function where i drop some seeds into a bucket and the seeds are removed however the function will just be the seeds colliding with the bucket.
I have both of the objects as movieclips and have a basic hitTestObject conditional statement, i have no idea why the feed_mc wont be removed.
if(bucket_mc.hitTestObject(feed_mc))
{
if(stage.contains(feed_mc))
removeChild(feed_mc);
}
thank you in advance
Sorry should have edited here
my code
var Necessities:Array = new Array (Seed, shelter, water);
for(var i:int = 0; i< 10; i++)
{
var pickObjects = Necessities[int(Math.random()* Necessities.length)];
var Objects:MovieClip = new pickObjects();
addChild(Objects);
Objects.x = Math.random() + 600;
Objects.y = Math.random() * stage.stageHeight;
}
stage.addEventListener(Event.ENTER_FRAME, feedHen);
function feedHen(e:Event):void {
if(hen_mc.hitTestObject(Objects))
{
if (Objects.parent)
Objects.parent.removeChild(Objects);
}
}
Seems like
if(feed_mc.parent){
feed_mc.parent.removeChild(feed_mc);
}
should help - if you are not sure what DisplayObjectContainer is parent
edit
I think this should work
var Necessities:Array = new Array (Seed, shelter, water);
//store Objects here
var objectsVector:Vector.<MovieClip> = new Vector.<MovieClip>();
for(var i:int = 0; i< 10; i++){
var pickObjects = Necessities[int(Math.random()* Necessities.length)];
var Objects:MovieClip = new pickObjects();
addChild(Objects);
objectsVector.push(Objects);//add to Vector
Objects.x = Math.random() + 600;
Objects.y = Math.random() * stage.stageHeight;
}
stage.addEventListener(Event.ENTER_FRAME, feedHen);
function feedHen(e:Event):void {
for(var i: int = objectsVector.length - 1; i >= 0; i--){//loop through stored objects
if(hen_mc.hitTestObject(objectsVector[i])){
if (objectsVector[i].parent){
objectsVector[i].parent.removeChild(objectsVector[i]);
objectsVector.splice(i, 1);//remove from storage
}
}
}
}
However I'd suggest checking on some mouse events instead of ENTER_FRAME to reduce number of function calls

Applying Drag, Snap Back Into Original Position To An Array

I am attempting to drag a movie clip and then have it snap back into its original position after being released. I want to apply this functioniality to an array with actionscript3. Here is the code so far:
var dragArray:Array = new Array;
dragArray.push(blockSmalla);
dragArray.push(blockSmallb);
dragArray.push(blockSmallc);
dragArray.push(blockSmalld);
dragArray.push(blockSmalle);
var startPosition:Point;
function drag(e:Event):void {
dragArray[i].startDrag();
startPosition = new Point( dragArray[i].x, dragArray[i].y);
}
function dragStop(e:Event):void {
dragArray[i].stopDrag();
dragArray[i].x = startPosition.x;
dragArray[i].y = startPosition.y;
startPosition = null;
}
for (var i:uint = 0; i < dragArray.length; i++) {
dragArray[i].addEventListener(MouseEvent.MOUSE_DOWN, drag);
dragArray[i].stage.addEventListener(MouseEvent.MOUSE_UP, dragStop);
}
The function is not being applied to the array. Any suggestions?
I think what null was trying to tell you is that within each function scope you should remove dragArray[i] and use e.currentTarget instead.
Here's a simple fix:
var dragArray:Array = new Array;
dragArray.push(blockSmalla);
dragArray.push(blockSmallb);
dragArray.push(blockSmallc);
dragArray.push(blockSmalld);
dragArray.push(blockSmalle);
var startPosition:Point;
function drag(e:Event):void {
e.currentTarget.startDrag();
startPosition = new Point( e.currentTarget.x, e.currentTarget.y);
}
function dragStop(e:Event):void {
e.currentTarget.stopDrag();
e.currentTarget.x = startPosition.x;
e.currentTarget.y = startPosition.y;
startPosition = null;
}
for (var i:uint = 0; i < dragArray.length; i++) {
dragArray[i].addEventListener(MouseEvent.MOUSE_DOWN, drag);
dragArray[i].addEventListener(MouseEvent.MOUSE_UP, dragStop);
}
Also note I removed the stage reference on your MouseUp listener.

How to call a variable of a function using concatenation (AS3)

I need to acess a variable inside this function using concatenation, following this example:
public function movePlates():void
{
var plate1:Plate;
var plate2:Plate;
var cont:uint = 0;
for (var i:uint = 0; i < LAYER_PLATES.numChildren; i++)
{
var tempPlate:Plate = LAYER_PLATES.getChildAt(i) as Plate;
if (tempPlate.selected)
{
cont ++;
this["plate" + cont] = LAYER_PLATES.getChildAt(i) as Plate;
}
}
}
EDIT:
public function testFunction():void
{
var test1:Sprite = new Sprite();
var test2:Sprite = new Sprite();
var tempNumber:Number;
this.addChild(test1);
test1.x = 100;
this.addChild(test2);
test2.x = 200;
for (var i:uint = 1; i <= 2; i++)
{
tempNumber += this["test" + i].x;
}
trace("tempNumber: " + tempNumber);
}
If i run the code like this, the line this["test" + i] returns a variable of the class. I need the local variable, the variable of the function.
Your loop on first step access plate0 this will cause not found error, if plate0 is not explicitly defined as class member variable or if class is not defined as dynamic. Same thing will happen for plate3, plate4, plate5... in case LAYER_PLATES.numChildren is more than 3.
EDIT:
Thanks to #Smolniy he corrected my answer plate0 is never accessed because cont is incremented before first access. So as he mentioned problem should be on plate3
You don't get the local variable with [] notation. your case has many solutions. You can use dictionary, or getChildAt() function:
function testFunction():void
{
var dict = new Dictionary(true);
var test1:Sprite = new Sprite();
var test2:Sprite = new Sprite();
var tempNumber:Number = 0;
addChild(test1);
dict[test1] = test1.x = 100;
addChild(test2);
dict[test2] = test2.x = 200;
for (var s:* in dict)
{
tempNumber += s.x;
//or tempNumber += dict[s];
}
trace("tempNumber: " + tempNumber);
};

AS3: can't addchild indexed movieclips into a sprite

I'm creating a dynamic blocked terrain in flash (AS3), and everything goes fine with it, the terrain is correctly placed. But I need to include collisions and I want the blocks to be within a movieclip (sprite), so I can test the collision with the terrain itself.
Ps: I don't know if it would be good to test the collisions with each block individually because I'll use a enterframe function and the block generation is dynamic.
The problem I'm facing is that I have a sprite called blockHolder, but I can't addChild the blocks to it.
Here's the code (I simplified it so we have the blocks being created in cascade if you addChild them into the stage directly, like addChild(clonedSquare).
The error I'm receiving:
TypeError: Error #1009: Can't access property or method of a null object reference.
var blockHolder:Sprite = new Sprite();
var clonedSquare = new square();
var lowestPoint:int = 10;
var highestPoint:int = 20;
var areaLenght:int = 10;
function createLvl():void
{
for (var i:Number = 0; i<(areaLenght); i++)
{
clonedSquare = new square();
clonedSquare.x = i * clonedSquare.width;
//sets the height of the first block
if (i == 0)
{
var firstY:Number = Math.ceil(Math.random()*((lowestPoint-highestPoint))+highestPoint)*clonedSquare.height;
clonedSquare.y = firstY;
trace("terrain begins " + firstY + " px down");
}
else
{
var previousId:Number = i - 1;
clonedSquare.y = getChildByName("newSquare"+previousId).y + clonedSquare.height;
}
//sets the entity (block) name based on the iteration
clonedSquare.name = "newSquare" + i;
//adds the cloned square
blockHolder.addChild(clonedSquare);
}
addChild(blockHolder);
}
createLvl();
Well I fixed the error. I am still not clear as to what you're asking for. Basically I add each block to an array and reference the block that way. Your clonedSquare.y = getChildByName("newSquare"+previousId).y + clonedSquare.height; was throwing the error. Also your firstY was placing the first block way off my stage so I just set it to 0 as firstY
var blockHolder:Sprite = new Sprite();
var squares:Array = [];
var lowestPoint:int = 10;
var highestPoint:int = 20;
var areaLenght:int = 10;
function createLvl():void
{
for (var i:Number = 0; i<(areaLenght); i++)
{
var clonedSquare = new square();
clonedSquare.x = i * clonedSquare.width;
if (i == 0)
{
var firstY:Number = Math.ceil(Math.random()*((lowestPoint-highestPoint))+highestPoint)*clonedSquare.height;
//clonedSquare.y = firstY;
clonedSquare.y = 0;
trace("terrain begins " + firstY + " px down");
}
else
{
clonedSquare.y = squares[i - 1].y + clonedSquare.height;
}
blockHolder.addChild(clonedSquare);
squares.push(clonedSquare);
}
addChild(blockHolder);
}
createLvl();

Filling open spaces in a grid top down

I am writing a match three engine and I succeed in creating the matching with using huge loops to find the matching items. Any ideas on how to fill the empty spaces with the items ( dropping down into the empty spaces ) and creating new items without excessive looping and if statements?
Here is my relavant code so far.
public var rows:uint = 8;
public var cols:uint = 7;
public var cell:Array = new Array();
public var plot:Array = new Array();
public var height:int;
public var width:int;
public var relativePositions:Array = [{name:'top', position:-1}, {name:'bottom', position:1}, {name:'left', position:rows*-1}, {name:'right', position:rows*1}];
public var dictionary:Dictionary = new Dictionary();
public var matches:Array = new Array();
public function createGrid(target:*, displayObject:*, spacer:int) : void {
var iterator:uint = 0;
for(var c:uint = 0;c<cols;c++){
for(var r:uint = 0;r<rows;r++){
cell[iterator] = createGamePiece();
Sprite(cell[iterator]).name = String(iterator);
Sprite(cell[iterator]).addEventListener(MouseEvent.CLICK, _handleGamePiece_CLICK);
Sprite(cell[iterator]).addEventListener(MouseEvent.MOUSE_OVER, _handleGamePiece_MOUSE_OVER);
Sprite(cell[iterator]).addEventListener(MouseEvent.MOUSE_OUT, _handleGamePiece_MOUSE_OUT);
cell[iterator].y = cell[iterator].height * r + (spacer*r);
cell[iterator].x = cell[iterator].width * c + (spacer*c);
GamePiece(cell[iterator]).positionX = cell[iterator].x;
GamePiece(cell[iterator]).positionY = cell[iterator].y;
GamePiece(cell[iterator]).positionRow = r;
GamePiece(cell[iterator]).positionCol = c;
target.addChild(cell[iterator]);
dictionary[String(iterator)] = cell[iterator]
iterator++
}
}
}
public function findRelativeMatches(targetSprite:Sprite) : void {
targetSprite.alpha = .5;
var rootPosition:Number = Number(targetSprite.name);
for ( var i:int = 0; i < relativePositions.length; i ++ ) {
var key:String = String(rootPosition + relativePositions[i].position);
// to do >> Not hardcoded to 'Pig'
if (findSprite(key) != null && GamePiece(targetSprite).color == GamePiece(findSprite(key)).color && GamePiece(findSprite(key)).found == false) {
var sprite:Sprite = findSprite(key);
sprite.alpha = .5;
GamePiece(sprite).found = true;
matches.push(sprite);
findRelativeMatches(sprite);
};
};
targetSprite.addEventListener(MouseEvent.MOUSE_OUT, function() : void {
if ( matches.length != 0 ) {
for ( var j:int = 0 ; j < matches.length ; j++ ) {
Sprite(matches[j]).alpha = 1;
GamePiece(matches[j]).found = false;
}
matches.splice(0);
}
});
}
public function findSprite(key:String) : Sprite {
var sprite:Sprite;
dictionary[key] != undefined ? sprite = dictionary[key] : null;
return sprite;
}
protected function _handleGamePiece_CLICK(event:MouseEvent):void
{
for ( var j:int = 0 ; j < matches.length ; j++ ) {
var sprite:Sprite = matches[j];
view.removeChild(matches[j]);
}
matches.splice(0);
}
public function createGamePiece() : Sprite {
var gamePiece:GamePiece = new GamePiece();
return gamePiece;
}
You want to collapse your grid downwards, right? The common algorithm is going from the bottom of every row upwards, having one index of the first empty space found, and the other for the first occupied space above empty space, then exchange those values once found, iterating to the top. But you don't store the grid in any accessible form! You should create a grid object, say a vector of vectors of sprites, and assign values in it as you move pieces around. Like this:
var GRID:Vector.<Vector.<Sprite>>; // this should be allocated at createGrid
// populate GRID with your sprites once generated:
// put the following into your inner loop in CreateGrid:
GRID[r][c]=cell[iterator];
// and the following into your removal of matches[] sprites:
GRID[GamePiece(sprite).positionRow][GamePiece(sprite).positionCol]=null; // release link from GRID
// now to move grid objects:
function DropAll():void {
var i:int;
var j:int;
for (i=GRID.length-1;i>=0;i--) {
var lastEmpty:int=-1;
for (j=GRID[i].length-1;j>=0;j--) {
if (GRID[i][j]) {
if (lastEmpty>0) {
GRID[i][lastEmpty--]=GRID[i][j];
// relocate your sprite properly here
GRID[i][j]=null;
} // else we're still at full part of grid, continue
} else if (lastEmpty<0) lastEmpty=j;
}
}
}
To properly instantiate GRID you need to allocate vectors of desired length that are filled with "null" values. Also, "GRID" itself is a Vector, and needs to be instantiated too.
GRID=new Vector.<Vector.<Sprite>>();
for (i=0;i<rows;i++) {
var a:Vector.<Sprite>=new Vector.<Sprite>(cols);
GRID.push(a);
}
After you do this, you fill the GRID by directly assigning links in it, like GRID[r][c]=gameObject;
This is actually what I wanted. A way to collapse WITHOUT iterating over the entire board. This way I JUST loop through the items that have been removed.
protected function _handleGamePiece_CLICK(event:MouseEvent):void
{
for ( var j:int = 0 ; j < matches.length ; j++ ) {
var oldSprite:Sprite = matches[j];
moveAllPiecesDown(oldSprite);
view.removeChild(oldSprite);
oldSprite = null;
}
matches.splice(0);
}
private function moveAllPiecesDown(oldSprite:Sprite):void
{
var piecesAbove:int = GamePiece(oldSprite).positionRow;
var index:int = int(oldSprite.name);
for( var i:int = 0; i < piecesAbove; i ++ ) {
var spriteAbove:Sprite = Sprite(view.getChildByName(String(index-(1+i))));
if(spriteAbove) {
spriteAbove.y = spriteAbove.y + spriteAbove.height + 1;
spriteAbove.name = String(Number(spriteAbove.name)+1);
GamePiece(spriteAbove).textField.text = spriteAbove.name;
delete dictionary[spriteAbove.name];
dictionary[spriteAbove.name] = spriteAbove;
}
}
}