Advice on game architecture/design patterns

user127817
  • Advice on game architecture/design patterns user127817

    I've been working on a 2d RPG for awhile now, and I've come to realize I've made some bad design decisions. Theres a few things in particular that are causing me problems, so I was wondering what sort of designs other people used to overcome them, or would use.

    For a little background, I started working on it in my free time last summer. I was initially making the game in C#, but about 3 months ago, decided to switch to C++. I wanted to get a good handle on C++ since it's been awhile since I used it heavily, and figured an interesting project like this would be a good motivator. I've been using the boost library extensively and have been using SFML for graphics and FMOD for audio.

    I have a fair bit of code written, but am considering scrapping it and starting over.

    Here's the major areas of concern I have and wanted to get some opinions on the proper way others have solved them or would solve them.

    1. Cyclical Dependencies When I was doing the game in C#, I didn't really have to worry about this since it isn't an issue there. Moving to C++, this has become a fairly major problem and made me think I may have designed things incorrectly. I can't really imagine how to decouple my classes and still have them do what I want. Here's a few examples of a dependency chain:

    I have a status effect class. The class has a number of methods (Apply/Unapply, Tick, etc.) to apply it's effects against a character. For instance,

    virtual void TickCharacter(Character::BaseCharacter* character, Battles::BattleField *field, int ticks = 1);
    

    This functions would be called everytime the character inflicted with the status effect takes a turn. It'd be use to implement effects such as Regen, Poison, etc. However, it also introduces dependencies on the BaseCharacter class and the BattleField class. Naturally, the BaseCharacter class needs to keep track of what status effects are currently active on them so that's a cyclical dependency. Battlefield needs to keep track of the fighting parties, and the party class has a list of BaseCharacters introducing another cyclical dependency.

    2 - Events

    In C# I made extensive use of delegates to hook into events on characters, battle fields etc. (for an example, there was a delegate for when the character's health change, when a stat changed, when a status effect was added/removed, etc.) and the battlefield/graphical components would hook into those delegates to enforce their effects. In C++, I did something similar. Obviously there's no direct equivalent to C# delegates, so instead I created something like this:

    typedef boost::function<void(BaseCharacter*, int oldvalue, int newvalue)> StatChangeFunction;
    

    and in my character class

    std::map<std::string, StatChangeFunction> StatChangeEventHandlers;
    

    whenever the character's stat changed, I'd iterate and call every StatChangeFunction on the map. While it works, I'm worried this is a bad approach to doing things.

    3 - Graphics

    This is the big thing. It isn't related to the graphics library I'm using, but is more of a conceptual thing. In C#, I coupled graphics in with alot of my classes which i know is a terrible idea. Wanting to do it decoupled this time I tried a different approach.

    In order to implement my graphics, I was imagining everything graphics related in the game as a series of screens. I.e. there's a title screen, a character status screen, a map screen, an inventory screen, a battle screen, a battle GUI screen, and basically I could stack these screens on top of each other as necessary to create the game graphics. Whatever the active screen is owns the game input.

    I designed a screen manager that would push and pop screens based on user input.

    For instance, if you were on a map screen (an input handler/visualizer for a Tile Map) and pressed the start button, it'd issue a call to screen manager to push a Main Menu screen over the map screen and mark the map screen to not be drawn/updated. The player would navigate around the menu, which would issue more commands to the screen manager as appropriate to push new screens onto the screen stack, then pop them as the user changes screens/cancels. Finally when the player exits the main menu, I'd pop it off and get back to the map screen, remark it to be drawn/updated and go from there.

    Battle screens would be more complex. I'd have a screen to act as the background, a screen to visualize each party in the battle, and a screen to visualize the UI for the battle. The UI would hook into the character events and use those to determine when to update/redraw the UI components. Finally, every attack that has an available animation script would call an additional layer to animate itself before popping off the screen stack. In this case, every layer is consistently marked as drawable and updatable and I get a stack of screens handling my battle graphics.

    While I haven't been able to get the screen manager to work perfectly yet, I think I can with some time. My question about it is, is this a worthwhile approach at all? If it's a bad design I want to know now before I invest too much more time making all the screens I'm going to need. How do you build up the graphics for your game?

  • Overall I would not say anything you listed should cause you to scrap the system and start over. This is something every programmer wants to do about 50-75% of the way through any project they are working on, but it leads to a never ending cycle of development and never finishing anything. So, to that end, some feed back on each section.

    1. This can be a problem but is usually more of an annoyance than anything else. Are you using the #pragma once or #ifndef MY_HEADER_FILE_H #define MY_HEADER_FILE_H ... #endif at the top or surrounding your .h files respectively? This way the .h file only exists once within each scope? If you are, my recommendation then becomes removing all #include statements and compiling, adding in the ones as needed to compile the game again.

    2. I am a fan of these types of systems and see nothing wrong with it. What is an Event in C# is commonly replaced with an Event System or Messaging System (can search the questions here for those things to find more information). The key here is to keep these to a minimum when things Need to happen, which it already sounds like you are doing so should be no to minimal worries here.

    3. This also seems on the right track to me and is what I do for my own engines, both personally and professionally. This makes the menu system into a state system that either has the root menu (before the game starts) or the player HUD as the 'root' screen displayed, depending on how you set it up.

    So to sum up, I see nothing restart worthy in what you are running into. You may want a more formal Event system replacement down the road but that will come in time. Cyclic includes is a hurdle all C/C++ programmers constantly have to jump through, and working to decouple the graphics all seem like logical 'next steps'.

    Hope this helps!

  • Your cyclical dependencies shouldn't be a problem as long as you're forward declaring the classes where you can in the header files and actually #including them in the .cpp (or whatever) files.

    For the event system, two suggestions:

    1) If you want to keep the pattern you're using now, consider switching to a boost::unordered_map instead of std::map. Mapping with strings as keys is slow, especially since .NET does some nice things under the hood to help speed things up. Using unordered_map hashes the strings so comparisons are generally faster.

    2) Consider switching to something more powerful like boost::signals. If you do that, you can do nice things like make your game objects trackable by deriving from boost::signals::trackable, and let the destructor take care of cleaning up everything instead of having to manually unregister from the event system. You can also have multiple signals pointing to each slot (or vice versa, I don't remember the exact nomenclature) so it's very similar to doing += on a delegate in C#. The biggest problem with boost::signals is that it has to be compiled, it's not just headers, so depending on your platform it might be a pain to get up and running.

Tags
c++ architecture rpg
Related questions and answers
  • from it. As an added touch i have made it so after you collide while traveling down the randomly generated map (or rather as the walls move uppward while your character stays put) the X chars you've... in the main function * not Finally.. but i believe that te numb_coll problem has something to do with the time and framrate. When running full speed i quickly die upon entering a wall as numb_coll...Alright so i'm making a vertical side scroller where you are an '8' character traveling downward while avoiding my randomly generated walls (the "generation" function) on the left and right sides

  • that make really hard to work with when coding some functions that use them. I was thinking of making ie. SimpleMesh and HierarchyMesh objects, which will also require that the renderer can deal with different types of objects in the same scene. I was also thinking about making a MeshNode class and then make a Mesh object that contains them, but then I have some conflict on where to store some data... shader in every node. Other option I was thinking was making some helper functions to deal with the simpler cases, which would set some default parameters and would ask only the most basic ones

  • ) is therefore highly wasteful. Then again, making each entity state a singleton hardly seems appropriate. What do you suggest I do? (The same can be said about game states, so whatever the solution...This is the first time I'm trying to make a 2D game, so I'm having quite a few difficulties in getting things right. Right now I'm trying to figure out exactly how the entity state machine should... changed, then it (the representation) starts having an internal state. I would much rather have it stateless so that I require only one instance of every representation (just as before). Edit

  • code in them... Right now for testing purposes, I just have the main loop call Level1 level1; and use the functions, but when I run the game I get a segmentation fault. This is the first time I've tried writing inherited classes, so I know I'm doing something wrong, but I can't seem to figure out what exactly. ... that'll have the inherited level classes pushed onto it...This is what my code looks like at the moment, I've tried various things and get the same result (segmentation fault). //level.h class Level

  • different objects in my game: plane, obstacle, player, bullet and I designed them like this: class Player : public GlObject{ private: std::string name; public: Player(); Bullet fire() const; //this method is unique to the class player void generate_mesh(); } Now in the game engine I want to have a general object list where I can check for example for collision, move objects, and so on, but I want also that the game engine will take the user commands to control the player... Is this a good Idea? class GameEngine{ private: std::vector<GlObject*> objects; //an array

  • Choosing an Audio API Aidan Knight

    library and stick with it. I switched physics engines 3 times which caused quite a bit of wasted time, so I would like to be set when I pick an Audio lib. I will be falling into the "indie" section as far..., features seem generic. Pretty much coming down to a battle between this and BASS. I have heard good and bad things. The other libraries such as OpenAL, PortAudio, Audiere, etc. were considered, but I am... months ago on par with FMOD/BASS/etc that were fairly new. No matter how hard I look now, I cannot find them. Hopefully someone here knows what they might be called. Anyways, basically just looking

  • I'm writing a shooter (like 1942, classic 2D graphics) and I'd like to use a component based approch. So far I thought about the following design: Each game element (airship, projectile, powerup... components and that would require searching each other component's list at each step. Which approch do you think is better? is boost::fusion map suited to be used in that way? ... components. A powerup has the Sprite, Position, BoundingBox. And so on. The main loop manages the game "physics", i.e. how the components interact each other: foreach(entity (let it be entity1

  • I'm writing a game engine which is going very fine. However, I'm now posed with handling textures. My Engine is in 2D, for simplicity reasons mostly to get a good idea of how to work with OpenGL. I do this in C++, and I have a hierarchical set-up when it comes to classes. There's a base class and some other classes derive from that. So now I'm onto the part where I want to load up some textures... have to use glGenTextures to allocate a texture and that I then swap betwe--.. I actually have no clue. What's a good way to keep track of all the textures you loaded into the memory and switch

  • GameSubsystems) can implement registerComponent(Component*). pro. Components and GameSubystems know nothing about each other. con. In C++ it would look like ugly and slow typeid-switch... Components. 3: Component registers itself in GameSubsystem(s). We know at compile-time that there is a GameSubsystemRenderer, so let's ComponentImageRender will call something like... a decision which Components to register (and how to organize them). For example, GameSubsystemRender can register Renderable Components. pro. Components know nothing about how they are used. Low

Data information