A few posts back I was writing about things that I’ll change for the next game that I make. One of those was the increased use of structs, especially if there is a lot of repeated code. Today and yesterday I spent my time creating the new project of Dangerous Games. In doing so, I decided that I was going to create a struct called CharacterBase, which stored a bunch of variables that every character (PC and NPC) must have. CharacterBase looks like:
float xVel, yVel;
bool isAlv, isSpwn;
Since WordPress always makes things very awkward to indent, I fully expect this to look weird. Anyway, I realized that all characters share velocity, collision box, rendering box, angle facing, health, and flags for being alive and being spawned. Not every character needs all of this, but even the ones that don’t need 90% of this.
Putting this all in one struct has a few benefits. The first is that I can make a change to the CharacterBase struct, and I don’t have to make that exact same change to all the NPC’s. Secondly, it saves a bunch of vertical space to give each NPC an array of these instead of each item individually. Thirdly, if I wanted to, I could create one constructor-like function, and just pass in this struct for each NPC and all of this information would be initialized to default values. Fourthly, it makes the code easier to read, since we can easily understand something that every character has, without having it burden the individual structs. Fifthly, somewhat on the same point, we can easily look at the individual character structs to see what is unique about this character.
As an example of the second, fourth and fifth points, look at our before and after for our turret class (now a struct).
double xPos, yPos;
double xVel, yVel;
double angle; //used to follow the player. I’ll eventually implement a max turning speed.
Turrets(int nmTurs, gs dt);
Turrets(int nmTurs, gs dt);
This is so much easier to read. I noticed that sometimes I had the same functionality with a slightly different variable name in a lot of spots in my code. No more with the character structs.
To expand on my third point, I don’t have to limit myself to constructors to reap massive benefits from the standardized way of doing things here. Most, possibly all, of the interaction between characters has to do with things in the CharacterBase. If I want to do something such as, say, collision detection, all I have to do is look through the CharacterBase’s for all the different enemies on screen, and the player character. I may be solving collisions differently for each enemy type, but this is a significant step forward for useability.
One major downside though is the downside I always get from putting structs in structs, massive waste of horizontal space when using things. As an example, this is an actual line of code from the re-written PC movement function:
xV *= sqrt(maxDisSqrd/(xV*xV + yV*yV));
That doesn’t sound so bad, but it’s because I made two temporary floats xV and yV, representing velocity. I had to do this because the original line read as:
pPC->bs.xVel *= sqrt(maxDisSqrd/pPC->bs.xVel*pPC->bs.xVel +pPC->bs.yVel*pPC->bs.xVel));
Which is a nearly unreadable mess. If it was just this one line I would have dealt with it, but I could use the temporary floats multiple times to save on space, so it was a no brainer. This has a real cost, since using temporary variables makes the program more confusing (although less confusing overall in this case, but still bad to have to do it), and is a great way to introduce bugs into the program. Even worse, in this case it’s likely that any bugs would compile properly, just not give me the right behaviour.
So there we have it, some of this can be lessened by just passing in the relevant structs, which would have saved me the pPC-> every time, but that isn’t always an option, since I may very well need the additional variables to modify behaviour at some point. After all, they exist for a reason.
Sometimes things just align, and I happened to watch Jonathan Blow’s excellent lecture on data-oriented programming and a new programming language. It’s the type of thing that is absolutely directly relevant to my problem here, and is the first time I’ve ever been excited by a programming language, even though I care little about performance right now, and am mostly interested in a language that’s less “sticky”, when I try to change things.