Respecting OOP a bit better this time around...

35 posts

Flag Post
So I'm (semi) hard at work on my previous game's sequel, but I want to clean up the engine a bit, first. For starters, I'd like to be more OOP-friendly this time around. I've got a few questions though in particular:

1) Previously, enemy AI would do the following when it wanted to shoot:

GameContainer.singletonReferenceToCurrentGameContainer.AddBullet(new [Bullet class here--there are many different types!](...various params here);

(Names changed for clarity's sake) Yeah I know, pretty ugly. I know that another option is to have the game container listen for custom events, and dispatch an event. I'm considering that, but my main question is this: Would it be faster than my current method? Or slower? I suck at setting up speed tests and such, so I figured I'd ask here and see if anyone knows off the top of their head before I try to cobble some sort of (probably fairly inaccurate) speed test together.

2) (Only really relevant if the answer to #1 being "faster or about the same" is "yes") I'm pretty unfamiliar with custom events. With the reach-across-the-classes function, it was easy to initialize everything when instantiating a new bullet: (initialX, initialY, direction, speed, bulletCreator, ...etc), with etc being special parameters that only a few actually needed. How will I get all of that information to a new bullet if I use events?
 
Flag Post

1) Using events would not be faster. Either way a function is being called, but consider the overhead of processing events. I can’t quantitatively say how much slower using events would be and it could be negligible in your project. That said, using an event driven system could be more “OOP-friendly” because it protects encapsulation.

2) Your custom event class can contain all of these properties.

 
Flag Post

From what I understand, you have an instance of a class that is calling a method of a singleton. There’s nothing wrong with that, especially as you’re sure that there will be one and only one instance of GameContainer.

There may be situations where you want an instance of a class to call a method of another object that isn’t a singleton or a child of the first class. An example of this would be having a child object notify its parent object that it is dead. Most tutorials would tell you to use custom events in such cases. Having to listen for events slows down the game a bit, however. My approach is to use callback functions instead. In AS3, functions are treated as objects, and you can store a function in a variable of type Function. For example, one can have the first class implemented as follows:

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	
	public class ClassChild extends Sprite
	{
		private var _personLeaving:String;
		private var _framesBeforeLeaving:uint = 50;
		private var _callbackLeave:Function;
		
		public function ClassChild(person:String, functionLeave:Function)
		{
			super();

			_personLeaving = person;
			_callbackLeave = functionLeave;
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		} // public function ClassChild
		
		private function onEnterFrame(e:Event):void
		{
			if (_framesBeforeLeaving > 0)
				_framesBeforeLeaving--;
			else
			{
				removeEventListener(Event.ENTER_FRAME, onEnterFrame);
				_callbackLeave(_personLeaving);
			}
		} // private function onEnterFrame
		
	} // public class ClassChild
	
} // package

Then the second class can be implemented as follows:

package 
{
	import flash.display.Sprite;
	import flash.events.Event;
	
	public class Main extends Sprite 
	{
		private var _myChild:ClassChild;
		
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		} // public function Main
		
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			_myChild = new ClassChild("Elvis", onLeave);
		} // private function init
		
		public function onLeave(person:String):void 
		{
			trace(person + " has left the building.");
		} // public function onLeave
		
	} // public class Main
	
} // package
 
Flag Post

Oh bummer, so it is in fact slower. I had a feeling it was, since in theory, it would be doing several other things in addition to making the game container add a bullet, compared to…well just telling the game container to add a bullet directly. That’s (unfortunately) reason enough to stick with my current method, even if it makes encapsulation cry. Thanks. :)

Edit: Hmm, callbacks might not be a bad idea at all. I’m going to play with that and see what I can do. :)

 
Flag Post

Signals might help you out. It’s basically the ‘shit’ (in a good way).

 
Flag Post

Just FYI, Events no matter from what library and in what flavor, are by definition slower than calling the methods of a class directly. There are no exceptions.

