Another little detail I forgot to mention is the (prototype) logo on top of this Blog. Just a little present from a good friend who has his own business in logo & design since a while:
Last but not least, in case you missed, we gave our engine a name…. Engine22. Not as brilliant as “Source”, but yet I like its simplicity. It doesn’t change the quality of the game, or how Earth orbits around the Sun, but it’s nice to call the beast with a name.
Off topic. Quick drawing by Jesse. Nitpickers as we are, sketches should help the modelers with details like these, rather than just go ahead and poop some polygons. Atmosphere is key baby, so every stupid wooden panel is handmade craftwork. The expected release date for Tower22 is May 2086 BFSM (Before Flying Spaghetti Monster) by the way
Back to the “input & output” story then. Previous time in The Bold & The Beautiful, we made an Input module. To register keypresses, mouse motion, sweat sensors and lightsaber velocity. Yeah, with some hardware knowledge you can do whatever you want there. Measure the player heartbeat, use the room temperature, make your own exotic joysticks, Duckhunt Zappers, dumbbell sensors for your own Dolph Lundgren fitness game, install a Boeing cockpit in your room and so on. The Input module abstracts the physical input to a listing of common controls that can be used in most types of games. And otherwise it's easy to extend.
But the real question is, what to do with it? Unlike earlier (messier) engine attempts, I made a strict difference between Input and Output this time. The Input module isn't aware at all of the game status. It doesn't know if you are controlling a HUD menu, Haiku Robot, or Lara Croft. Neither does it know which buttons are allowed or not. It just registers input, that's it. What to do with it completely depends on "the others"... whatever that is.
Sounds pretty simple, but there is a catch. Where exactly do we code the output? Didn't I say to keep game/entity specific actions apart from the core-engine? You don't have to follow my advice, but personally I don't want to litter Engine22(yeah) entity system with stuff like
- "player spawns 20 blood decals on bullet hit"
- "tanks accelerates forward when FORWARD is pressed"
- "Goku charges up powerlevel to a maximum of 45.000 while bashing the ACTION2 button"
You could try to make a super-entity that can do everything in the world, but that is asking for failure. Abstracting everything makes hard-to-understand and/or lacking code that just doesn’t do what you really want. Instead, like you do in small specific industrial applications, focus on the specific task. More effective, faster, less error-prone, and especially more fun. Finally you feel like you are programming an actual game!
To break up this large piece of text, just some relaxing carpet. A dull screenshot indeed, but carpetting the building has to be done as well. It should be somewhat more spectacular as soon as the carpet layer makes some holes and throws around carpet-tiles...
Right, that means we have to move the specific "game-logic" elsewhere. I'm not 100% done with the design, but I have some ideas... Half a year ago I mentioned Python scripts already. In short, when the engine detects a certain event such as onBulletHit(), onUse() or onSectorLeave(), it can call a Python script for the specific execution. Each entity (a barrel, player, monster, shotgun, …) can have its own script. Since Python scripts are external files, you can do whatever you want here. And also adjust whenever you want without needing Delphi, MS Visual Studio or other tools. Python scripts compile at run time, so you don't have to rebuild the Game project when you just added a "player health = 9999" cheat in the player script. That also means you can screw up the game any time you want :D
This is effective, but it still has some downsides. So far I used Python scripts for rather simple tasks that are only executed when X happens, not every cycle. Updating complex tasks like physics, controls, animations, AI and pathfinding each cycle (more than 30 times per second) might be too much. I have no idea how slow or fast Python really is, but it IS slower than normal compiled code. That's for sure. Maybe updating one entity isn't much of a problem, but how about 10. Or 100? I'm not taking the risk, neither do I buy "That few milliseconds don't matter as long as it works". That's a lazy approach sir.
Asides from speed, Python isn't as flexible than your trusted uncle Delphi. For real complex stuff I still prefer a traditional language (or at least I don't know Python that well). So... what to do now? How about making entity DLL's?
• Each entity can(doesn’t have to) be assigned to a DLL
• DLL does the cyclic update, physics, events, queries from other objects, handling the input, etcetera, etcetera
• DLL gets access to the Engine API so it can call all kinds of things (render something, apply force, get another entity, play sound, and so on).
• Most “simple” objects like a stupid box or chair can all do with the same DLL. So don’t worry, you won’t end-up with thousands of little programs.
Instead of letting the engine fool around with lots of specific actions, let the DLL do it. Yeah, even maintaining a simple "health" value can be different for each entity. Some are immortal, some are sensitive for headshots, others bounce back bullets, others explode when they got hit, etcetera. So, remove "health" and all the possible effects from the core-engine, and let the DLL (or script) do the job call.
The Engine is doing less and less… specific action is moved to the surrounding units, making the Engine more like a “manager”. All rendering functionality is (still) inside though. Even though we could move that to an external unit as well of course.
Engine22 only does what all entities should do when getting updated, hit, spawned, or whatever event there is. The DLL and/or Script tell the specific output by using the API delivered by the engine. API? Yeah, Application Programming Interface. Engine22 has a large list of varying functions that can be called by Python scripts. And also by DLL's now.
In Delphi terms, we just pass an "Interface" type towards the DLL when it asks for it. This interface is just one big listing of method pointers, towards the engine. You don't have to do it that way of course, but it looks nice. Either how, we can call those functions whenever we like. The beauty is that you can drop the choking "keep it universal" way of thinking once you are in your DLL. Sure, using some frameworks helps, but basically you can code whatever you want here. Ah.... it almost feels as good as when I began with programming games 10 years ago. No worries.
Some of the DLL & API functions...
Next time, in the last part, I’ll give some example code to illustrate some common game mechanics. In the meanwhile, eat your vegetables!