Respecting OOP a bit better this time around... page 2

35 posts

Flag Post

You have 114 separate classes all running the same hard-wired static call? Good lord! Right there, your code is so tightly coupled you can’t even change the method without a huge overhaul. If you really want to improve your architecture that right there should be the first thing you fix. I can’t even fathom how that would work. Having an entirely separate class for each game object sounds nuts.

 
Flag Post
Originally posted by BigJM:
[snip]

I read “The test is wrong and the results are wrong and you are wrong”. Is all you know how to say “Nope, that’s wrong”? If you want to call someone out on something that’s wrong, fine. At least back up your statement.

The type of the function IS lost. This is a compiletime thing, and that’s clearly what Drakim was talking about. There’s no way to infer the type of the function at compiletime (except in very specific situations — and this doesn’t happen anyway, with Adobe’s compiler). If you want to say I’m wrong:

function a():bool { return false; }
function b():int { return 200; }

//...

Function f;
if (Math.random() > .5) { f = a; }
else { f = b;}

//Computers are not magic. If the compiler could know what the return type of f is here, so could you. So tell me what it is.
var x:??? = f();

The function type DOES exist — at runtime, in the RAM, bundled with the function object. This is obvious. Why wouldn’t it? Why would we just throw it away. The issue here however is that the runtime DOES have to do some “special stuff” now. If we had known the type of the function at compiletime, the compiler could have hard-coded in the details, but since it doesn’t, it has to do a lookup on the function object to find the type.

So, both the statement that “the type of the function is lost” and “the runtime has to do some special stuff” are true statements. Now, this doesn’t necessarily mean that function objects are necessarily slower. It’s possible that Adobe is retarded, and treats even direct function calls as calling through a function object. Based on my own speed tests a year or two back, the Jackston Dunstan article, 6 years of Flash experience, and general knowledge of computer science in general, I don’t think this is the case. (Even Adobe shouldn’t be that dumb).

If you want to argue otherwise fine. There is a possibility (though I have no reason to believe it to be very large at this point) that I’m wrong. Show me a test with “better methodology” that supports your argument — if you’re qualified to dismiss that test, you should be able to write your own. Show me documentation about how Adobe doesn’t take advantage of the obvious benefits of direct function calls. Look at the bytecode and show me that they’re equivalent. Take your pick. But don’t just tell me I’m wrong without any supporting evidence, and don’t do it to other people either.

 
Flag Post
Originally posted by Vontremort:

You have 114 separate classes all running the same hard-wired static call? Good lord! Right there, your code is so tightly coupled you can’t even change the method without a huge overhaul. If you really want to improve your architecture that right there should be the first thing you fix. I can’t even fathom how that would work. Having an entirely separate class for each game object sounds nuts.

It’s not as bad as you seem to think, but it absolutely could be better—hence why I want to optimize the engine a bit first. Those 114 classes all extend a basic enemy object class which does most of the work (I’d be insane if I didn’t set it up like that!) But since each enemy behaves in its own, unique way with its own, unique list of stats, I can’t think of a more logical way than to give each one its own class. So when I want to change the way yellow slimes behave, I just open up the yellow slime class and it’s all right in front of me. While sure, I could just make a bunch of preset behavior patterns, but unless I make a lot of them, I introduce “mmo enemy syndrome” or “hp, damage, and appearance aside, these enemies are all the same.”

 
Flag Post

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.

Really, this is a case of confusing architecture with direct implementation. What I meant is direct implementation is always easier to change than the architecture. If all of those 114 enemies need to add bullets, that functionality should be decoupled. If decoupled properly, at most you would need to change only a few lines of code. If you realized that you needed to change 144 implementations, then that is an architecture problem, which is going to be hard to change.

It’s not as bad as you seem to think, but it absolutely could be better—hence why I want to optimize the engine a bit first. Those 114 classes all extend a basic enemy object class which does most of the work (I’d be insane if I didn’t set it up like that!) But since each enemy behaves in its own, unique way with its own, unique list of stats, I can’t think of a more logical way than to give each one its own class. So when I want to change the way yellow slimes behave, I just open up the yellow slime class and it’s all right in front of me. While sure, I could just make a bunch of preset behavior patterns, but unless I make a lot of them, I introduce “mmo enemy syndrome” or “hp, damage, and appearance aside, these enemies are all the same.”