Also, functions as objects can be incredibly useful for many purposes, however, when you treat functions as object, you have a performance penalty because the type of the function is lost, so the runtime has to do some special stuff whenever you call the function.

myEnemy.update(); //fast

var temp = myEnemy.update; //store the function in a variable

temp(); //slow
 
Flag Post

As far as I can tell, the solutions get slower the more correct they are.

1. Pass a reference to the game container in the constructor and call the function directly (fast but dodgy)
2. Use a callback function (slightly slower but not dodgy)
3. Custom event (somewhat slow).

Hopefully someone can come up with the goods though. Signals look interesting.

 
Flag Post

Drakim and stickman are right. At some point, however, AS3 programmers have to strike a balance between speed and maintainability/re-usability of code. If you find that you have a number of classes that need to communicate with one another, I feel that using callbacks generally strikes a reasonably good balance. In the end, how best to implement class-to-class communication should be handled on a case-to-case basis.

 
Flag Post
Originally posted by Drakim:

Also, functions as objects can be incredibly useful for many purposes, however, when you treat functions as object, you have a performance penalty because the type of the function is lost, so the runtime has to do some special stuff whenever you call the function.

myEnemy.update(); //fast

var temp = myEnemy.update; //store the function in a variable

temp(); //slow

This isn’t true.

 
Flag Post

Elyzius is right on. It ultimately matters on a case-to-case basis, and as bad you say you are in setting up speed tests, you’re going to need to learn it if you’re game is very performance intensive. Think of it as learning something new :3

If I may, I suggest you simply use your current implementation. However you could further optimize that by saving the game container to a variable in your enemy object. That is faster, and more OO.

 
Flag Post
Originally posted by BigJM:
Originally posted by Drakim:

Also, functions as objects can be incredibly useful for many purposes, however, when you treat functions as object, you have a performance penalty because the type of the function is lost, so the runtime has to do some special stuff whenever you call the function.

myEnemy.update(); //fast

var temp = myEnemy.update; //store the function in a variable

temp(); //slow

This isn’t true.

It’s very true actually: Link

It’s about 14 times slower. Ka-ching!

 
Flag Post

I see, so basically, I was pretty much on the right track performancewise, with the exception Secretmapper mentioned—which I plan on including this time around, of course. I’ll save the proper OOP stuff for something less picky about performance, such an RPG. Thanks guys. :D

Edit: Would the same thing apply to classes as objects? Because I abuse the hell out of that. :O

 
Flag Post

I think the problem is that you have the logic backward. Your enemy object is calling the main game object saying it wants to create a bullet, when it should be the game calling the enemy and asking if he’s ready to spawn bullets now. The game contains the enemies, therefore the game calls the enemies. Soldiers don’t grab stuff on their general’s desk.

Anyway, so the game queries, and the enemy replies with an Array. If the answer is [] it means no bullet to spawn, and otherwise each element has one bullet info (type, bearing, speed, damage, homing, etc… all nicely packed in a bullet object). The game then pushes that array at the bullet array so all bullets will get displayed and get henceforth to live their bullet lives, fully dissociated from the enemy that spawned them.

 
Flag Post

It’s unlikely the performance difference between an event model and direct calls is going to make the slightest bit of difference on a computer built in this century unless you are calling it hundreds or thousands of times per frame. And if you are putting that much load on the event model it’s likely you are doing something else wrong that is much more severe. There are some cases where it’s absolutely necessary, but in general this sort of thing is the last place you look for optimization.

Write your code the correct way first and if you need to optimize you’re going to get a lot more mileage looking at screen redraws, complex loops and algorithms, stuff like that.

 
Flag Post

If you use it as the underlying mechanism of for anything “happening” in your game, it’s not unlikely that it’s gonna be called thousands of times per frame.

While it’s true that machines these days can handle a lot of work, you simply are not allowed to make your little flash 2d game require the same specs as Crysis to run at an acceptable rate.

