6

I'm trying to learn how to produce quality object-oriented code and have been studying concepts like SOLID. I'm currently working on an entity-component-process system for a small game engine.

Currently, I have it implemented as such:

  • There is a ScreenStack which contains a stack of Screens
  • Each Screen has an EntityManager and ProcessManager.
  • The ProcessManager updates all Processes given entities from the EntityManager.
  • A Process handles all game logic, so it needs to be able to use ScreenStack to possibly push and pop screens. It can also create, remove, and change entities, so it needs the EntityManager from Screen. Basically a Process needs to know everything about the game since it affects so much of it, but it feels wrong.

How do I go about implementing this better? It seems like everything has a clear dependency hierarchy until you get to a process, where it gets thrown out the window.

There also seems to be tight coupling when I would want to push a new screen. Say, for example, I have a process in a MainMenu screen that checks for menu choice. If "New Game" is clicked, I need to push a new screen, which gets created at that moment. I've read that I shouldn't randomly throw in new which this seems to be doing.

Shane
  • 175
  • 4
  • You mentioned your objects/classes but you didn't mention any interfaces. Are you following the D in SOLID? – david.pfx Sep 04 '14 at 03:04
  • Instead of letting a Process *do* everything, you can let it emit *a list of changes it wants to see done*. Pushing the side effects out to the "top level" of the code has a lot of benefits - now you can simulate game states and run unit tests on them without firing up the window manager, loading textures and playing sounds. – Doval Nov 21 '14 at 22:08

3 Answers3

2

I would suggest looking into "Tell Don't Ask" principle. Martin Fowler gives a good introduction here

The common implementation usually is based on messaging/notifications between the classes. Note, TDA is a "pure OOP" that object oriented languages are designed for. Unlike the most common mixed mode of OO+functional code together.

Another advice is to work on separation of queries from updates (do not allow code in same methods or even classes to request data and act on it) - that removes a lot of accidental complexity and greatly improves SRP.

Paul
  • 394
  • 2
  • 8
0

A process doesn't need to know everything about the game, but it might need to know about what the game does. This is the basic difference between classes and interfaces. (Part of the "D" in solid.)

Imagine all of your objects as separate and completely unrelated. Then, imagine a single connection from each of those to a service that provides interface instances. Each link between your classes can be broken and replaced with a set of behaviors (called an interface). Call something like GetInstance(...) to get an existing interface or create a new instance of one. The consuming object doesn't care which, where, or when the instance was created -- but it does know how to use it. (If you have looked into Dependency Injection, this might be starting to sound familiar.)

Back to reality now. While separating objects' dependencies by using Interfaces is a generally good idea, you don't need to rework everything you already have. Just refactor what is difficult or not working properly, and keep moving forward.

John Fisher
  • 1,795
  • 10
  • 12
  • I didn't explicitly mention interfaces but I am using them to that end. I'm curious how I would go about actually feeding these implementations down to a process. Should screen have a reference to its containing stack to give to new processes even though the screen never actually does anything with it besides feeding it down to processes? – Shane Sep 04 '14 at 07:16
  • Without fully understanding your structure, it's difficult to answer how the classes should relate. However, it sounds like you've got a circular reference/dependency arrangement. You *definitely* want to break that somehow. – John Fisher Sep 04 '14 at 18:29
0

I suppose you are trying to make the game engine Process-driven. I.e. Process will decide what should happen it the game and change game's state. I like the idea, but I was never able to apply it to my game (I've finished only one).

The core of the problem was that my game was not truly process-driven. The inputs came from the frontend (Screen or ScreenStack in your case) obviously, so I had to sacrifice process-driven architecture for a layered one: 'frontend' uses 'backend'. Backend contains most of the game logic (processes and entities in your case), but the frontend is the driver. Backend cannot push screens. Backend does not know anything about frontend. Backend is only a slave of the frontend. That's what I ended up with. Maybe your game is similar.

Maros
  • 61
  • 2