No. From what I understand you’re trying to create a bullet hell game correct? You do not need unique classes for every single thing. You need unique behaviors. Not only is that going to be easier to edit and more OO, it would also allow you to mix and match things better. Again, this is architecture.

 
Flag Post
Originally posted by Aesica:

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.

That’s what the Event system is for. It would be pretty slow to have every enemy dispatch an event every time they want to shoot, especially in a bullet hell, but events are ideally suited for those special cases that occur once in a blue moon. Custom events such as a boss calling out “New rule!” when its hitpoints drop below a certain fraction of their max value would handle these cases. Along with the event, the game engine can receive the identity of the boss (as the event’s target) and the fraction of hitpoints, look up the corresponding special effect in a table, and apply it. Or you could leave the boss in charge of the effect by having it dispatch a specific event for the effect you want. So either

dispacthEvent(new BossEvent(BossEvent.BOSSCALL, hp / maxHp));

where BOSSCALL is pretty much the only type of custom event that BossEvent defines, and then the game engine calls specialEffectsLookupTable(customEvent.target, customEvent.hpFraction) to figure out what the appropriate response is,

Or have the boss figure out what it should request from the game
if (hp <= 0) dispatchEvent(new BossEvent(BossEvent.KILLBULLETS));
if (phase == 2 && hp <= phase3HP) dispatchEvent(new BossEvent(BossEvent.REVERSEBACKGROUND));
and so on…

These events happen rarely enough that they will not impact performance, and they preserve encapsulation.

 
Flag Post
Originally posted by Secretmapper:

No. From what I understand you’re trying to create a bullet hell game correct? You do not need unique classes for every single thing. You need unique behaviors. Not only is that going to be easier to edit and more OO, it would also allow you to mix and match things better. Again, this is architecture.

How do you implement unique behaviors without creating new classes? The way I would have done it, I’d have made a base Bullet class with an override-able function called, say, “advance.” When the advance method of the base class is called, the bullet object would move in a straight line based on the angle of the shot. I would then extended the base class for each different type of bullet, thereby creating new classes. Each of these extended classes would have a different way of executing the “advance” method. One bullet would move in a wave of fixed amplitude and wavelength, another would move in a spiral, etc. So basically, I’d be using polymorphism on the “advance” method.

How would you implement unique behaviors without creating unique classes? Will you use something like a select…case statement or nested ifs?

 
Flag Post

You do not need new classes for every new behaviour. For your bullet example, you would need at most 3 classes, maybe at least 7-10 if you want to get very creative, and that even is quite pushing it. I suggest looking at something like Bulletml to see how they do it.

 
Flag Post
Originally posted by Secretmapper:

For your bullet example, you would need at most 3 classes, maybe at least 7-10 if you want to get very creative

All right, so you do need a few new classes… not 114 classes, but more than one class for sure. I understand how setting different properties on instances of the same class can change the behavior of different objects, assuming that the class’s methods take those properties into account. I just wanted to make sure I wasn’t missing out on something important.

 
Flag Post

@Ace_Blue: Yeah, I think events will be the way to go for the seldom-called things that I mentioned, as none of them are called multiple times a second. When I think back on it, I even recall having to make certain private variables/functions in the game container class public to allow the boss to change the background image and speed. (Not something I was thrilled about doing, but I felt it necessary at the time)

@Secretmapper: Reflecting a bit, there were common patterns, despite each enemy being unique: Small slimes would descend downward usually while shooting something, big slimes (and several other things) would sit in place and shoot, several different enemies would bounce around the screen, some would spawn and grow continuously until they (or you) died. Is that what you mean by creating just a few behaviors instead of 114? Sure, each boss would need its own special behavior, but the common enemies…hmm. I’ve always liked seeing other people’s approach to doing things. Thanks, I’m going to play around with that I think.

 
Flag Post
Originally posted by Aesica:

@Ace_Blue: I even recall having to make certain private variables/functions in the game container class public to allow the boss to change the background image and speed.

In my experience, that’s always a sure sign that a ‘child’ class is overstepping its authority, and bossing its parent around. (I’m guilty of doing it as well though, because breaking encapsulation is usually the fastest way to get something working the way I want it too. It’s usually come back to haunt me in the end.)