2011/02/03 (Villainmad): Object-Disoriented Design
So, with a more sensible solution to last week's problem out of the way, let's talk about objects in the game-world.
Preamble: I've decided not to obsess myself with making the game INFINITELY FLEXIBLE, but for certain things, it's actually easier to code in flexibility than to create different cases in the C# end of things. (Where it is less convenient, however, I will hardcode stuff in. For instance, the player is going to be a traditional shmup-player whom you move around with the arrow-keys, and the other buttons will be Esc, Z, X, C, Left-Shift, and Left-Ctrl1 by default. And I'll have to figure out an options-page with which you can change key-mappings ...)
Now: without wasting space and time going into too much technical detail: every object-type will have its own drawing-layer. The game-creator will define every type of game-object (i.e. enemies, bullets, items), and which ones they'll do collision-detection for, and what collision will entail (i.e. "if a bullet hits a player, the bullet disappears and the player takes damage according to the bullet's properties.").2
I will be using a variation on the linked-list method described in this thread on the XNA forum for handling all the game objects and their draw-order. I will be using a List instead of an Array to store the objects themselves, and add new bullets to the end and "if the last bullet in the list is 'deleted', remove it until the last one in the list isn't deleted anymore" as needed, in order to bypass that "capacity" deal. The game-entity structs themselves will contain:
- The creation-frame (int)
- The position (Vector2)
- The velocity (Vector2)
- A pointer to a data-table which contains data for that particular game-object (in the "LuaTable" format included by LuaInterface).3
And, as I said in the comment I mentioned, you will keep track of them using an object-ID struct, containing the creation-frame and its position in the list (again, the reason for this is so that, even if an object inherits a position in the list from a previously-deleted one, it can't inherit the creation-time), as well as what layer it goes in.
Now, the data-table (it can be an object-instance, but it doesn't have to be) will have some basic fields like "texture" and "health" and whatnot. However! You will also be able to optionally create functions on this table named init() (called once before it does anything else), draw() (called every frame and replacing "just show the image"), update() (called every frame before doing the drawing), and its own collision() (or proximity) function (called every frame, once for every extant object it can collide with, overriding the one in the data-table). These functions will each be passed the data in the object-ID structs (and that of the other object in the Proximity function), and will have getters and setters for the values in the game-entity structs.
This will be presumably enough that you can do pretty much anything with 'em. So much for not obsessing myself with flexibility ...4
1I have no idea what I'm going to do with C and Left-Ctrl. But someone (who wants to mod things) might!
2Technically, what's actually happening is, the so-called "collision" function would be better called a "proximity" function: rather than only firing if a bullet (or other "colliding-with-player object") is a certain distance away, it always fires, and the first thing the player-to-bullet collision does is, "If it's too far away to even graze, do nothing." I figure it doesn't matter whether it's the Lua-function or the C# that checks how close they are; I mean, in the grand scheme of things, what difference does it make?
3For the record: all references to Lua tables (including the LuaTable type in C#) are just pointers. If foo is a table, and you do "bar = foo" in Lua, bar isn't a duplicate of foo, it is foo by another name, so to speak. If you subsequently do "LuaTable baz = lua.GetTable("foo")" in the C#, anything you do to baz will also happen to both foo and bar.
4Technically, if I wanted to be less flexible, I could just have the C# hardcode the number of layers and their collision-relations. But that would just be stupid.