Populating a dynamic array with objects and managing it in runtime.
Copy link to clipboard
Copied
So I'm another stuck firstyear. I'll try and make my question compact. I'm using Flash CS6 and have drawn an animated character on the stage that consists of separate parts that are animated and its head is a separate class/symbol entirely because it has not only animation, but a state switch timeline as well. This said Head extends the Main that is the character MovieClip.
I am using a dynamic array to store and .push and .splice objects of another class that would collide with this said Head.
I also discovered the super() function that is implicitly called as the constructor of the parent in any child class that extends the parent, in this case Head extends Main. The issue is that my collidable object array is populated within the main, within the function that spawns every next collidable object with a TimerEvent. This said function then gets called twice due to the super() call.
I have tried putting this super() call into an impossible statement in my child class, but it doesn't change a thing, and it was said that this method is unsafe so I don't even know if it should be working.
However what confuses me the most is when I trace() the .length of my collidable object array at the end of that function. As I said earlier, the original function both spawns an object after a period of Timer(1000) and adds it to the stage as well as adds the object onto the object array, but the super() constructor only duplicates the length call and a creates a copy of the object on the stage, but it does not add the second copy of the object onto the array. The trace() output goes on like so:
1
1
2
2
3
3
4
4
etc.
I wonder why and I'm really stumped by this.
Here is the code in question:
public class Main extends MovieClip {
public var nicesnowflake: fallingsnow;
var nicesnowflakespawntimer: Timer = new Timer(1000);
public var nicesnowflakearray: Array = new Array();
public function Main() {
nicesnowflakespawntimer.addEventListener(TimerEvent.TIMER, nicesnowflakespawn);
nicesnowflakespawntimer.start();
}
public function nicesnowflakespawn(event:TimerEvent) : void {
nicesnowflake = new fallingsnow;
nicesnowflake.x = Math.random()* stage.stageWidth;
nicesnowflake.y = - stage.stageHeight + 100;
nicesnowflakearray.push(nicesnowflake);
stage.addChild(nicesnowflake);
trace(nicesnowflakearray.length);
for (var i:Number = 0; i < nicesnowflakearray.length; i++){
nicesnowflakearray.addEventListener(Event.ENTER_FRAME, snowhit);
}
}
public function snowhit(event:Event) : void {
if (nicesnowflakearray[0].y >= 460){
if (nicesnowflakearray[0].y == stage.stageHeight) {
nicesnowflakearray.splice(nicesnowflakearray.indexOf(nicesnowflake), 1);
}
//if (this.hitTestObject(nicesnowflake)){
//trace("hit");
}
}
I am also fiddling with the collision, but I believe that it would sort itself out when I deal with the array pop and depop properly. However I'm pasting it anyway in case the issue is subtly hidden somewhere I'm not looking for it. And here is the child class:
public class Head extends Main {
public function Head(){
if (false){
super();
}
this.stop();
}
}
}
So like what happens at the moment is that the array gets populated by the first object that spawns, but there is two objects on the stage, then when the objects reach stage.460y mark the array splices() the one object away and displays an error:
"#1010: A term is undefined and has no properties.
at Main/snowhit()"
then when the next object spawns, it repeats the process. Why does it trace the array.length as "1, 1, 2, 2, 3, 3, 4, 4, 5, 5, etc" until the despawn point and then goes on to display an error and then starts from 1 again, because if the array length is more than one object at the time when the first object of the array gets spliced away, shouldn't it go on as usual, since there are other objects in the array?
Thank you very much to whomever will read this through.
Copy link to clipboard
Copied
There are multiple problems:
1. You should add eventlisteners for your objects only once, but you add eventlisteners every time your timer runs to all of your snowflakes, again and again:
for (var i:Number = 0; i < nicesnowflakearray.length; i++){ nicesnowflakearray.addEventListener(Event.ENTER_FRAME, snowhit); }
change it to
nicesnowflake.addEventListener(Event.ENTER_FRAME, snowhit);
I don`t see why its even necessary to employ this snowflakearray, it would be much straight forward if you simply let the snowflakes take care of themselves.
2. Then you have to change your enterframe function accordingly
public function snowhit(event:Event) : void { if (e.currentTarget.y >= 460){ if (e.currentTarget.y == stage.stageHeight) {
e.currentTarget.removeEventlistener(Event.ENTER_FRAME, snowhit); removeChild(e.currentTarget); }
}
3.
//if (this.hitTestObject(nicesnowflake)){ //trace("hit"); }
since "this" is a reference to the Main class (root) it surely won`t function as you intend it to.
if (false){ super(); }
makes no sense to use a condition that can never be true
Copy link to clipboard
Copied
1. I moved the whole snowflakespawner etc out of the main into a separate snowflake symbol class.
2. The hitTest I posted was a rudiment and was previously in a different class, where this. was the head of the character.
3. Exactly. I found that you could force the program NOT to call super() at all by encasing it in an impossible statement, but I don't think I understood it fully and am not doing something right.
4. I have a different problem now. There is nothing left in my main and I just need to call in it the main function of the child snowflake class in order to execute everything like before. How do I simply call a child function in a parent class?
Copy link to clipboard
Copied
if the function is public you can call it with
_parent._child._myPublicFunction()
//subsitute with the instance names of your objects
Copy link to clipboard
Copied
I assume the underscores are necessary for some reason.
I don't think I'll ever be touching FlashCS6 again as a coding environment.
I don't believe I have anywhere an object of the Main class, since it is empty. Pretty much everything in my program is on the stage automatically because I drew it all there as symbols etc. There are no instantiations of objects in code aside from the falling snowflakes. I don't know what is objects anymore... or what is parent and child anymore... or what is real. Got:
1. My Main:
public class Main extends MovieClip {
public function Main() {
_Main._nicesnowflake._fallingsnow();
}
2. The class in question:
public class fallingsnow extends Main {
public var nicesnowflake: fallingsnow;
var nicesnowflakespawntimer: Timer = new Timer(1000);
public var nicesnowflakearray: Array = new Array();
var snowFlakeSpeed:int = 2.5;
public function fallingsnow(){
nicesnowflakespawntimer.addEventListener(TimerEvent.TIMER, nicesnowflakespawn);
nicesnowflakespawntimer.start();
this.addEventListener(Event.ENTER_FRAME, updateme);
}
And I need to call the fallingsnow(); in my Main. Or so I believe.
Copy link to clipboard
Copied
I assume the underscores are necessary for some reason.
No they are not, they are merely there, because "parent" and "child" are reserved keywords in AS3
I don't believe I have anywhere an object of the Main class
Every Flash file has an instance of the Main class, its called "root"
so in every flash file you can call "root" and will reach the highest object.
instead of writing
_Main._nicesnowflake._fallingsnow();
you can write
root.nicesnowflake.fallingsnow();
or if you call from Main you can simply write
this.nicesnowflake.fallingsnow();
this will trigger the public function that belongs to the nicesnowflake instance
Copy link to clipboard
Copied
Yeah I tried that. It didn't work. It provided me with an error in the output field saying sometihng about static class function or something. Although I'm not using `static` for anything.
In any case I just moved it all back into the Main and fixed it partially.
I fixed the double call of trace and the constructor duplication and life is almost beautiful.
The issue I've got now is that I can't seem to find the Head object on the stage in order to check its .y value against .y values of the snowflake objects that are falling down. So to make a manual collision test.
The head is just an empty class that extends MovieClip and has this.stop(); in it in order for it to enter the program in it's default state and not animate continuously.
And then I want to use my manual collision like so:
public function snowhit(event:Event) : void {
if ((nicesnowflakearray[0].y == Head.y) || (nicesnowflakearray[0].y == stage.stageHeight)) {
nicesnowflakearray.splice(nicesnowflakearray.indexOf(nicesnowflake), 1);
}
but it says "1119: Access of possibly undefined property y through a reference with static type Class". when I change the hardcoded value in the first statement parameter bracket to `Head.y`.
Which is also the same thing it said when I tried calling that child function in the main with the same syntax that you advised.
Thanks for bearing with me, Mocca.
Copy link to clipboard
Copied
The head is just an empty class that extends MovieClip and has this.stop();
For it to be able to have a y-property, Head must be a DisplayObject. If you made A "Head" Object than it must be added to the Displaylist. This can be done by dragging the Head-MovieClip from the library on to the stage or by adding it via Actionscript.
It seems you are directly trying to access the class why you should refer to the instance of the class.
Copy link to clipboard
Copied
Not to sound cheeky, but I've obviously done that. As in I drew it and put it on the stage, and animated and created different facial expressions on its own timeline besides the animation that goes together with the character. Then I clicked on it in the library and added AS3 linkage and created a class out of it to stop the continuous animation. Still wouldn't recognize it as an object with usable parameters.
Copy link to clipboard
Copied
Make sure you saved the Head.as file in a folder that the compiler knows about. For beginners its easiest to save all their classes in the same folder where the fla file sits that uses them.
If the compiler can`t find your Head.as file it will automtically generate one the moment you publish, thus "overriding" the code you used in your "true" Head.as.
Also: For Main to manipulate your Head instance, this Head must have a name, if you don`t give a name to it , which can be done via actionscript or via properties dialog, it will not find the object.
There is a useful convention that classes are written with leading capitals and objects start with lower case.
If you gave your Head the name "Head" instead of "head" you are in for some trouble, because Flash doesn`t know if you mean the class or the object
Copy link to clipboard
Copied
All of my source files are in the same folder as the .fla project.
Ok. I found the Head in my flash project. It's named Head as the original object that was created from the drawing and the instance name thats on the scene is named `head` so everything should be ok shouldnt it?
Trying to use `head.y` in my main and getting 1120: Access of undefined property head.
Copy link to clipboard
Copied
This said Head extends the Main that is the character MovieClip
I´m a little confused why you would name an ordinary MovieClip "Main", Main is usually reserved for the Document class that belongs to a swf file. You have some strange conventions going on in your code that makes it very hard to debug.
So after solving that puzzle this is what I read between the lines:
You have a simple fla file, which has no document class.
You have a MovieClip called Main in your library which is the Character without Head
You have a MovieClip called Head in your library which is the Head without Character
if you have two instances "head" and "main" on stage
since head extends main, head can call any public function in main with
super.function()
//subsitute the word function with the actual name of a function
whereas main can call any function of head with
this.parent.head.function()
a list of statements/words you should never attempt to redefine in your objects:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/statements.html
parent, child, root, main, String, Number, int, uint and any common properties (x,y,width,height) should also be avoided, because it makes your code unreadable.
if you feel you absolutely must use such words to name instances you should stick to a convbention like always addinmg a leading underscore to not confuse yourself
var _movieClip:MovieClip = new MovieClip();
var _sprite:Sprite = new Sprite();
etc

