Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411588 Posts in 69386 Topics- by 58443 Members - Latest Member: Mansreign

May 06, 2024, 06:48:59 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Actionscript 3: Assistance required
Pages: 1 [2] 3 4
Print
Author Topic: Actionscript 3: Assistance required  (Read 15708 times)
Problem Machine
Level 8
***

It's Not a Disaster


View Profile WWW
« Reply #20 on: October 01, 2008, 12:59:29 PM »

Quote
Global variables are not intrinsically evil provided they represent something unique, but in this case you're using it for storing something which is really non-unique in nature: a pointer to a game. Now perhaps you just happen to know that there will only ever be one game object in your system, but in a more general case your software will go horribly pear shaped as soon as you accidentally do this with something your software uses twice or more concurrently.
Um, no, you're storing a unique pointer to the STAGE, which is unique. Actually, what I'd do if I was actually making this (and I did make something similar) is have a static pointer to a default display object which new instances were added to and then another one for each instance. The constructor would use the static variable as a default parameter, but if one wanted to add the objects to another display object it would be as simple as passing that parameter to the constructor.
BTW, I'm currently working on a huge AS3 project for work, though I will admit that I was only brought in for the last month for debugging.
Code:
package {
  import flash.display.*;
  import flash.events.*;
  import flash.geom.*;

  class Blot extends Sprite {
    function Blot() {
      // Blot object gets created here.
      this.addEventListener(MouseEvent.MOUSE_DOWN, clickedBlot);
    }
    private function clickedBlot(event:MouseEvent) {
      Object(root).makeBlot(); // HERE
    }
  }
}
Okay, that's a grotesque solution. Basically you're typecasting the stage as an instance of your game object, and then using that type-cast stage's new makeBlot method.
Edit: Now that I look at it a little closer it's not QUITE so bad, but the way you cast the stage as (Object) really throws me off. Cast it as (Game) instead, so that you at least get compile errors if you refer to a nonexistent function.
« Last Edit: October 01, 2008, 01:05:01 PM by Kobel » Logged

agj
Level 10
*****



View Profile WWW
« Reply #21 on: October 01, 2008, 03:38:30 PM »

I know it's not exactly elegant, that's why I said that it's a momentary solution. I needed for it to work today to have something to show to my teacher. And I'll try to avoid doing that from now on. Hope I don't run into too many problems moving things around now.

edit: Oh yeah, just so you guys can see what this thread has helped me with, here's what I've got so far. No semblance of a game logic yet, though.
« Last Edit: October 01, 2008, 03:46:32 PM by agj » Logged

bateleur
Level 10
*****



View Profile
« Reply #22 on: October 02, 2008, 01:17:21 AM »

Um, no, you're storing a unique pointer to the STAGE, which is unique.

Whilst that's technically true, it's very misleading here.

The Stage isn't really needed. What the static field is holding in this case is a pointer to a DisplayObjectContainer (not DisplayObject as was suggested earlier). It doesn't have to be the Stage, it could be anything.

So yes, you're correct that there's nothing instrinsically wrong with this:

Code:
 public static var stage:Stage;

...but it's still a dirty hack, because if this toy example were to turn into a proper app you would no longer want to interact only with the Stage and would have other Sprites and so on in the hierarchy on which you might want to make Blobs. Leading to this:

Code:
 public static var container:DisplayObjectContainer;

...and that is bad.

So far better to just do things correctly. No static properties!

Sorry to be pedantic and make a huge fuss about things I know you already understand, but if there are people reading this thread who are just learning AS3 (or maybe even learning to program for the first time with AS3) it's really, really important not to be advocating Bad Things!
Logged

Problem Machine
Level 8
***

It's Not a Disaster


View Profile WWW
« Reply #23 on: October 02, 2008, 07:16:18 AM »

IIRC DisplayObject inherits from DisplayObjectContainer and I've never seen the latter actually instantiated, but yeah that all makes sense. I do think that the static member used as default value in constructor version that I was talking about is fine though (though probably unnecessary).
Logged

bateleur
Level 10
*****



View Profile
« Reply #24 on: October 02, 2008, 08:58:13 AM »

IIRC DisplayObject inherits from DisplayObjectContainer

Fortunately not!

The hierarchy goes like this:

DisplayObjectContainer -> InteractiveObject -> DisplayObject -> EventDispatcher -> Object