Optimizing is grand, but often these early architectural foundations of your game is very hard to change once most of the game is built. The “don’t optimize early” mantra is invalid, instead, you should be aware of what you are using and what cost it will have at scale.

Make informed decisions that will not come back to haunt you.

 
Flag Post

If you use it as the underlying mechanism of for anything “happening” in your game, it’s not unlikely that it’s gonna be called thousands of times per frame.

If that’s the case, a bigger, architectural decision is more important than the concrete specifics of the implementation.

Optimizing is grand, but often these early architectural foundations of your game is very hard to change once most of the game is built.

I disagree. It is incredibly easy to change.

The “don’t optimize early” mantra is invalid, instead, you should be aware of what you are using and what cost it will have at scale.

This depends on the developer.

 
Flag Post
If that’s the case, a bigger, architectural decision is more important than the concrete specifics of the implementation.

The entity loop / entity event system is not some minor sidequest in how your game runs. I actually have a hard time thinking of any “bigger, architectural decision”, except graphics.

We all know how utterly terrible games that uses a MovieClip with an ENTER_FRAME listener for every entity runs.

If you are planning to make a bullet game, or a huge world simulation game, this is a very vital decision you need to make early on in development.

I disagree. It is incredibly easy to change.

I disagree back. Early architectural decisions tend to affect how the rest of your game works.

You can’t just glue on multiplayer to your game once it’s complete, it needs to be accounted for from day 1 in the development.

Likewise, if you want your world’s boundaries to extend forever in every direction (like minecraft) your entities can’t just be powered by a flash event.

And don’t even get me started on multi-threading.

None of these things are “incredibly easy”.

This depends on the developer.

It does not. All developers should be aware of what they are using and what cost it has. Shitty flash developers are what got us in this “everybody hates Flash” mess in the first place. Flash is a pretty decent plugin but it has the reputation like that of a lame horse with cancer because people don’t care about their craft.

 
Flag Post

The entity loop / entity event system is not some minor sidequest in how your game runs. I actually have a hard time thinking of any “bigger, architectural decision”, except graphics.

If you’re having a hard time thinking of any bigger architectural decision except graphics, then you have never coded something big before/always focused on the front-end. The back-end can be as much more of a hog than the front-end if left to the simplest implementation. Collision-detection? Path-finding?

I disagree back. Early architectural decisions tend to affect how the rest of your game works.

You can’t just glue on multiplayer to your game once it’s complete, it needs to be accounted for from day 1 in the development.

Likewise, if you want your world’s boundaries to extend forever in every direction (like minecraft) your entities can’t just be powered by a flash event.

And don’t even get me started on multi-threading.

None of these things are “incredibly easy”.

Straw man argument. We were talking about how bullets are added in the game. That is incredibly easy to change. This is not even an “early architectural decision” as you say.

It does not.

http://en.wikipedia.org/wiki/Big_Design_Up_Front
http://en.wikipedia.org/wiki/KISS_principle
http://en.wikipedia.org/wiki/Don%27t_repeat_yourself
http://en.wikipedia.org/wiki/Agile_software_development
http://en.wikipedia.org/wiki/Continuous_integration

The list goes on. There are numerous programming philosophies. And actually, I’ve reread what you’ve said:

The “don’t optimize early” mantra is invalid, instead, you should be aware of what you are using and what cost it will have at scale.

Optimizing stupid things early on is a must. But you also need to plan what to optimize. This is where architectural decisions come in. Currently it is in a case of worrying about how to add bullets. You spend most of your time in this.

Then you realize that the game is really slow. You decided to pool your bullets, which had a new way of adding bullets to the stage. All that optimization early on was moot since you failed to focus your attention on something that would ultimately matter.

All developers should be aware of what they are using and what cost it has. Shitty flash developers are what got us in this “everybody hates Flash” mess in the first place. Flash is a pretty decent plugin but it has the reputation like that of a lame horse with cancer because people don’t care about their craft.

