I've run into an issue a number of times now. In my mindjail engine, there're several levels of development - I think of there as being four levels, of which I'm concerned with two.
At the lowest level, there's window management. I've shoved this off onto pyglet, a lightweight (their website tells me) GL windowing library for python. Pyglet does some things that I know - in an abstract way - how to do: drawing basic shapes, interfacing with the operating system to draw windows, and keeping track of input.
At the next level up, most of the meat of my engine is present. The main game's state is in a mindjailengine class, with lists of entities, rules on how and when to update and draw, and a basic physics engine. This level is what I think of as low-level game programming, and I chose to develop in python largely 'cause I felt it'd be easiest to code this 'meat' in an easy language. I'm doing the hard thinking here, so I do it how I think best - in python.
Problems really start in the next level - where entities in the game world have behaviors defined. Suppose a missile hits a robot. The previous level of abstraction determined if the missile was currently striking the robot - physics is a universal thing and so it shouldn't happen here*. But missiles explode when they hit things, so the missile should explode - definitely missile-specific behavior.
Our issue is how to separate our code. Presently, it's all close together - all of the missile's behavior is encapsulated in the Missile class in missile.py. But why is this? If we truly think of the behavior of entities in the world as being a totally separate thing then my instincts say they should be in different places in the code.
I did a bit of Lua scripting way back when to make tools in Garry's Mod, and it seems like a scripting language might be the answer. Object management and physics would be handled in python, and then at some point the game would instantiate a Missile object, and in the process would hook in the Missile.lua file to manage how the missile behaves.
But here's my biggest problem: I don't know how to interpret lua, and my game is still under a hundred kilobytes. I don't know how to include a Lua interpreter, which is a stickier subject still - how would I have the Lua scripts adjust things like position and velocity, which are hard-coded into the physics engine? The script/engine interface is more complex than the engine/windowing interface.
This level of abstraction is easy to brush aside when I'm dealing with simple objects, with behaviors as simple as "when I hit something, remove it", but it's going to balloon out horrendously when we get to, say, enemy AI.
A similar problem is presented at the next level, which is the broad-scale game design - the things that make a game Fun. It's not the physics engine, I'll tell you that.
By analogy to object behavior, this would involve having a separate language or interpreter for levels. I was toying with the idea of having levels stored as vector graphics files, with lists of circles drawn at specific locations. I've since thrown that idea mostly out, but the problems remain - if I have a format for my files, I can either have
In the mean time? I'm blocking the game out as best I can all in python. My level format is a text file that gets parsed with a case-switch loop, and my object behaviors are defined in distinct classes. Basically, I'm trying to keep everything separated by sheer force of will, which is okay because I know how everything works.
I've seen this become a major problem, and a major reason for code becoming confusing, in just about every team project I've worked on, and it's a serious argument for having paid attention in software engineering class. This kind of architecture is something to pay attention to, because it means the difference between
At the lowest level, there's window management. I've shoved this off onto pyglet, a lightweight (their website tells me) GL windowing library for python. Pyglet does some things that I know - in an abstract way - how to do: drawing basic shapes, interfacing with the operating system to draw windows, and keeping track of input.
At the next level up, most of the meat of my engine is present. The main game's state is in a mindjailengine class, with lists of entities, rules on how and when to update and draw, and a basic physics engine. This level is what I think of as low-level game programming, and I chose to develop in python largely 'cause I felt it'd be easiest to code this 'meat' in an easy language. I'm doing the hard thinking here, so I do it how I think best - in python.
Problems really start in the next level - where entities in the game world have behaviors defined. Suppose a missile hits a robot. The previous level of abstraction determined if the missile was currently striking the robot - physics is a universal thing and so it shouldn't happen here*. But missiles explode when they hit things, so the missile should explode - definitely missile-specific behavior.
Our issue is how to separate our code. Presently, it's all close together - all of the missile's behavior is encapsulated in the Missile class in missile.py. But why is this? If we truly think of the behavior of entities in the world as being a totally separate thing then my instincts say they should be in different places in the code.
I did a bit of Lua scripting way back when to make tools in Garry's Mod, and it seems like a scripting language might be the answer. Object management and physics would be handled in python, and then at some point the game would instantiate a Missile object, and in the process would hook in the Missile.lua file to manage how the missile behaves.
But here's my biggest problem: I don't know how to interpret lua, and my game is still under a hundred kilobytes. I don't know how to include a Lua interpreter, which is a stickier subject still - how would I have the Lua scripts adjust things like position and velocity, which are hard-coded into the physics engine? The script/engine interface is more complex than the engine/windowing interface.
This level of abstraction is easy to brush aside when I'm dealing with simple objects, with behaviors as simple as "when I hit something, remove it", but it's going to balloon out horrendously when we get to, say, enemy AI.
A similar problem is presented at the next level, which is the broad-scale game design - the things that make a game Fun. It's not the physics engine, I'll tell you that.
By analogy to object behavior, this would involve having a separate language or interpreter for levels. I was toying with the idea of having levels stored as vector graphics files, with lists of circles drawn at specific locations. I've since thrown that idea mostly out, but the problems remain - if I have a format for my files, I can either have
- a hand-grown format (where my level editor will be notepad and my parser will be a loop with a case-switch statement) or
- I can use someone else's format (where I might be able to have a graphical editor and parse by means of a call to FormatParser.ParseFile("level1.lvl")).
In the mean time? I'm blocking the game out as best I can all in python. My level format is a text file that gets parsed with a case-switch loop, and my object behaviors are defined in distinct classes. Basically, I'm trying to keep everything separated by sheer force of will, which is okay because I know how everything works.
I've seen this become a major problem, and a major reason for code becoming confusing, in just about every team project I've worked on, and it's a serious argument for having paid attention in software engineering class. This kind of architecture is something to pay attention to, because it means the difference between
- a game with two enemy types because they're such a pain to code that only one person can make them work and
- a game where it's easy to add new enemies and levels and weapons, because it just means adding a few lines to a clean file called 'enemies.py' or 'weapons.py'
No comments:
Post a Comment