But you're right, it would be very unusual to instantiate a DisplayObjectContainer. What you often do want to do though, is to instantiate a Sprite. Sprite inherits from DisplayObjectContainer, but the Stage is not a Sprite. Hence the property type "DisplayObjectContainer" - it's the lowest common denominator.

Logged

Problem Machine
Level 8
***

It's Not a Disaster


View Profile WWW
« Reply #25 on: October 02, 2008, 09:08:23 AM »

Yeahhh... not sure what I was thinking there. How could something inherit from something made to contain instances of itself? That was retarded.  Undecided
Logged

agj
Level 10
*****



View Profile WWW
« Reply #26 on: October 03, 2008, 02:28:04 PM »

I managed to fix my code and do things the right way. But the rest of the road was not meant to be this easy. Thus, here's more fodder for some hot actionscript discussion!

My question is, can I add an array as a, uh, property, or however it should be called, of a sprite? Alternatively, can I have an object that contains both a sprite and an array as 'properties'? This is what I want to do, essentially:

Code:
var mySprite:Sprite;
var mySprite.itsArray:Array;

// Or:

var myObject:Object;
var myObject.itsSprite:Sprite;
var myObject.itsArray:Array;

What I want an array that contains a numeric representation of the sprite. But, obviously, doing it that way didn't work. Thanks, again.
Logged

agj
Level 10
*****



View Profile WWW
« Reply #27 on: October 03, 2008, 06:09:22 PM »

I've been experimenting, and so have found that working with static functions means less headaches in general--so thanks for giving me the idea, Kobel. This object oriented programming deal is kind of hard to grasp for someone whose limited experience has been mostly scripting and, uh, Basic.

I still haven't solved the abovementioned problem, though...
Logged

isaac
Level 2
**



View Profile WWW
« Reply #28 on: October 03, 2008, 08:57:21 PM »

Code:
var mySprite:Sprite;
var mySprite.itsArray:Array;

// Or:

var myObject:Object;
var myObject.itsSprite:Sprite;
var myObject.itsArray:Array;

What I want an array that contains a numeric representation of the sprite. But, obviously, doing it that way didn't work. Thanks, again.

The second one. Though the ideal way to do it would be:

Code:
public class ArraySprite extends Sprite{
    public var spriteArray:Array;
    public function ArraySprite () {
        spriteArray = new Array();
        super();
    }
}

So then you're not dealing with Objects, which don't give good error messages when you make mistakes.

I've been experimenting, and so have found that working with static functions means less headaches in general--so thanks for giving me the idea, Kobel. This object oriented programming deal is kind of hard to grasp for someone whose limited experience has been mostly scripting and, uh, Basic.

Surely if you're not using an object-oriented approach, you shouldn't need to use static methods -- just keep everything in one .as file, and you won't need to access methods from other classes?
Logged

agj
Level 10
*****



View Profile WWW
« Reply #29 on: October 03, 2008, 09:11:24 PM »

Ohh, so I have to go into the trouble of creating a new class to do that, huh? I thought it'd be easier. Thanks a bunch for that.

Regarding OOP and static methods: I am actually using one class separate from the main one, and this is why it's been useful in specific cases, since my approach has been to fragment the code into several methods in order to make it easier to expand later on.
Logged

bateleur
Level 10
*****



View Profile
« Reply #30 on: October 04, 2008, 03:10:13 AM »

Ohh, so I have to go into the trouble of creating a new class to do that, huh? I thought it'd be easier.

You need to try to be less shy about making new classes. Classes are to object oriented languages what sentences are to English - you can get by without them, but it's very limiting.

As it happens there is a much easier way to add properties to objects. Simply set the object's class up as dynamic. But... you can't do this, because you aren't using your own classes! (Sprite is a system class and is not dynamic.)
Logged

ninjascience
Level 0
***



View Profile
« Reply #31 on: October 04, 2008, 02:15:29 PM »

think of classes as contracts.  When you make a class that has certain properties and does certain methods, it's a contract to all your other classes that they can rely on.  If you start using dynamic properties then there's no trust between classes and your code can get messy and buggy REALLY quick.
Logged
agj
Level 10
*****



View Profile WWW
« Reply #32 on: October 04, 2008, 06:59:56 PM »

