Random movide clip without loop? - actionscript-3

I created some MovieClips and put all of them on the stage. I'm trying to move a random MovieClip, using it only once, but at the same time I need to know which one it is because it will conflict with other tween effects. Is there an easy way to do that?
Here is what I've tried:
var biryukseklev1, ikiyukseklev1, ucyukseklev1, dortyukseklev1, besyukseklev1:int;
var assignavalue1, assignavalue2:int;
stage.addEventListener(Event.ENTER_FRAME,survivordondurlev6);
function survivordondurlev6(e:Event) {
if (biryerlessurlev1 == 0) {
biryukseklev1 = 764;//36
} else if (biryerlessurlev1 == 1) {
biryukseklev1 = 680;//120
} else if (biryerlessurlev1 == 2) {
biryukseklev1 = 596;//204
} else if (biryerlessurlev1 == 3) {
biryukseklev1 = 512;//288
} else if (biryerlessurlev1 == 4) {
biryukseklev1 = 428;//372
}
if (assignavalue1 == 0 && rabbitstatus.text.length < 2) { //Make sure to not used before
var my:Tween = new Tween(rabbit, "y", Back.easeInOut, rabbit.y, rabbit.y -biryukseklev1, 3, true);
rabbitstatus.text = "okfull";
} else if((assignavalue1 == 1 && birdstatus.text.length < 2){ //Make sure to not used before
var mys:Tween = new Tween(bird, "y", Back.easeInOut, bird.y, bird.y -biryukseklev1, 3, true);
birdstatus.text = "okfull";
}
}

If you want to keep track of which clips you've animated, then you'll have to have some way of iterating through them. The easiest list would be an Array, though how you mark them as "animated" is up to you. If you never plan on animating them again, then simply removing the ones that you've animated, and leaving the rest for later will work.
Below is example code, which you should be able to run in a new scene. You should be able to apply it to your needs with some small edits.
import fl.transitions.Tween;
import fl.transitions.easing.*;
// We'll keep track of which blocks still need to be animated by including them in this list
// Once we animate a block, we remove it from the list.
var pool:Array = [];
// Populate the stage with blocks.
for (var i:int = 0; i < 30; i++) {
var block:Sprite = createBlock();
addChild(block);
block.y = 50;
if (i > 0) { block.x = block.width * i; }
pool.push(block);
}
// Create an interactive button.
var txt:TextField = new TextField();
txt.text = "Do something";
addChild(txt);
txt.addEventListener("click", animateNext);
function createBlock():Sprite {
// Creates a single, randomly colored block.
var block:Sprite = new Sprite();
block.graphics.beginFill(random(0x000000, 0xFFFFFF));
block.graphics.drawRect(0,0,16,16);
block.graphics.endFill();
return block;
}
function random(low:Number, high:Number):Number {
// Returns a random number between the low and high numbers.
return Math.floor(Math.random() * (1+high-low)) + low;
}
function animateNext(e:Event):void {
// Do this 5 times.
for (var i:int = 0; i < 5; i++) {
// As long as we have blocks in the pool...
if (pool.length > 0) {
// Pick a random block from the pool
var index:int = random(0, pool.length-1);
// Animate it
new Tween(pool[index], "y", Back.easeInOut, pool[index].y, pool[index].y + 50, 3, true);
// Remove it from the pool so it isn't picked again
pool.splice(index, 1);
} else {
// Otherwise, break the loop.
break;
}
}
}

Related

Finding cubes that touch air.. [Searching elements in a vector]

Using Away3D...I have this array of cubes I generated. This array of cubes are in a "Sector" that contains 50x50x50 cubes. The only thing the sector contains is the cubes coordinates and color. They are stored inside the Cube class. I only want to render the ones that touch air (currently "air" the "color" 0xFFFFFF)
I've tried this...an interesting number of ways...
My current method (slowest) was to make vector3D points for each object, and then use indexOf on a set of Vector3Ds containing the points of all the cubes in my "Sector".
public function renderSector(sector:Sector):void
{
trace("init sector render..");
allCubes = sector.cubes;
//Render only things touching air.
for each (var cube:Cube in sector.cubes)
{
//If the cube is not an air block
if (cube.color != 0xFFFFFF)
{
var topEstimate:Vector3D = new Vector3D(cube.x + 1, cube.y, cube.z);
var bottomEstimate:Vector3D = new Vector3D(cube.x, cube.y +1, cube.z);
var leftEstimate:Vector3D = new Vector3D(cube.x + 1, cube.y, cube.z +1);
var rightEstimate:Vector3D = new Vector3D(cube.x - 1, cube.y, cube.z);
var frontEstimate:Vector3D = new Vector3D(cube.x, cube.y -1, cube.z);
var backEstimate:Vector3D = new Vector3D(cube.x, cube.y, cube.z - 1);
//If the cube is next to an air block
if (checkForAir(topEstimate) || checkForAir(bottomEstimate) || checkForAir(leftEstimate) || checkForAir(rightEstimate) || checkForAir(frontEstimate) || checkForAir(backEstimate))
{
var meshCube:Mesh = new Mesh(new CubeGeometry(10, 10, 10), new ColorMaterial(cube.color));
meshCube.x = (sector.x * 125000) + (10 * cube.x);
meshCube.y = (sector.y * 125000) + (10 * cube.y);
meshCube.z = (sector.z * 125000) + (10 * cube.z);
trace("This cube touches air..rendering");
viewport.scene.addChild(meshCube);
}
}
}
}
private function checkForAir(point:Vector3D):Boolean
{
var returnValue:Boolean = new Boolean(false);
var index:int = allCubes.indexOf(point);
if (index > -1)
{
if (allCubes[index].color == 0xFFFFFF)
{
returnValue = true;
}
}
return returnValue;
}
Nothing happens. I get no cubes (letting it run for about 2 minutes) that have an air block next to them using a 3DVevtor. So, I try iterating through all my cubes again while fetching a list of cubes that are "next" to my current cube. I do this by comparing each cube to each other vs a stored 3DVector in my Sector class.
public function renderSector(sector:Sector):void
{
//Render only things touching air.
for each (var cube:Cube in sector.cubes)
{
//If the cube is next to an air block and is not an air block, render it.
if (cube.color != 0xFFFFFF)
{
var touchesAir:Boolean = new Boolean(false);
//Search touching cubes
var touchingCubes:Vector.<Cube> = new Vector.<Cube>();
for each (var possibleCube:Cube in sector.cubes)
{
if ((possibleCube.x == cube.x + 1 && possibleCube.y == cube.y && possibleCube.z == cube.z) ||
(possibleCube.y == cube.y + 1 && possibleCube.x == cube.x && possibleCube.z == cube.z) ||
(possibleCube.z == cube.z + 1 && possibleCube.x == cube.x && possibleCube.y == cube.y) ||
(possibleCube.x == cube.x - 1 && possibleCube.y == cube.y && possibleCube.z == cube.z) ||
(possibleCube.y == cube.y - 1 && possibleCube.x == cube.x && possibleCube.z == cube.z) ||
(possibleCube.z == cube.z - 1 && possibleCube.x == cube.x && possibleCube.y == cube.y))
{
touchingCubes.push(possibleCube);
}
}
for each (var touchingCube:Cube in touchingCubes)
{
if (touchingCube.color == 0xFFFFFF)
{
touchesAir = true;
}
}
if (touchesAir)
{
var meshCube:Mesh = new Mesh(new CubeGeometry(10, 10, 10), new ColorMaterial(cube.color));
meshCube.x = (sector.x * 125000) + (10 * cube.x);
meshCube.y = (sector.y * 125000) + (10 * cube.y);
meshCube.z = (sector.z * 125000) + (10 * cube.z);
trace("This cube touches air..rendering");
viewport.scene.addChild(meshCube);
}
}
}
It works..but it takes about 15 seconds for it to find one....The current spec of the Sector is a plane of 50x25x50 grass colored blocks. So this would take a while..
My first method (and oh man was this about an hour+ of brainstorming back) was to fetch the positions of each cube that [i]would[/i] be next to my main cube by basing it on the render order in my world generator function. [Seen below]
public static function generateSector(type:String, position:Vector3D):Sector
{
var returnSector:Sector;
var grassArray:Vector.<uint> = new Vector.<uint>();
grassArray.push(new uint(0x56b000));
grassArray.push(new uint(0x63c900));
grassArray.push(new uint(0x6fe300));
grassArray.push(new uint(0x7cfc00));
//Current types...grass field
switch(type)
{
case "grass":
var cubeArray:Vector.<Cube> = new Vector.<Cube>();
for (var x:int = 0; x < 50; x++) //Moving right
{
for (var z:int = 0; z < 50; z++) //Headed out.
{
for (var y:int = 0; y < 50; y++) //From bottom up.
{
if (y < 25)
{
var color:uint = grassArray[Math.floor(Math.random() * 4)];
}
else
{
var color:uint = 0xFFFFFF;
}
cubeArray.push(new Cube(x,y,z,color));
}
}
}
returnSector = new Sector(position.x, position.y, position.z, cubeArray);
break;
}
return returnSector;
}
Y building first (bottom to top)
then X
then Z
So, simple right? Based on the order of the cubes, I should be able to just pull, for example, the cube on top of my current cube by adding 1 to the index of my current cube, right? (Getting the other cubes respectively based on their order of course and catching errors for any cubes that would be outside of my 50x50x50 grid)
public function renderSector(sector:Sector):void
{
//Render only things touching air.
var counter:int = 0;
for each (var cube:Cube in sector.cubes)
{
//If the cube is next to an air block and is not an air block, render it.
if (cube.color != 0xFFFFFF)
{
var touchesAir:Boolean = new Boolean(false);
try
{
var topCube:Cube = sector.cubes[counter + 1];
if (topCube.color == 0xFFFFFF)
{
touchesAir == true;
}
}
catch(rangeError:RangeError)
{
}
//-------
try
{
var bottomCube:Cube = sector.cubes[counter - 1];
if (bottomCube.color == 0xFFFFFF)
{
touchesAir = true;
}
}
catch (rangeError:RangeError)
{
}
//-------
try
{
var leftCube:Cube = sector.cubes[counter - (50 * 50)];
if (leftCube.color == 0xFFFFFF)
{
touchesAir = true;
}
}
catch (rangeError:RangeError)
{
}
//-------
try
{
var rightCube:Cube = sector.cubes[(50 * 50) + counter];
if (rightCube.color == 0xFFFFFF)
{
touchesAir = true;
}
}
catch (rangeError:RangeError)
{
}
//-------
try
{
var frontCube:Cube = sector.cubes[counter - 50];
if (frontCube.color == 0xFFFFFF)
{
touchesAir = true;
}
}
catch (rangeError:RangeError)
{
}
//-------
try
{
var backCube:Cube = sector.cubes[counter + 50];
if (backCube.color == 0xFFFFFF)
{
touchesAir = true;
}
}
catch (rangeError:RangeError)
{
}
if (touchesAir)
{
var meshCube:Mesh = new Mesh(new CubeGeometry(10, 10, 10), new ColorMaterial(cube.color));
meshCube.x = (sector.x * 125000) + (10 * cube.x);
meshCube.y = (sector.y * 125000) + (10 * cube.y);
meshCube.z = (sector.z * 125000) + (10 * cube.z);
trace("This cube touches air..rendering");
viewport.scene.addChild(meshCube);
}
}
}
}
This one renders in about 4 seconds! Though, no cubes actually appear on screen...and the trace statement never fires. I have had no luck finding out why.
TL;DR Let's say you have a grid of cubes. How do you only render the ones that are out in the open?
Or (great alternative) only render mesh's that you can "see". (I need the meshs not merged because I have to have listeners on them to remove them or add new meshes when clicked next to or ontop of them)
You know those moments when you forget to sleep and then you forget to add counters to your for each loops since you're referencing a counter inside of it?
counter = sector.cubes.indexOf(cube);
Need to make sure that the counter (which I should rename indexItem) matched the index of the current cube that I was running through inside my conditional that checks to see if the cube is "air" or not.
Of course, now I'm getting a resource limit error but this can be fixed by reducing the sector size and combining a few meshes.
[Fault] exception, information=Error: Error #3691: Resource limit for this resource type exceeded.

AS3 How can I get back the object that being dragged to Item

I have board with 16 objects(MovieClip), every one of them have a unique instance name (slot1-16).
I'm trying to make a drag and drop code that return the instance name of the object dragged on it.
function fl_ReleaseToDrop(evt:MouseEvent):void {
var object = evt.currentTarget;
if(object is textBox || object is UILoader)
{
for(var i:int = 1; i < 16; i++){
//Checks the correct drop target
if (object.hitTestObject(getChildByName("slot" + i)))
{
trace("slot" + i);
slot(getChildByName("slot" + i)).gotoAndStop(3);
}else{
object.x = xPos; //If not, return the clip to its original position
object.y = yPos;
}
}
object.stopDrag();
}
}
What really happened is that the only place that i can drag in to is slot1, other slots are not working.
In your current code, if the 1st hit test with slot1 object fails, you return your dragged object to its original position and of course all the hit tests with other slots will fail.
So you should return your object to its original position just after doing the hit test with all objects. You can use, for example, a Boolean var to know if there is at least one succeeded hit test, in that case you don't need to return your dragged object to its original position :
function fl_ReleaseToDrop(evt:MouseEvent):void
{
var object = evt.currentTarget;
var hit_test:Boolean = false;
if(object is textBox || object is UILoader)
{
for(var i:int = 1; i < 16; i++)
{
if (object.hitTestObject(getChildByName("slot" + i)))
{
hit_test = true;
slot(getChildByName("slot" + i)).gotoAndStop(3);
}
}
if(!hit_test)
{
object.x = xPos;
object.y = yPos;
}
object.stopDrag();
}
}
Hope that can help.

Trouble with addChild/removeChild and display list order in ActionScript3

I am working on a project, which includes a Lake symbol that the player can throw stones into, which in turn causes octopi to rise out of the lake in the positions that each stone hits the lake.
There is also a symbol for the splash made by the stone which will appear after the stone hits and before the octopus appears.
It is likely that there will be many octopi on the screen at the same time and they need to be ordered in the display list so that the ones that should appear further back are behind the others.
Each instance of these symbols should only play once and then be removed.
My code for this makes use of the different add/remove child method alongside for loops, conditionals and arrays which I have put together with the help of various tutorials and forums.
The problem I have is that when you click on the lake two or more times in quick succession, the stone and the splash symbols aren't removed properly and often keep looping.
Here is the code I am using. Any ideas?
var stone:Stone;
var stoneSplash:StoneSplash;
var octopus1:Octopus1;
var octopus2:Octopus2;
var whichOctopus:Array = [addOctopus1, addOctopus2];
var octopusScale:Number;
var octopusContainer:MovieClip = new MovieClip;
lake.lakeHitArea.addEventListener(MouseEvent.CLICK, onClickLake);
//Add octopusContainer to the stage's display list just above the Lake
addChildAt(octopusContainer,getChildIndex(lake) + 1);
octopusContainer.x = 0;
octopusContainer.y = 0;
function onClickLake(e:MouseEvent):void
{
trace("CLICK");
throwStone(mouseX, mouseY);
}
function throwStone(stonePositionX:int, stonePositionY:int)
{
stone = new Stone();
stone.x = stonePositionX;
stone.y = stonePositionY;
addChild(stone);
addEventListener(Event.ENTER_FRAME, removeStone);
}
function removeStone(e:Event):void
{
var count:int = numChildren;
var children:Array = [count];
//load all the children of the component into an Array
for (var i:int=0; i<count/* -1*/; i++)
{
children[i] = getChildAt(i/* + 1*/);
}
for (i=0; i<count/* - 1*/; i++)
{
if (children[i] is Stone)
{
if (children[i].currentFrameLabel == "Splash")
{
stoneSplash = new StoneSplash();
octopusContainer.addChild(stoneSplash);
stoneSplash.x = children[i].x;
stoneSplash.y = children[i].y;
}
if (children[i].currentFrameLabel == "end")
{
octopusContainer.removeChild(stoneSplash);
var positionX:int = children[i].x;
var positionY:int = children[i].y;
addOctopus(positionX, positionY);
removeChild(children[i]);
}
}
}
}
function addOctopus(positionX, positionY)
{
var o:int = Math.round(randomNumber(0,1));
whichOctopus[o](positionX, positionY);
reorderDisplayList();
addEventListener(Event.ENTER_FRAME, removeOctopus);
}
function addOctopus1(positionX: int, positionY:int):void
{
// if (whichOctopus1 == true)
// {
// var octopus:* = octopus1_1;
// }
// else
// {
// octopus = octopus1_2;
// }
octopus1 = new Octopus1();
var octopus:DisplayObject = octopus1;
octopusContainer.addChild(octopus);
octopus.x = positionX;
octopus.y = positionY;
octopusScale = randomNumber(0.5,0.85);
octopus.scaleX = octopusScale;
octopus.scaleY = octopusScale;
trace("children = " + octopusContainer.numChildren);
testPosition(octopus);
}
function addOctopus2(positionX: int, positionY:int):void
{
// if (whichOctopus2 == true)
// {
// var octopus:* = octopus2_1;
// }
// else
// {
// octopus = octopus2_2;
// }
octopus2 = new Octopus2();
var octopus:DisplayObject = octopus2;
octopusContainer.addChild(octopus);
octopus.x = positionX;
octopus.y = positionY;
octopusScale = randomNumber(0.25,0.5);
octopus.scaleX = octopusScale;
octopus.scaleY = octopusScale;
trace("children = " + octopusContainer.numChildren);
testPosition(octopus);
}
function testPosition(octopus:Object):void
{
trace(octopus)
for (var i:int = 0; i < 200; i++)
{
if (lake.hitTestPoint(octopus.x + octopus.hitTestBox1.x * octopus.scaleX,octopus.y + octopus.hitTestBox1.y * octopus.scaleY,true))
{
break;
}
else
{
octopus.x++;
}
}
for (i = 0; i < 100; i++)
{
if (lake.hitTestPoint(octopus.x + octopus.hitTestBox2.x * octopus.scaleX,octopus.y + octopus.hitTestBox2.y * octopus.scaleY,true))
{
break;
}
else
{
octopus.y--;
}
}
for (i = 0; i < 200; i++)
{
if (lake.hitTestPoint(octopus.x + octopus.hitTestBox3.x * octopus.scaleX,octopus.y + octopus.hitTestBox3.y * octopus.scaleY,true))
{
break;
}
else
{
trace(i);
octopus.x--;
}
}
for (i = 0; i < 100; i++)
{
if (lake.hitTestPoint(octopus.x + octopus.hitTestBox1.x * octopus.scaleX,octopus.y + octopus.hitTestBox1.y * octopus.scaleY,true))
{
break;
}
else
{
octopus.y--;
trace(i);
}
}
}
function randomNumber(min:Number, max:Number):Number
{
return Math.random() * (max - min) + min;
}
function reorderDisplayList():void
{
//the number of children in our component
var count:int = octopusContainer.numChildren;
var children:Array = [count];
//load all the children of the component into an Array
for (var i:int=0; i<count; i++)
{
children[i] = octopusContainer.getChildAt(i);
}
//sort the Array children based on their 'y' property
children.sortOn("y", Array.NUMERIC);
//re-add the children to the component ;
//in the order of the sorted Array we just created.
//When we add the children using 'addChild' it will
//be added at the top of the component's displaylist
//and will automatically be removed from its original position.
for (i=0; i<count/* - 1*/; i++)
{
if (children[i] is Octopus1 || children[i] is Octopus2)
{
// trace("child = " + children[i] + " at i: " + i);
octopusContainer.removeChild(children[i]);
octopusContainer.addChild(children[i]);
}
}
}
function removeOctopus(e:Event):void
{
var count:int = octopusContainer.numChildren;
var children:Array = [count];
//load all the children of the component into an Array
for (var i:int=0; i<count/* -1*/; i++)
{
children[i] = octopusContainer.getChildAt(i/* + 1*/);
}
for (i=0; i<count/* - 1*/; i++)
{
if (children[i] is Octopus1 || children[i] is Octopus2)
{
trace(i);
trace("Is an octopus");
if (children[i].currentFrame >= 202)
{
octopusContainer.removeChild(children[i]);
}
}
}
}
I would greatly appreciate any advice to help me overcome this hurdle and continue with my project.
Thank you in advance.
Chris Collins.
Your issue (or at least one of them) is that your code will only remove the most recent StoneSplash. So if you click a bunch of times in between the splash and end animation , only the last clicked one will get removed.
This is because you are using a global var (stoneSplash) to reference the splash, and it gets overwritten to the new one. You need to either add a splash reference on the stone itself, or create a dictionary so you know which splash goes with which stone.
Here would be one way:
if (children[i].currentFrameLabel == "Splash")
{
stoneSplash = new StoneSplash();
MovieClop(children[i]).stoneSplash = stoneSplash; //add a reference the splash on the stone itself
Then later, instead of octopusContainer.removeChild(stoneSplash); do:
octopusContainer.removeChild(MovieClop(children[i]).stoneSplash);
This way your removing the correct splash that goes with this stone.
Here would be a much cleaner way to architect this instead of using an enter frame handler:
On your Stone class timeline, put the following code on your Splash and End frames respectively:
Splash frame: this.dispatchEvent(new Event("Splash"));
End frame: this.dispatchEvent(new Event("End"));
Listen for those events when you create a new stone instance:
stone = new Stone();
stone.x = stonePositionX;
stone.y = stonePositionY;
stone.addEventListener("Splash", splashHandler,false,0,true);
stone.addEventListener("End",removeStone,false,0,true);
addChild(stone);
Respond to those events appropriately:
function splashHandler(e:Event):void {
var stone:Stone = e.currentTarget as Stone;
stoneSplash = new StoneSplash();
//you need a reference to the splash from the stone class - it would be best to create a class file and add a public property called splashObj and then just use stone.splashObj = new StoneSplash();
MovieClip(stone).stoneSplash = stoneSplash; //so on the end event we can read this var to remove stoneSplash
octopusContainer.addChild(stoneSplash);
stoneSplash.x = stone.x;
stoneSplash.y = stone.y;
}
function removeStone(e:Event):void {
var stone:Stone = e.currentTarget as Stone;
octopusContainer.removeChild(MovieClip(stone).stoneSplash);
addOctopus(stone.x, stone.y);
removeChild(stone);
}

Add a movieclip but make sure it isn't in the same place as another movieclip. (as3)

So I have this where you add movieclips by clicking, but it is unefficient and doesn't have some functionality that I want, I need to only add the movieclip if no other movieclip is in the same place.
private function onClick():void
{
if(placesound==false)
{
placepixel.play();
placesound = true;
}
if(erasetrue==false)
{
var pixel = new Pixel();
pixel.x = 0;
pixel.y = 0;
}
if(mouseY>30 && irontrue==true)
{
//var pixel = new Pixel();
pixel.x=(Math.round(mouseX/5)*5)-2.5;
pixel.y=(Math.round(mouseY/5)*5)-2.5;
pixel.graphics.beginFill(0x999999);
pixel.graphics.drawRect(0, 0, 5, 5);
pixel.graphics.endFill();
pixel.type=0;
pix.push(pixel);
//addChild(pixel);
}
if(mouseY>30 && woodtrue==true)
{
//var pixel = new Pixel();
pixel.x=(Math.round(mouseX/5)*5)-2.5;
pixel.y=(Math.round(mouseY/5)*5)-2.5;
pixel.graphics.beginFill(0x996600);
pixel.graphics.drawRect(0, 0, 5, 5);
pixel.graphics.endFill();
pixel.type=3;
pix.push(pixel);
//addChild(pixel);
}
if(erasetrue==true)
{
for (i=pix.length-1; i>=0; i--)
{
if(pix[i].x==(Math.round(mouseX/5)*5)-2.5 && pix[i].y==(Math.round(mouseY/5)*5)-2.5)
{
removeChild(pix[i]);
pix.splice(i, 1);
}
}
}
if(mouseY>30 && springtrue==true)
{
//var pixel = new Pixel();
pixel.x=(Math.round(mouseX/5)*5)-2.5;
pixel.y=(Math.round(mouseY/5)*5)-2.5;
pixel.graphics.beginFill(0x000000);
pixel.graphics.drawRect(0, 0, 5, 5);
pixel.graphics.endFill();
pixel.type=1;
pix.push(pixel);
//addChild(pixel);
}
if(mouseY>30 && portaltrue==true)
{
//var pixel = new Pixel();
pixel.x=(Math.round(mouseX/5)*5)-2.5;
pixel.y=(Math.round(mouseY/5)*5)-2.5;
pixel.graphics.beginFill(0x9999FF);
pixel.graphics.drawRect(0, 0, 5, 5);
pixel.graphics.endFill();
pixel.type=2;
pix.push(pixel);
//addChild(pixel);
}
if(erasetrue==false)
{
addChild(pixel);
}
}
I want to somehow only run the last if (the one that addChilds the pixel.) only if no other movieclip (see the array "pix") has is already in the spot it would be placed in. (I round the mouse before placing it.
Thanks for any help.
Edit: Spoilers failed.
Loop through the pix array to see if any of the pixels in the array match the x and y coordinates of the new pixel object. If not, the pixel should be added.
So instead of your final if statement:
...
if(erasetrue==false){
var canPlace:Boolean = true;
for (var i:int = 0; i < pix.length; i++){
var placedPixel:Pixel = pix[i] as Pixel;
if(pixel.x == placedPixel.x && pixel.y == placedPixel.y){
canPlace = false;
}
}
if(canPlace){
addChild(pixel);
}
}

AS3: Large number of timers lagging flash

I have a large number of objects (472) that require a timer used to check how long it takes between state changes of a variable. The code below is what I have so far but that many timers running definitely impacts the performance of the application, is there a better optimised way of measuring this?
import flash.utils.Timer;
var active_:Boolean;
var matched:Boolean;
var vacated:Boolean;
var circ:Shape=new Shape();
this.addChild(circ);
circ.x = 0;
circ.y = 0;
var circRad:Number = 5;
var mat= new Matrix();
var busyColors = [0xFFFF00,0xFFCC00];
var idleColors = [0xCCCCCC,0x000000];
var matchedColors = [0x0099FF,0x0066FF];
var vacatedColors = [0xFF0000,0x990000];
var busyAlphas = [1,1];
var idleAlphas = [0.5,0.5];
var ratios = [0,255];
var prev:int = 0;
var time:Timer = new Timer(1000,0);
//time.start();
mat.createGradientBox(2*circRad,2*circRad,0,-circRad,-circRad);
circ.graphics.lineStyle();
if (active_ == false)
{
if (prev != 0)
{
setAverage(prev,false);
prev = 0;
}
circ.graphics.clear();
circ.graphics.beginGradientFill(GradientType.RADIAL,idleColors,idleAlphas,ratios,mat);
circ.graphics.drawCircle(0,0,circRad);
circ.graphics.endFill();
}
else if (active_ == true && matched == true)
{
if (prev != 1)
{
setAverage(prev,true);
prev = 1;
}
circ.graphics.clear();
circ.graphics.beginGradientFill(GradientType.RADIAL,matchedColors,busyAlphas,ratios,mat);
circ.graphics.drawCircle(0,0,circRad);
circ.graphics.endFill();
}
else if (active_ == true && vacated == false && matched == false)
{
if (prev != 2)
{
setAverage(prev,true);
prev = 2;
}
circ.graphics.clear();
circ.graphics.beginGradientFill(GradientType.RADIAL,busyColors,busyAlphas,ratios,mat);
circ.graphics.drawCircle(0,0,circRad);
circ.graphics.endFill();
}
else if (active_ == true && vacated == true)
{
if (prev != 3)
{
setAverage(prev,true);
prev = 3;
}
circ.graphics.clear();
circ.graphics.beginGradientFill(GradientType.RADIAL,vacatedColors,busyAlphas,ratios,mat);
circ.graphics.drawCircle(0,0,circRad);
circ.graphics.endFill();
}
function setAverage(i:int, a:Boolean)
{
time.stop();
switch (i)
{
case 0 :
break;
case 1 :
MovieClip(root).avgMat.push(uint(time.currentCount));
break;
case 2 :
MovieClip(root).avgBusy.push(uint(time.currentCount));
break;
case 3 :
MovieClip(root).avgVac.push(uint(time.currentCount));
break;
}
if(a == true){
//time.reset();
//time.start();
}
}
Commented out the timer starts because of the issue.
You can make public function like "tick()" at yours objects and call it in loop from 1 general timer outside.
Consider doing the following:
in the top, import getTimer
import flash.utils.Timer;
Create a variable containing the starting time (instead of doing timer.start) do this:
var timerStart : int = getTimer();
and instead of doing this: time.currentCount
Simply do this:
(getTimer() - timerStart) / 1000
Good luck.
you could change all the timers with addEventListener of type EVENT FRAME
var counter:Number = 0;
addEventListener(Event.ENTER_FRAME, counting);
function counting (e:Event):void
{
counter++
}
So counter will increment on every frame. Now you have to find fps. Now multiply fps by time that you want timer to run after. So it's should look like this:
var counter:Number = 0;
addEventListener(Event.ENTER_FRAME, counting);
function counting (e:Event):void
{
counter++
if(counter == 60) //60 fps means this line will run after 1 sec.
{
//do something
}
If(counter == 120) //60 fps; 2 sec
{
//do something
}
}
This method is much more accurate and the system will not be so overloaded. This can especcially help you for setting up the stage using addChild, when you need a delay after the animation is started.
You can make more of this 'timers', but that depends on the demands of the game, but i'm sure that it will work faster than hundreths of timers.