We actually agreed for a change, save the “Flash is a pretty decent plugin” part.

 
Flag Post
If you’re having a hard time thinking of any bigger architectural decision except graphics, then you have never coded something big before/always focused on the front-end. The back-end can be as much more of a hog than the front-end if left to the simplest implementation. Collision-detection? Path-finding?

Since when did graphics become front-end? Graphics is a very deep and hard topic. It’s certainly a lot harder than Path-finding. :(

AS3 has most graphical things ready implemented though, so I guess if one is happy with that it’s a pretty minor topic.

Straw man argument. We were talking about how bullets are added in the game. That is incredibly easy to change. This is not even an “early architectural decision” as you say.

Since when were we were talking specifically about bullets being added in a game? I recall we were talking about event callbacks vs typed function calls, where I said that these architecture decisions are important while you disagreed.

You wrote “It is incredibly easy to change.” in regards to my “but often these early architectural foundations of your game is very hard to change”. It’s not a strawman to point out that often these things are not easy.

If you go on with a philosophy that “everything is dead easy to change afterwards” you are gonna acquire a lot of technical debt and have a bad time. Stability, correctness and performance are not things that can just be taped on once your game is done.

Currently it is in a case of worrying about how to add bullets. You spend most of your time in this.

Although this topic specifically mentions adding bullets to the “world”, it’s merely used as an example for OOP design. OP wants to know about OOP.

Look, I’m not interested in arguing for the sake of arguing, but it’s ludicrous to say that it “depends on the developer” in regards to the statement “developers should be aware of what the are using and how it scales”. There is absolutely zero benefits of a developer not knowing this.

 
Flag Post

Since when did graphics become front-end? Graphics is a very deep and hard topic. It’s certainly a lot harder than Path-finding. :(

Front-end can be used generally. But yes, Graphics is a deep topic, and certainly we could talk about this all day. But since flash implements it already, it’s minor.

I recall we were talking about event callbacks vs typed function calls

Yup, which are easy to change.

Let’s use collision detection as a frame.

Even if you use the most efficient way of calling functions, but you keep using a simple hit test between two arrays, you’re game will lag. But even if you use the most inefficient way of calling functions but use something like a quad-tree, it will run faster.

That’s basically it.

 
Flag Post

There are two answers to the original question that I’ve used.

One is, instead of having a singleton game object, to pass the game object into the constructor of each entity you make, and store it. That way an entity can do the same call that is in the first post, but on ‘my game’ not ‘the game’. This kind of two way reference (game contains entities, entities know about the game they’re in) can be very useful.

The other is, when the game is doing its update loop and calling an update function on each entity, it can ask the entity whether it wants to spawn anything, and the game can handle adding them to the object tree.

 
Flag Post

A decoupled architecture is going to be the easiest to refactor down the road. If you find it necessary to make thousands or more event calls in a particular case then it should be very easy to change only that case to do a direct function call. It is fine to tightly couple things for performance reasons, but a correctly decoupled architecture is really easy to put back together. Whereas if you are tightly coupling your entire architecture it’s going to be more difficult to pull it apart later. And in general this has much less impact on performance that how you architect your collision, sorting, path-finding or other intense algorithms. Even object pooling is a better optimization.

I would never rely on event dispatches for a CPU intensive sorting algorithm that runs every frame, but it’s better you don’t write your entire code-base in that mindset.

 
Flag Post
Originally posted by Drakim:
Originally posted by BigJM:
Originally posted by Drakim:

Also, functions as objects can be incredibly useful for many purposes, however, when you treat functions as object, you have a performance penalty because the type of the function is lost, so the runtime has to do some special stuff whenever you call the function.

myEnemy.update(); //fast

var temp = myEnemy.update; //store the function in a variable

temp(); //slow

This isn’t true.

It’s very true actually: Link

It’s about 14 times slower. Ka-ching!

I knew you were going to send me a link to that site. Aside from the methodological and analytical errors underlying the test itself, he’s comparing calling properties with calling method closures (which isn’t what was suggested earlier). The speed discrepancy he found (if there even is one; it’s impossible to tell by his results due to the aforementioned errors) is likely caused by this and not because “the type of the function is lost” or “the runtime has to do some special stuff”.

 
Flag Post
Originally posted by Ace_Blue:

I think the problem is that you have the logic backward. Your enemy object is calling the main game object saying it wants to create a bullet, when it should be the game calling the enemy and asking if he’s ready to spawn bullets now. The game contains the enemies, therefore the game calls the enemies. Soldiers don’t grab stuff on their general’s desk.

Anyway, so the game queries, and the enemy replies with an Array. If the answer is [] it means no bullet to spawn, and otherwise each element has one bullet info (type, bearing, speed, damage, homing, etc… all nicely packed in a bullet object). The game then pushes that array at the bullet array so all bullets will get displayed and get henceforth to live their bullet lives, fully dissociated from the enemy that spawned them.

I thought about doing it that way in the beginning, actually. The problem arises in the occasional special case, where an enemy needs to interact with the game container in ways that involve more than just shooting bullets. For example, the last boss changes and accelerates the background when she spawns, and then reverses its direction on the last phase. When a boss is killed or switches phases, it needs some way to tell the game container to wipe out all of the spawned enemies/bullets. The dialog sequences and tutorial overlay text are also initiated by “enemy” objects with no graphic that immediately terminate themselves afterward. (Weird, I know, but it flows pretty well!) There’s a few others that don’t immediately come to mind, but you get the idea. Because of those odd exceptions, it seemed more logical to let the enemies tell the world how they wanted to interact with it.

Originally posted by Secretmapper:

Optimizing is grand, but often these early architectural foundations of your game is very hard to change once most of the game is built.

I disagree. It is incredibly easy to change.

To be fair, I think “easy” is an ambiguous term in this particular case. Based on my last game, if I were to go in and change the singleton game container reference spawning technique with another, such as callbacks, I’d be requiring myself to (after making sure the initial implementation worked properly, of course) go back into every single enemy. My last game had about 114 enemies, bosses, and special bullets (even the bullets shoot bullets!) that would all need to be checked. Now that might be easy in that it isn’t a coding challenge, but it’s still a fair amount of work, and such a large, sweeping change carries with it the possibility of introducing new bugs. Not something I’d want to mess with once most of the game was built.

 
Flag Post
Originally posted by BigJM:

I knew you were going to send me a link to that site. Aside from the methodological and analytical errors underlying the test itself, he’s comparing calling properties with calling method closures (which isn’t what was suggested earlier). The speed discrepancy he found (if there even is one; it’s impossible to tell by his results due to the aforementioned errors) is likely caused by this and not because “the type of the function is lost” or “the runtime has to do some special stuff”.

Here is a newer version of the test, featuring pretty much every way you could possibly call a function in AS3: Link

Plain                               432
Local                              344
Function var (Plain)	     308
Function var (Private)	     216
call (Plain)	                     427
call (Private)	             859
apply (Plain)	             311
apply (Private)	             834
Private                            56
Protected                        57
Internal                           60
Public	                             59
this.Private	                     55
this.Protected	             60
this.Internal	             59
this.Public	                     54
Static private	             67
Static protected               65
Static internal                  61
Static public                    64
Static private (by class)    68
Static protected (by class)69
Static internal (by class)   71
Static public (by class)     70
Override protected           61
Override internal              60
Override public                59
Super protected              66
Super internal                 63
Super public                   62
Interface direct              54
Interface via interface     53
Interface via class          56
Private Get                    64
Protected Get                60
Internal Get	                  59
Public Get                     58
Private Set                   60
Protected Set               61
Internal Set	                  61
Public Set                     58
Final Private                  54
Final Protected              56
Final Internal                 59
Final Public                    61
Final Override protected  58
Final Override internal     56
Final Override public       59

As you can see, referencing a function and calling a function though that reference is objectively slower.