Alright, back when I was younger I used to really enjoy playing an online game called Spybotics: the Nightfall Incident, and I've always really wanted to do my own version / clone. The game involves virtual hacking sessions called 'databattles' in which the player fights other software using the different commands available to them through their programs, which are visually represented as little tiles on a grid. I've always considered this type of game one of the easier ones for me to create, as collision checking (one of my weak points) is pretty trivial, since it only involves checking if the tile you want to move into is already occupied or not. It's also turn-based, so my code doesn't have to be super-efficient either.
Anyway, around mid-last year I decided to have a go using my preferred language, C++, and using SFML as a library for graphics and related things.
My first approach was a naive one, using the classic, inheritance-heavy approach, and since I didn't really know or care about organisation or architecture my code became a huge mess, and I began to think "surely there is a better way of doing this?!". So somehow I stumbled upon something called entity / component-based architecture, and bought a very good book on game architecture (namely Game Coding Complete: 4th edition). The book made reference to Design Patterns, which I bought as well. However I began to realise that while the methods discussed in GCC 4 were really good and suitable for industry-standard games, it may be a bit 'over-engineering' to go for a fully-fledged actor/component system for such a small and tightly-defined game. By tightly-defined I mean the range of different types of actors wasn't that big; the way I see it, entities can either be Programs, which all have the same types of properties; or Items such as credits, which don't do anything except sit there and perform an action (such as award points) when moved over.
Also, GCC4 seems to be focused on making a more general-purpose engine (in addition to a game using it) rather than an engine specific to a certain game. I only really care about doing the latter, and after reading articles like "Make games, not engines" on the Internet I am convinced this is the right way for me to go. So over the past few months I've been going round in circles, constantly conjuring up a 'better way' to go about designing my game. I'm getting nowhere fast and very frustrated in the process.
Recently I thought I'd go for some flexibility and trust that the component system is indeed the right way to approach my game. I began constructing it this way, for example:
- Programs, Items, etc are just Entities, which store a list of Components. All Entities have a grid position (x, y), a unique ID, a name and a description.
- Programs would have a ProgramComponent and a VisibleComponent, along with either an AIComponent or a PlayerComponent.
- Items would have an ItemComponent, a VisibleComponent, etc.
However the way I was implementing it meant that lots of data was duplicated which shouldn't be. For example, a ProgramComponent contains the Commands (attacks) the program can perform. They have a name, a description, and some way to be executed (via strategy / command pattern, perhaps). So one class of program (called the "Hack") could have a command called "Slice". However if the ProgramComponent stores all of a program's commands, this would mean that every instance of a Hack in one game (there can be multiple instances of one type of program / item) would have a copy of the Slice command when it really doesn't need to since all Hacks behave the same way. Obviously this isn't that much of a problem for this example but it would be worse for programs with lots of commands. It's also mildly annoying anyway since it isn't necessary.
The same applies to entities' names and descriptions. All Hacks are called "Hack" and they all have the same description. Maybe storing references to these (via pointers), rather the concrete strings, in each entity would be better but then where would the actual strings go?
I suppose I could have a global registry for certain properties or something like that but I'm wondering if there is a less convoluted way to solve this problem.
Anyway, my latest idea does away with the components and goes back to inheritance. I have two separate hierarchies, the EntityPrototype hierarchy and that of the Entity itself. Prototypes hold the data that is common to all instances of something (eg a ProgramPrototype would store image data and commands) and differ solely in the values of this data. Entities are the actual playing pieces on the grid and maintain a reference (pointer) back to their associated prototype. Sample code:
shared_ptr<ProgramPrototype> pProtoHack(new ProgramPrototype(PROG_HACK, 2, 4, 5)); //"Hack" is just a type/class of program shared_ptr<ProgramPrototype> pProtoSentinel(new ProgramPrototype(PROG_SENTINEL, 2, 4, 256)); //Same with sentinels pProtoHack->addCommand(Command("Slice", "Deletes 2 sectors from target"))->setName("Hack")->setDescription("Basic attack program"); pProtoSentinel->addCommand(Command("Cut", "Deletes 2 sectors from target"))->setName("Sentinel")->setDescription("Corporate data defender"); shared_ptr<EntityProgram> pHack1((EntityProgram*) (pProtoHack->createInstance(1))); //Number passed to createInstance() is just an ID for the entity shared_ptr<EntityProgram> pSent1((EntityProgram*) (pProtoSentinel->createInstance(2))); pHack1->getImageIndex(); //Because image data is shared, the method retrieves the value from its object's prototype reference
Prototypes are responsible for creating the actual Entities they correspond to. It's almost like the clone() method in the actual Prototype design pattern, but my implementation is modified to share some of the data.
This works currently. However something tells me I'll regret doing things this way at some point, which is why I'm asking: given everything I've said, what would be a good way to approach the design of my entities / game objects without being too general, which seems to be the case in a typical component based architecture? Or should I just plod on with my homegrown prototype-inspired system and let experience be the best teacher?
Also, apologies in advance for any confusion... I can't really explain the mechanics of this game without going into a lot of detail