[Solved] Understanding the usage of "world.create()"


(Helios) #1

The big question here is about closure when using FP. recycle and FP.create…

okay, so when one uses FP.recycle, what happens to the objects member variables? For instance, if my entity has member variable currentThoughts:Vector<String>, and I call

myEntity.currentThoughts.push("I have come back from the dead!")
myEntity.recycle();
FP.world.create(myEntity);
trace(myEntity.currentThoughts[0]);

am I going to trace out “I have come back from the dead!”? Or are all the member variables reset to the states specified by the constructor? Does FP.create bypass the constructor entirely?

That said, my general impression of the use of create is this:

If you are planning to instantiate your entity with the create method, you need to essentially move your constructor details into a separate, created() function which you then call via FP.world.create(myEntity).created();

is that about right?


(Jacob Albano) #2

Exactly. The best way to think of it is that you’re not creating a new Entity, you’re just taking one you don’t need any more and re-purposing it. All its state will be unchanged.


(Helios) #3

That’s a really great functionality to have!

Is there any way to get around the fact that it breaks inheritance?

like, lets say I have a class bullet and a subclass subBullet extends bullet

and lets say we have them set up for recycling as follows

public class bullet
{
	private var x:Number;
	private var y:Number;
	public function bullet(x:Number = 0, y:Number = 0)
	{
		created(x, y);
	}
	public function create(x:Number = 0, y:Number = 0)
	{
		this.x = x;
		this.y = y;
	}
}

public class subBullet extends bullet
{
	private var x:Number;
	private var y:Number;
	private var superSonic:Boolean;
	public function bullet(x:Number = 0, y:Number = 0, superSonic:Boolean = false)
	{
		created(x, y, superSonic);	
	}
	public function create(x:Number = 0, y:Number = 0, superSonic:Boolean = false)
	{
		this.x = x;
		this.y = y;
		this.superSonic = superSonic;
	}
}

So, if I do this, I’m going to get an error – “incompatable override - created()” so you can’t really use inheritance with the FP.world.create(myEntity).created() pattern.

Like I said, are there any good work arounds?


(Jacob Albano) #4

Unfortunately this is due to AS3’s ridiculous restrictions on method overloading. Even though you’re not trying to literally override create(), it won’t allow you to add a method on a subclass with the same name.

Here’s how you might work around that:

  • Approach #1: Pass an array of parameters
//  on bullet
public function create(args:Array)
{
    this.x = args[0];
    this.y = args[1];
}

// on subbullet
public override function create(args:Array)
{
    base.create(args);
    superSonic = args[2];
}

Pros: Easy to set up and override.

Cons: No way to check (at compile time) that you’ve passed enough parameters.

  • Approach #2 : varargs
//  on bullet
public function create(args...)
{
    this.x = args[0];
    this.y = args[1];
}

// on subbullet
public override function create(args...)
{
    base.create.apply(this, args);
    superSonic = args[2];
}

Pros: Calling create() feels just like any other function.

world.create(bullet).create(x, y);
world.create(subbullet).create(x, y, true);

Cons:Same drawbacks as the first approach, and delegating calls down the chain with Function.apply() is ugly.

  • Approach #3: Object literals
//  on bullet
public function create(options:Object)
{
    x = options.x;
    y = options.y;
}

// on subbullet
public override function create(options:Object)
{
    base.create(options);
    superSonic = options.superSonic;
}

Pros: Easy to set up and override.

Cons: Again, no type safety.

Matter of preference: If you like object literals, you’ll like the way to call these functions.

world.create(bullet).create({ x : 100, y : 50});
world.create(bullet).create({ x : 100, y : 50, superSonic : true});

Overall there’s really no way I can think of to have the flexibility you’re looking for while at the same time making things type-safe.


(Helios) #5

That’s excellent, thanks a lot. I was kind of honing in on that third solution, but your excellent articulation has saved me quite a bit of time.

Well, I’ll do what I can with what I have. That’s really phenomenal advice. Hopefully I can make the title something easy to search so others can see this.


(Martí Angelats i Ribera) #6

Isn’t it possible to use this?

//on bullet
public function create(x:Number = 0, y:Number = 0, ...args):void
{
    this.x = x;
    this.y = y;
}

//on subBullet
override public function create(x:Number = 0, y:Number = 0, ...args):void
{
    super.create(x, y);
    superSonic = args[0];
}

And insted of x and y being private make be protected (no need of another x and y in the subclass).

For me is easier to see what’s going on this way.

PD: I see it’s solved but if someone in the funure serch it i would like him to know this option as well.


(Jacob Albano) #7

Sure. My purpose wasn’t to show every possible combination of approaches, just a few ways to handle variance. Your solution is fine for your needs, but it won’t necessarily work for everyone or every class; some classes will choose their position randomly, or defer to some other value to get that information.

And insted of x and y being private make be protected (no need of another x and y in the subclass).

x and y are public variables on Entity. No need (or option!) to specify them on each subclass.


(Martí Angelats i Ribera) #8

Actually true but the code he sended wasn’t extending an Entity and was using private x and private y in the Bullet class and the subBullet class. If extends an Entity of course there is that public variables (probably my bad for not understanding that).

And my aproach was just another solution (is a bit of a database for future serches and visits). Everyone have their way to make that.

PD: Actually whould be nice to test for args[0] is Boolean before set the variable.


(Jacob Albano) #9

I’m sure that was purely for the sake of example code, as world.create() will throw a type coercion error if the type passed to it isn’t an Entity. If that’s not the case, good call.

I considered adding error checking but I figured this is an error you most likely want to leave unsuppressed. If you pass the wrong values to an initialization function, you want the game to crash so you can fix it.