Ok, so I have some experience with as3 and some of the basics. But this problem has been stumping me for so long. I tried to do a workaround based on what I currently know about as3. But somehow either i get an error message or it just doesn't do anything at all. Here is the code that i'm trying to solve.
var zombieCount:Array = new Array();
var helltime:Timer = new Timer(1500);
helltime.addEventListener(TimerEvent.TIMER, spawnzombies)
helltime.start();
function spawnzombies(happened:TimerEvent){
var zombie1:Zombie = new Zombie();
zombieCount.push(zombie1);
stage.addChild(zombieCount[zombieCount.length - 1]);
zombie1.x = 135 + (330*Math.random())
zombie1.y = -29
stage.addEventListener(Event.ENTER_FRAME, move_zombie)
function move_zombie(happened:Event){
for(var i:int; i < zombieCount.length; i++){
zombieCount[i].y = zombieCount[i].y + 1;
if(zombieCount[i].hitTestObject(border)){
stage.removeChild(zombieCount[i]);
zombieCount.shift();
trace(zombieCount.length);
}
}
}
}
While this may not be inclusive of everything wrong, here are at least a few of the issues I see.
Inline function issue:
Inside your timer tick handler (spawnZombies), you create an inline function called move_zombie and then add an enter frame handler that calls that function.
The issue here, is that every tick of the timer, will then create a whole new copy of that function, and add ANOTHER enter frame handler. This will create huge problems after a few timer ticks.
Break that move_zombie function OUT OF the spawn function:
eg:
helltime.addEventListener(TimerEvent.TIMER, spawnzombies)
helltime.start();
stage.addEventListener(Event.ENTER_FRAME, move_zombie);
function move_zombie(......
function spawnzombies(.....
Iteration issue:
In your for loop:
for(var i:int; i < zombieCount.length; i++){
zombieCount[i].y = zombieCount[i].y + 1;
if(zombieCount[i].hitTestObject(border)){
stage.removeChild(zombieCount[i]);
zombieCount.shift();
trace(zombieCount.length);
}
}
You are not initializing your i value. While this will default it to 0, it's still a good idea for readability to initialize it.
So your iterating forward from 0 to the end of the array. However, if your hit test succeeds, you then use the shift method of the array. This removes the first item of the array (irrespective of what value i is at the time). This will remove the wrong item, plus mess up what zombieCount[i] refers to (because the amount of items has now changed after doing shift, so the next iteration zombieCount[i] will be a reference to same item as the previous iteration).
Instead of what you're currently doing, use the splice method to remove, and iterate backwards so your index doesn't get out of whack.
for(var i:int=zombieCount.length-1;i >=0;i--){
zombieCount[i].y += 1; //move it down 1 pixel
if(zombieCount[i].hitTestObject(border)){
stage.removeChild(zombieCount[i]);
zombieCount.splice(i,1); //remove the item at the current index (do this instead of shift)
trace(zombieCount.length);
}
}
Related
I am stuck doing this even though I know it's very simple. Yet, I am getting errors.
What I have:
I have 3 arrays.
1st Array contains objects of UpgradeButton class.
2nd Array contains objects of BuyButtonclass.
3rd Array named newCostlyShops contains Numbers.
BuyButton class and UpgradeButton class, both have a shopCode member which is a number; the number which I'm trying to equate.
What I'm trying to do:
My goal is to first look for BuyButton and UpgradeButton objects in the respective arrays which have shopCodes same as those in newCostlyShops.
After that, I removeChild() that object and splice it out from the array.
My Code:
Array 3:
var newCostlyShops:Array = new Array();
newCostlyShops = Object(root).WorkScreen_mc.returnCostlyShops();
trace(newCostlyShops); // this is tracing out the exact shopCodes I want and is working fine.
Deletion and Splicing codes:
for (looper = 0; looper < upgradeButtonsArray.length; looper++) {
for (var secondLooper: int = 0; secondLooper < newCostlyShops.length; secondLooper++) {
if (upgradeButtonsArray[looper].shopCode == newCostlyShops[secondLooper]) {
trace(looper);
trace(upgradeButtonsArray[looper]);
removeChild(upgradeButtonsArray[looper]);
upgradeButtonsArray.splice(looper, 1);
}
}
}
for (looper = 0; looper < buyButtonsArray.length; looper++) {
for (secondLooper = 0; secondLooper < newCostlyShops.length; secondLooper++) {
if (buyButtonsArray[looper].shopCode == newCostlyShops[secondLooper]) {
trace(looper);
trace(buyButtonsArray[looper]);
removeChild(buyButtonsArray[looper]);
buyButtonsArray.splice(looper, 1);
}
}
}
What's wrong with this Code:
I keep getting error
TypeError: Error #1010: A term is undefined and has no properties.
This error comes only after the 1st time this code is run and not the first time it is run. When I remove the removeChild and splice , this traces out objects that are not null, ever. Even after this whole function is called 100 times, the error is not shown. Only when I removeChild and use splice this occurs.
Is there something wrong with what I'm doing? How to avoid this error? This is throwing the whole program haywire. If there is any other alternative to this method, I'm open to take those methods as well as long as I don't get errors and my goal is reached.
It might sounds funny, but.... try to decrement looper after splicing.
trace(looper);
trace(upgradeButtonsArray[looper]);
removeChild(upgradeButtonsArray[looper]);
upgradeButtonsArray.splice(looper, 1);
looper--;
I think after splicing the array all item's are being shifted and you're skipping next one.
Also, you should get some more information with this error, like which class/line is throwing it. Maybe you need to enable "permit debugging" or something?
Bonus suggestion:
For newCostlyShops use Dictionary instead of Array so you won't have to nest for inside for...
So I'm facing a problem with an AS3 class that's not operating the way I need it to. It's a simple problem, but a complex set of methods that cause it.
Firstly, the 'quiz' I'm building has 6 questions loaded as external SWFs inside of a Shell, run by a class. First we declared a var "a_quiz" to hold 6 values pushed from the external SWFs. These 6 values are reduced to a string and then checked against another array that contains the correct answers. The following loadQuiz function is designed to launch one of three random quizes and clear the a_quiz array so it can take new answers:
public function loadQuiz():void {
a_quiz.length=0;
trace("loadQuiz");
n_quizCorrect = n_quizScore = 0;
n_currentQuiz = Math.floor(Math.random() * (n_totalTopics - n_quizStart + 1) + n_quizStart);
loadTopic(n_currentQuiz);
}
Now I've tested the Shell and confirmed that the trace "loadQuiz" fires every time. And the first time you load the quiz, everything behaves as it should. The 6 questions trace correct or incorrect responses and push 6 binary values into the a_quiz array. The output looks like this:
loadQuiz
incorrect
correct
incorrect
incorrect
incorrect
incorrect
0,1,0,0,0,0
you failed
Then I jump back to the main menu and launch again. This deploys the loadQuiz function all over again. The first line of the function:
a_quiz.length=0;
should be emptying the a_quiz array to accept new answers to mark against. But when I complete the quiz I get this:
loadQuiz
correct
correct
correct
correct
correct
correct
,,,,,,1,1,1,1,1,1
you failed
For some reason beyond my understanding, the push values are stacking on top of empty positions, so when the strings compare...they won't match. What is going on here?
The push function:
function handleClick(evt:MouseEvent):void{
var tempCORRECT = a_answerSheet.toString();
var tempSELECTION = a_selected.toString();
//
if(tempSELECTION == tempCORRECT){
trace('correct');
parentObj1.a_quiz[ parentObj1.n_currentQuestion - 1 ] = 1;
}else{
trace('incorrect');
parentObj1.a_quiz[ parentObj1.n_currentQuestion - 1 ] = 0;
}
parentObj1.n_currentQuestion ++;
// GOTO NEXT SLIDE
parentObj1.LOADNEXT('up');
}
The problem originated in the loading of the Quiz itself.
as you can see on the handleClick function:
parentObj.n_currentQuestion++
was increasing an integer variable on the parentObj's timeline called n_currentQuestion. The problem then, originated in how the quiz was logging n_currentQuestion when the quiz loads with this function:
public function loadQuiz():void {
a_quiz= [];
trace("loadQuiz");
n_quizCorrect = n_quizScore = 0;
n_currentQuiz = Math.floor(Math.random() * (n_totalTopics - n_quizStart + 1) + n_quizStart);
loadTopic(n_currentQuiz);
}
So to correct the error, I needed to add a line to the loadQuiz, so that it would always load with n_currentQuestion set to 1.
public function loadQuiz():void {
a_quiz= [];
n_currentQuestion = 1;
trace("loadQuiz");
n_quizCorrect = n_quizScore = 0;
n_currentQuiz = Math.floor(Math.random() * (n_totalTopics - n_quizStart + 1) + n_quizStart);
loadTopic(n_currentQuiz);
}
I'm writing a game with Flash CS5/AS 3.0 that tries to simulate depth of field by drawing all the relevant Movie Clips based on their Y position in ascending order, i.e. things lower on the stage overlap things higher on the stage. A MovieClip with a Y position of 10 would therefore need to have a lower index compared to a MovieClip with a Y position of 20, so the second one gets drawn on top of the first.
I wrote a quick and dirty function just to test this. During the trace, I've noticed that the truck's index hits 0 when I go near the top of the stage, but if I go too far up it will completely disappear from the stage. Trace then starts generating this error:
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/getChildIndex()
at EICT::Game/ReorganizeDisplayIndexes()
at EICT::Game/loop()
theTruck is a MovieClip of the player controlled vehicle
Enemies, Cones, Rocks are all arrays which contain MovieClips
None of them have event listeners.
private function ReorganizeDisplayIndexes(): void
{
var drawableObjects:Array = new Array();
drawableObjects.push(theTruck);
drawableObjects = drawableObjects.concat(Enemies, Rocks, Bushes);
drawableObjects.sortOn("y", Array.DESCENDING | Array.NUMERIC);
drawableObjects.reverse();
trace(collisionLayer.getChildIndex(theTruck));
for (var a:int = collisionLayer.numChildren - 1; a >= 0; a--)
{
collisionLayer.removeChildAt(a);
}
for (var i:int = 0; i < drawableObjects.length; i++)
{
collisionLayer.addChild(drawableObjects[i]);
}
}
Hint: You don't need to remove the child first. When you use addChild() on an object, it is automatically re-added to the next highest depth.
That said, you'll just need to do something like this:
drawableObjects.sortOn("y");
for each(var i:DisplayObject in drawableObjects)
{
if(i.parent)
i.parent.addChild(i);
}
Use setChildIndex instead of removing and re-adding:
for (var a:int = collisionLayer.numChildren - 1; i >= 0; i--)
{
collisionLayer.setChildIndex(drawableObjects[i], i);
}
Also, it's a bit wasteful to first order the sort in descending and then reversing the array. Sort it ascending to begin with!
I had a hard time trying to word my question properly, so i'm sorry if it seems confusing. Also i'm using the flixel library in flash builder. It may not be that important butcause probably anyone that knows a little more than me or even a little AS3 could probably see what i'm doing wrong.
Anyway, what i'm trying to do is basically create 10 instances of this square object I made. all I have to do is pass it an x an y coordinate to place it and it works. so ive tested if i just do:
var testsquare:Bgsq;
testsquare = new Bgsq(0,0);
add(testsquare);
it works fine and adds a square at 0,0 just like i told it to, but i want to add 10 of them then move the next one that's created 25 px to the right (because each square is 25px)
my problem is that I only ever see 1 square, like it's only making 1 instance of it still.
anyone possibly have an idea what I could be doing wrong?
var counter:int = 0;
var bgsqa:Array = new Array;
for (var ibgs:int = 0; ibgs < 10; ibgs++)
{
bgsqa[counter] = new Bgsq(0,0);
bgsqa[counter].x += 25;
add(bgsqa[counter]);
counter++;
}
There's a lot you're doing wrong here.
First off, you're using a pseudo-iterator (counter) to access array elements through a loop instead of, well, using the iterator (ibgs).
Second, I don't see anything in the array (bgsqa) you're iterating through. It's no wonder you're having problems. Here's what you should do.
var bgsqa:Array = [];
for(var i:int=0;i<10;i++)
{
var bgsq:Bgsq = new Bgsq(i * 25, 0);
add(bgsq);
bgsqa.push(bgsq);
}
That should probably do it if your post is accurate.
for (var ibgs:int = 0; ibgs < 10; ibgs++)
{
bgsqa[counter] = new Bgsq(0,0);
bgsqa[counter].x = counter * 25;
add(bgsqa[counter]);
counter++;
}
They start at 0, so applying += is simply adding 25 to 0. This should do the trick.
As a followup to the question, How to get associated URLRequest from Event.COMPLETE fired by URLLoader, how can I make the function work for loader object in a loop?
Here is my existing (rough) code; I always get the mylabel from the last element of the array.
var _loader = new Loader();
for (j = 0; j < 5; j++) {
//mylabel variable is correct setup in the loop
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event):void {
doneLoad(e, mylabel);
});
_loader.load(new URLRequest(encodeURI(recAC[j].url)));
}//for loop
As per the comments above, this won't work because:
1) You're just adding the same event listener 5 times to the loader.
2) You're just reseting your same loader object 5 times.
The final output will just be as though you only called it the last time.
There are a variety of ways to address this - loading stuff asynchronously is one of the great mindfucks of learning to code - but the simplest way is probably just to create five separate loaders.
I'd do something like this:
var loaders:Array = [];
var labels:Array = ["label1", "label2", "label3", "label4", "label5"];
for (var j:int = 0; j < 5; j++) {
loaders[j] = new Loader();
loaders[j].contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loaders[j].load(new URLRequest(encodeURI(recAC[j].url)));
}
function completeHandler(e:Event):void {
doneLoad(e.currentTarget, labels[loaders.indexOf(e.currentTarget)]);
}
The confusing part is finding a good way to keep track of which load is associated with which label etc, since in theory your loads can finish in any order. That's why I've got a separate label array there, and then you just match up the desired label with the loader that just finished loading.
I hope that helps!
the line belove should work but it returns -1, always.
loaders.indexOf(e.currentTarget);
Here my code
for(i; i < total; i++){
imgLoaderArray[i] = new Loader();
imgLoaderArray[i].contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, urlError);
imgLoaderArray[i].contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
imgLoaderArray[i].load(new URLRequest(xmlList[i].image));
}
function loaded(e:Event):void{
trace("index: "+imgLoaderArray.indexOf(e.currentTarget)); // return -1 every time
}