Well, I really see the benefit in creating classes for objects that will be repeated several times with the same properties, but, in this particular case, I only wanted it to hold a single big array, so I just left the sprite and its array separate, which is not quite as pretty as I wanted it to be, but it works the same.

I can see the point in classes not being dynamic, yeah. It does help to force the code to be stricter.

On another note: I discovered the weirdest bug in my code. Or in Flash player's code, maybe. My code constantly creates sprites and removes them; it keeps track of them using an array. After playing around with the thing running for a bit, it suddenly breaks, and spits an error about removeChild(), saying that the parent DisplayObject does not have the object passed as an argument as its child. Several hours of debugging later, I discover that this is caused because the sprite that I'm trying to remove had already been removed, but it wasn't deleted from the array. Testing the code a bit I find that, to my dismay, the splice() function does not work every time I call it. Most of the time it does, but every now and then it just doesn't, not even throwing an error. So, after failing to delete the sprite's reference in the array, the next time the code tries to delete that same sprite, it breaks. The weird thing is that I could find no pattern at all to when splice() would not work, so I just used 'delete' instead, and, well, it's working now. What gives?

Through this whole debugging deal I also realized that the number of sprites keeps escalating as it's running, even though I am cleaning all of their traces. Is there a way to effectively remove them?
Logged

bateleur
Level 10
*****



View Profile
« Reply #33 on: October 05, 2008, 03:46:20 AM »

Testing the code a bit I find that, to my dismay, the splice() function does not work every time I call it.

Can we see the relevant section of code, please?

Quote
Through this whole debugging deal I also realized that the number of sprites keeps escalating as it's running, even though I am cleaning all of their traces. Is there a way to effectively remove them?

What do you mean by "number of sprites"? On screen? In some array? In memory?

Flash has a garbage collector, so you need to remove all references to an object before it will completely disappear. Even then, it will only actually disappear when the system decides to collect it.
Logged

agj
Level 10
*****



View Profile WWW
« Reply #34 on: October 05, 2008, 06:30:25 PM »

Can we see the relevant section of code, please?

Hmm, I'm not sure how much you'll be able to understand, but here are the two methods involved, which I'll just post verbatim. What do you think?

Code:
// Method: Paint blot on canvas.
private var drop:Sprite;
private var blotDepth:uint;
private function paintBlot(blot:Blot, x:int, y:int):void {
for (var column:uint = 0; column < 4; column++) {
for (var row:uint = 0; row < 4; row++) {
// Paint drop.
if (blot.shape[column][row] > 0) {
drop = makeDrop(blot.shape[column][row], blot.color);
// Add to array.
if (blot.shape[column][row] == 3) {
deleteDrops(column + x, row + y, 1, 2, 3);
canvasReference[column + x][row + y][1] = drop;
} else if (blot.shape[column][row] == 2) {
deleteDrops(column + x, row + y, 2, 3);
canvasReference[column + x][row + y][2] = drop;
} else {
deleteDrops(column + x, row + y, 3);
canvasReference[column + x][row + y][3] = drop;
}
drop.x = (x + column) * canvasInter;
drop.y = (y + row) * canvasInter;
canvas.addChild(drop);
}
}
}
}

// Method: Delete drops.
private function deleteDrops(column:uint, row:uint, ...depths) {
for (var i:int = depths.length - 1; i >= 0; i--) {
if (canvasReference[column][row][depths[i]]) {
if (canvasReference[column][row][depths[i]].parent == null) { // Error-catching.
trace("Error in deleteDrops(): DisplayObject " + canvasReference[column][row][depths[i]].name + " has no parent.");
return;
}
canvas.removeChild(canvasReference[column][row][depths[i]]);
// canvasReference[column][row].splice(depths[i], 1); // THIS DOESN'T ALWAYS WORK
delete canvasReference[column][row][depths[i]];
}
}
}

What do you mean by "number of sprites"? On screen? In some array? In memory?

What I mean is simply that the sprites I was creating were named automatically 'instance1045', or some number, and escalating over time. Maybe the garbage collector does get rid of them but Flash still doesn't re-use their instance names?
Logged

Problem Machine
Level 8
***

It's Not a Disaster


View Profile WWW
« Reply #35 on: October 06, 2008, 01:17:11 PM »

An easy way to safely solve this would be
Code:
if (canvasReference[column][row][depths[i]].parent)
   canvasReference[column][row][depths[i]].parent.removeChild(canvasReference[column][row][depths[i]])

canvasReference[column][row].splice(depths[i], 1);
The main difference, AFAIK, between deleting the node and splicing it out is that deleting nulls it and splicing removes that space in the array. For example, given the array
1, 2, 3, 4, 5, 6, 7
If you delete 3 you get
1, 2, null, 4, 5, 6, 7
Whereas if you splice it you get
1, 2, 4, 5, 6, 7
This can cause a problem with your for loop, because the length of the array changes as you're going, so each time you splice an element out you're going to be skipping it on the next iteration. In order to avoid that, you could do this:
Code:
canvasReference[column][row].splice(depths[i--], 1);

Hope that provided a little extra insight. I recently ran into the above mentioned problem myself.
Logged

agj
Level 10
*****



View Profile WWW
« Reply #36 on: October 06, 2008, 01:53:21 PM »

I actually knew the difference between splice() and delete, and I considered what you're saying as a possible cause of the problem, so I did something like what follows, to check:

Code:
trace(canvasReference[column][row][depths[i]].name);
canvasReference[column][row].splice(depths[i], 1);
trace(canvasReference[column][row][depths[i]].name);

Not exactly that, as doing that would break the code if the reference in the array is undefined (by trying to access a property of nothing), but basically that. As you can imagine, every now and then both trace()s would output the same thing. Now, there's a lot of variables in play and maybe I overlooked something, but it still seemed weird that it only happened in random occasions, while working fine most other times.

Code:
canvasReference[column][row].splice(depths[i--], 1);

I don't understand this, though. What's the i-- supposed to do in that context? Does it actually alter its own value after outputting i, or decrements first, or doesn't modify itself at all? Either way, I don't really understand what the improvement is.
Logged

Problem Machine
Level 8
***

It's Not a Disaster


View Profile WWW
« Reply #37 on: October 06, 2008, 02:20:54 PM »

Oh dang I didn't notice you started at the top and worked down. That changes things a little bit. In that case, the post-decrement is pointless, yeah (it's for if you start from index 0 and work up, to knock the iterator down to the appropriate node each time one is spliced out).

Okay, here's my guess as to why it's tracing out the same value. You splice out the third element, and then you access it; because the garbage collector hasn't collected either the severed node or the value stored in it yet, this works and reconnects you to the node you just spliced. However, when you delete the node instead it gets nulled out, and there's no longer an instance name to refer to. The nasty bit is, I suspect that by referencing it you revive that node in the array, which would make the array a different length than expected.

Why is it even necessary to kill the sprite from the array? As long as it eventually gets removed from memory (when that element is overwritten) I don't see why that needs to be done. Am I missing something?
Logged

agj
Level 10
*****



View Profile WWW
« Reply #38 on: October 07, 2008, 12:07:06 AM »

But the thing is that it doesn't matter what length the array is; I'm not going by its length, I use a set of numbers that are included as parameters and stored in a completely unrelated 'depths' array with said parameters.

Why is it even necessary to kill the sprite from the array?

Because I use it to keep track of sprites on the stage. I check the array to see if the new sprite will cover any other sprites, and delete those. In less abstract terms, I have a grid of dots, on which the player can drag masses of colored circles of different sizes; my array, which is three-dimensional for this purpose, is used to check whether each circle is big enough to cover sprites directly under it, and which.

Don't think it over too much, it's working now and that's what matters. :) Well, sort of, because I decided to change my approach yet again and I'm in the process of fixing everything as I move code from one part to the other.
Logged

bateleur
Level 10
*****



View Profile
« Reply #39 on: October 07, 2008, 01:15:37 AM »

Code:
trace(canvasReference[column][row][depths[i]].name);
canvasReference[column][row].splice(depths[i], 1);
trace(canvasReference[column][row][depths[i]].name);

I've been thinking about this a bit and there's only a few ways this could happen:

1) You have the same object stored more than once in your array.
2) You are misinterpreting the trace because the two lines are identical (I'd recommend always adding some unique prefix to each trace so you can be sure which line you're looking at) and the two values "the same" are not from the same cycle.
3) You have more than one object with the same name.

Can't say which is most likely without knowing more about your software.

Chances of a bug in splice() for a case this simple: basically zero.
Logged

Pages: 1 [2] 3 4
Print
Jump to:  

Theme orange-lt created by panic