We currently have the problem that our main class GameController is being pulled into every backend file in our game. We're wondering what are common solutions to this problem.
Here's a bit more about the game architecture. The game is a board game, so since ~90-95% of the time there isn't anything happening, the game is set up more like a rest API. It waits for a user prompt, when received, the msg is distributed to the respective components of the game and the proper logic is executed. No large update loops, just executes logic when prompted.
The problem is that as this msg cascades through the system, GameController acts more like a relay point between the systems. It's how the nodes communicate to each other so that all game components are updated properly. The problem is that it's created this system where all new/old classes contain a pointer to parentGame, so GameController is everywhere.
Are there any simple architectural solutions to avoid having every class contain a pointer to parentGame? Is this necessarily a bad thing?
Some example code:
class GameController {
bank: Bank
action: Action
...
}
class Bank {
parentGame: GameController
constructor(game: GameController) {
this.parentGame = game
}
}
class Action {
parentGame: GameController
constructor(game: GameController) {
this.parentGame = game
}
}
I don't believe it is necessarily a bad thing, but you might be able to clean it up a bit by wrapping it in some kind of eventing mechanism in the middle - in other words, pub/sub might give you some of the decoupling that you want.
It doesn't have to be anything that communicates via an external messaging service - that just introduces unnecessary overhead. The Observer Pattern comes to mind for me.
Related
I want to learn how to create good object-oriented (OO) design practice for collision between two objects situation in game development.
Let's say I have a SpaceShip class and a Meteor class. When Meteor collide with the SpaceShip, the SpaceShip will be destroyed.
The question:
What class should I put the method to check if there is collision between meteor and spaceship as well as the collision resolution method (destroy the spaceship)? Is it at SpaceShip class or Meteor class? Or maybe I should put at another class, ie. GameArea or GameController class?
Note: for the sake of simplicity, assume the Meteor and SpaceShip is in form of image resource. I'm used to use Java language, but other language is okay too.
It's more natural to think that collision detection is a responsibility which does not belong to Spaceship or Meteor classes. Especially when this gets complicated with multiple collision possibilities in different directions. If you put this logic in both these classes they will need to have references to lots of other objects that are around them which wouldn't be appropriate.
You could have this on a separate class such as CollisionDetector which keeps track of coordinates of all objects in game space and detect collisions. Collision prevention also appears to be a separate responsibility that should be in a different class in my opinion. You could have a separate class CollisionResolver for this. Depending on the requirements, CollisionDetector could talk to CollisionResolver.
CollisionResolver may need to be able to talk to Spaceships, for purposes such as advising them to change direction, or to command firing missiles towards the Meteor.
CollisionDetector and CollisionResolver could sit within the GameSpace/*GameController*. etc..
This would promote Single Responsibility Principle so each component would be doing only one focussed task.
Collision detection, in my opinion, is not part of an object... it should be defined as something else - some physics manager, etc. That way your objects will be independent on the collision algorithms.
Another thing is that in games usually object consists of several layers (components): Graphics Layer, Physics Layer, Logic Layer.
That way physics manager manages only physics component of given objects.
class GameObject
{
RenderComponent m_renderComponent;
LogicComponent m_aiComponent;
PhysicsComponent m_physicsComponent;
};
Well, I usually create a (sometimes generic) GameObject class or interface that has a collides method. For example:
template< typename T = int > class GameObject
{
public:
bool collides(const GameObject& obj);
};
// usage
GameObject<int> my_obj, your_obj;
if(my_obj.collides(your_obj)) { ... };
Another thing I sometimes (but rarely) do is to create a separate GamePhysics class:
template< typename T > class GamePhysics
{
public:
/* you may make this static or the class a singleton */
void detect_collision(const T& obj, const T& obj2);
};
In Java (or any other OO language) I would place a CollisionDetected callback/event in the common ancestor class of all moving objects in your game.
This is a simplified description of a game:
In a game, there's usually a game-loop. A game-loop is like a while(true) loop that runs continuously (kind of like the main UI thread of an application) and at every step checks what has changed with the objects, what should be updated and what events should be called (and more...).
For responsiveness, this loop should cycle many times a second.
Inside this loop, a Physics Engine object should continuously update it's status. This would be an instance object of an independent class. It's this engine that should detect collisions between objects and call the CollisionDetected event on all objects that have collided.
It's an idea, not the definitive solution...
I have a quick question about the organization of a particular OOP problem.
Say I have a Terrain class, full of Tiles. There are multiple derivatives of class Tile, namely Door. The Door class has a method called open() which opens the door, and close() which closes the door. This makes perfect sense until both of these methods need to check for something in the way before opening and/or closing. How do I make a Door check for an object in the way without it knowing about its parent?
A simple solution would be to check for something in the way before calling open(), but if there was a different kind of door that needed to be check in a different shape, it creates clutter on the higher level.
It seems like this would have a simple answer, but it also seems like I run into this problem more often than not.
One answer is that Doors should know how to open and close themselves and know if they are blocked. If Door is a class, then both the state (is_open, is_blocked) and the behavior (open_the_door, close_the_door) should reside in the Door class. Encapsulation is a fundamental principle of the object-oriented paradigm.
But the real-world answer is usually more subtle. Can you provide some background on the application and what it needs to accomplish? There are clean, simple solutions that will work well for toy applications, but bigger apps are going to need something more sophisticated.
How to handle door is_blocked presents some design issues. There is no one right design, but there are good design and bad designs. Separating the good ideas from the bad ideas depends on more than just design principles-- it depends on the context of the problem.
If I had to take a guess, I'd guess that your application is a game. Maybe the tiles represent the area of the game board or map. You have identified that many different objects might have to interact and that it would be mess if they all referenced each other directly.
Games often have a master object called "Game" or "Board" or "Map". Let the master object hold the collection of things in the Tile hierarchy (tiles, doors, etc).
Let the master object also hold the collection of things that can block doors or otherwise interact with tiles and doors.
Now create a method named update() on the Tile class that accepts an object as a parameter.
And create a boolean attribute for the Door class called "blocked".
The update method for the Door might do something like this:
Door::update(BlockingObject object) {
if(object.location == this.location)
blocked = true
}
The method on the superclass of door might do nothing. Like this:Tile::update(BlockingObject obj) {
//tiles cannot be blocked
}
Now, inside the game loop, include a step where all the doors are set to blocked = false.
The create some loops ask all of the tiles to check if they are blocked. It might look something like this in pseudo code:
For each tile {
For each blocking object {
tile.update(object)
}
}
This is a naive, but straight forward design that holds true to the OO paradigm.
The design gives tiles/doors and objects a chance to interact once per turn, without forcing them to hold references to one another.
The design will work fine for a few hundred tiles and objects, but it would become very slow for thousands of tiles.
Is it a good design?
The answer depends on the needs of the application.
I try to realize a little game project to dive deeper into OO programming (winforms c++/cli).
I already started coding but now I´d like to make a re-design.
For the beginning the game should consist of four parts like game-engine, user interface, highscore and playground. Heres a little (non-UML-conform) class diagramm to visualize my purposes
Would this be the right way?
In my eyes the game engine is responsible to control the game sequences (state machine?) and exchanges information betweens all other classes.
I appreciate any help!
EDIT:
so it´s a really simple game, no big deal! here´s a link of what I made by now:
http://www.file-upload.net/download-2595287/conways_project.exe.html
(no virus :) but I guess you need .NET framwork to get it work)
Unfortunately, your current design sucks :)
I won't say what I will suggest is actually the best solution available, because in game design there is generally "no best" solution, but still I think it would make you think appropriately.
Larger UML here.
alt text http://yuml.me/1924128b
Let's say you have your basic class Game. It's something abstract class, that wraps all your game logics and works as a sort of Swiss knife.
You should create two another classes - UI and State (which, obviously, encapsulate game UI operations and store current game state). Let your Game class hold UI and State instances.
Now, your Game class should have basic methods to control your game. They could be plain render(...) and update(...) methods and this part is actually a bit tricky. If your game is real-time, you would have to update your state every Y milliseconds, so your update(...) should be called in a loop.
If your game isn't actually real-time, your updates should happen only when user does something or you actually know that you need to change something. You could implement a message queue here and update(...) call would simply flush all those messages.
Now, the render(...) method. Create some class and call it Backend - let this class encapsulate all your drawing possibilities. There is one really cool thing here - you could let your Backend be an abstract superclass and create some concrete backends, which derive from Backend. And that would actually give you an opportunity to switch your Backends with simple code manipulations.
After that, you should pass your Backend instance to your render(...) method, which would do appropriate drawing and it's logic could be written the following way:
foreach (const Object& object, game_state) {
object->render(backend); // Or something like that
}
The last thing to mention, your game state. You could have a plain structure to hold all your current objects, score, etc, etc. Let every object access that GameState structure and everything will be fine.
Actually, there are many things to think about, if you wish to, I could write more about this game design approach and share some tricks :)
Your 'Game Engine' would probably be considered more of a 'Math Library.' You might want to insert another object in between 'Game' and the other Server Classes that 'Delegates' the requirements of 'Game' to the Server Classes and call that 'Game Engine'.
Also maybe 'High Score' and 'Playground' could be combined into a Class which represents 'Game State' and port that directly to 'Game.' 'Playground' could be a Server Class which encapsulates any code to do the actual presenting of said background where this would usually represent a 'Rendering Class.'
IMHO
Imagine I have a class that represents a simple washing machine. It can perform following operations in the following order: turn on -> wash -> centrifuge -> turn off. I see two basic alternatives:
I can have a class WashingMachine with methods turnOn(), wash(int minutes), centrifuge(int revs), turnOff(). The problem with this is that the interface says nothing about the correct order of operations. I can at best throw InvalidOprationException if the client tries to centrifuge before machine was turned on. I can also use a separete Program class that will pass centrifuge revs and wash minutes to the WashingMachine and will simplify these methods.
I can let the class itself take care of correct transitions and have the single method nextOperation(). The problem with this on the other hand, is that the semantics is poor. Client will not know what will happen when he calls the nextOperation(). Imagine you implement the centrifuge button’s click event so it calls nextOperation(). User presses the centrifuge button after machine was turned on and ups! machine starts to wash. I will probably need a few properties on my class to parameterize operations, or maybe a separate Program class with washLength and centrifugeRevs fields, but that is not really the problem.
Which alternative is better? Or maybe there are some other, better alternatives that I missed to describe?
I'd have a 'high level' State Machine class which controls the entry/running/exit of each state (where states could be things like 'filling', 'washing', 'rinse', 'emptying', 'spin dry', etc)
Draw up a State Transition Diagram of all the states you need, including (for each state)
what requirements there are before you enter the state (entry conditions)
what needs to happen when you enter the state (entry actions)
what happens during the state (the task itself)
what requirements there are before you can leave the state (exit conditions)
what happens when you exit the state (exit actions)
You may or may not need the entry/exit conditions (e.g. you can force the conditions with an entry/exit action in some cases). For safety reasons though, some conditions can be good (e.g. exiting from a 'standby' state or entry into a 'dangerous' state like spin dry)
You also create Transitions, which define the links between states. A transition has
a 'from' state
a 'to' state
transition conditions (can the transition happen?
transition actions (what needs to happen when you transition)
Again, you may not need all of these, and many transitions will have only the 'from' and 'to' states specified.
In both cases, try to keep each State and Transition as simple as it needs to be (try to put the conditions/actions where they make the most sense, obviously there's potential double-up of these to be defined in a State and a Transition because of the generic design)
It should be pretty obvious at this point that you can make a fairly generic State class which includes abstract/overloadable functions for all of these things, and likewise for the Transition class. The State Machine class can call each of these member functions as required, based on the transitions requested of it.
If you make it especially generic, then the States and Transitions can be registered with the State Machine at construction time, or you might just code the State Machine to contain them all.
You can then request transitions, either from within states (i.e. a particular state can know when it has ended, and know which state to go to next) or you could have an external class which controls the state transitions (each state is then very simple, purely taking care of its own actions, and the external class decides the order and timing of transitions).
In my experience with these things, it's a good idea to separate the high level logic of deliberate order/timing of each action and the low level logic of reaction to some hardware event (e.g. transition out of the 'filling' state when the water level is reached).
It's a really generic design though, and you can achieve exactly the same functionality a bunch of different ways -- there's rarely a single right way of doing things...
I think that turnOn(), wash(), centerfuge() etc. should be private/protected methods. The public interface should be doTheWash(WashMode mode). The washing machine itself knows the modes it supports and how to make them work, the user of the washing machine need not get involved with the order or duration of operations. It is reasonable to expect the author of the washing machine class to call the private methods in a sensible order.
Most western washing machines use a timer to move from cycle to cycle. This timer can be thought of as a state machine of sorts. However, it's important to realize that a wasching machine runs itself, not the user. The user sets the initial mode, and then it goes on about its business.
So internally, you may have Wash, Rinse, Spin private functions, the actual interface would be SetCycle() and Start() and Stop(). You may also have some additional properties, like Water Level, Agitation Speed, Water Temperature, etc...
Start causes the time to advance, which after a period of time enters the next state, until finally it is complete.
Every washing machine has a controller and a program. For older and simple machines, program and controller are integrated into a rather complicated knob, modern and more expensive machines have a computer.
In either case, the machine has additional subsystems and the controller notifies the subsystems to perform some action, like lock the door, heat water until 40°C or spin the drum.
The Controller itself knows the sequence, which is pretty linear and timer based for old machines or complex for modern systems which vary the sequence based on sensor data. But in either case it executes a series of commands which may notify sensors and actors.
If you look at the washing system from this perspective, you may want to make use of the Command pattern inside the controller to model the washing program and of the Observer pattern for notifying the subsystems (Like: The door switch listens to the controller for a signal to lock the door).
The first is exactly what I'd do. wash and centrifuge would check the flag that tracks if the machine is on and throw an exception if it's not, but otherwise there is no mandatory order of operations; you could call centrifuge before wash if you really felt the need
Erm, a little weird but here goes;
I'd be looking at even delegates. So for a particular wash cycle type, heave, light, suddsy, economic etc I'd have say an interface for each.
Then, with the use of generics, I'd create the appropriate wash type I want.
The wash type would then have a wash event which delegates, in order, the cycles to perform.
The washing machine should know how to properly run a load. Perhaps before washing a load, certain configuration items are expected to be set (with defaults, if unset), like what type of load (lights vs darks) or size (small, medium, large). The user (another class) should know how to properly configure a load to run, but for washing a load, the washing machine should only need to expose one method, something like washLoad. Internally it would manage what needs to be called when to wash a load of laundry.
Alternatively, you could still expose public functions for turning the washer on and off, then if washLoad were called when the washer was off, it would be appropriate to throw an exception. Additionally, in this scenario, I would probably make the settings for the washer set via a single method setLoadOptions that would take another class the would be something like LoadOptions and defined whatever characteristics you wanted configurable. I would have this method also throw an exception if the washer was not on.
On my washing machine you have access to two knobs. I'm a little confused as to what the limitations are in your case.
Load size (Small, Medium, Large)
Cycle knob (Perm Press, Knits & Delicates, Regular)
Each cycle contains different "Phases" at which it can be activated at
When you "Activate" a cycle (by turning the knob), the machine will begin running if you turn it to the middle or beginning of a cycle.
Here is a really, really basic example of how I would translate this into a class:
class WashingMachine
{
public void Activate(Cycle c, LoadSize s);
...
}
Lately I have been going functional and using immutable objects with Martin Fowler/JQuery chaining fluent style.
I use the type system as much as possible as it makes refactoring.
With my method the compiler will force you to do it right.
Because the objects are somewhat immutable its easier to prove that mathematically this state machine is deterministic.
code:
public class Washer {
public void exampleRun() {
new On()
.wash(30)
.spin(100)
.turnOff();
}
public abstract static class State {}
public static class On extends State {
public Wash wash(int minutes) {
return new Wash(minutes);
}
}
public static class Wash extends State {
private int minutes;
public Wash(int minutes) {
super();
this.minutes = minutes;
}
public Spin spin(int revs) {
return new Spin(revs);
}
}
public static class Spin extends State {
private int revs;
public Spin(int revs) {
super();
this.revs = revs;
}
public Off turnOff() {
return new Off();
}
}
public static class Off extends State{}
}
Option A is like a manual washer while option B is like an automatic washer. Both options are useful to their targeting users:
A user of option A can enjoy manually programming the whole process (like doubling the washing circle, or teaching the little one what if you turn off the machine while it's in centrifuging circle).
A user of option B can enjoy the simplicity and write a dummy serials - teach your self washing in 21 seconds:-)
Have you ever structured your source code based on your user interface parts? For example if your UI consists of:
GridView for showing some properties
3D rendering panel
panel for choosing active tools
, then you name and group your variables and functions more or less in the following way:
class Application
{
string PropertiesPanel_dataFile;
DataSet PropertiesPanel_dataSet;
string[] PropertiesPanel_dataIdColumn;
void PropertiesPanel_OpenXml();
void PropertiesPanel_UpdateGridView();
string ThreeDView_modelFile;
Panel ThreeDView_panel;
PointF[] ThreeDView_objectLocations;
void ThreeDView_RenderView();
string ToolPanel_configurationFile;
Button[] ToolPanel_buttons;
void ToolPanel_CreateButtons();
}
What's your opinions on this? Can this architecture work in long run?
PS. Even though this solution might remind you of Front-ahead-design april-fool's joke http://thedailywtf.com/Articles/FrontAhead-Design.aspx my question is serious one.
EDIT
Have been maintaining and extending this kind of code for half a year now. Application has grown to over 3000 lines in the main .cs file, and about 2000 lines spread out in to smaller files (that contain generic-purpose helper-functions and classes). There are many parts of the code that should be generalized and taken out of the main file, and I'm constantly working on that, but in the end it doesn't really matter. The structure and subdivision of the code is so simple, that it's really easy to navigate though it. Since the UI contains less than 7 major components, there's no problem in fitting the whole design in you head at once. It's always pleasant to return to this code (after some break) and know immediately where to start from.
I guess one the reasons this gigantic procedural-like structure works in my case is the event-like nature of UI programming in c#. For the most part all this code does is implementation of different kinds of events, that are really specific to this project. Even though some event-functions immediately grow into couple of pages long monsters, coupling between event-handlers is not that tight, so it makes it easier to refactor and compress them afterwards. That's why Iam intentionally leaving generalization and refactoring for later time, when other projects start to require the same parts of implementation that this project uses.
PS to make it possible to navigate through 3000 lines of code I'm using FindNextSelection- and FindPrevSelection-macros in visual studio. After left-clicking on some variable I'm pressing F4 to jump to the next instance of it, and F2 to the previous instance. It's also possible to select some part of variable name and jump between partial-name matches. Without these shortcuts I would most defenetly lost my way long time ago :)
That looks very procedural in concept and is completely bypassing the value of OOD. The sensible approach would be to create objects for each of your elements and the values you have given would be properties of those objects, i.e.
class PropertiesPanel
{
public string DataFile { get; set; }
public DataSet DataSet { get; set; }
public string[] DataIDColumn { get; set; }
etc...
I think you get the idea so I'm not going to type the whole lot out. That's a first stage and there may be further work you could do to structure your application appropriately.
The best advice I ever received for OOD was to look to the smallest object that each logical branch of your app can be distilled to, it probably on has native types for properties (with .NET there no point in reinventing Framework objects either so they can be in your base class) and then using inheritance, polymorphism and encapsulation to expand on those base classes until you have an object that encapsulates the logical branch.
At the time I was writing an app that pushed data to an I2C device so I started with a class that put a bit onto an I2C bus, that was inherited by a class that put a byte onto a bus, inherited by a class that put an array of bytes onto the bus, and finally a class that put an address and an array of bytes. This is rather extreme OOD but it produced very clean code with each class being very small and very easy to debug.
It's possibly more work up front in thinking about the problem but in the long run it save soooooo much time it's just not funny.
It's OK to structure your user interface code based on your UI parts, but the non-UI related logic of your program should be kept separate.
But event on the UI part you shouldn't just smash everything into one class. Instead you should divide your UI code into several classes, so that every class only deals with one UI component and doesn't deal with others it doesn't need to know about:
class Application
{
PropertiesPanel
ThreeDView
ToolPanel
}
class PropertiesPanel {
string dataFile;
DataSet dataSet;
string[] dataIdColumn;
void OpenXml();
void UpdateGridView();
}
class ThreeDView {
string modelFile;
Panel panel;
PointF[] objectLocations;
void RenderView();
}
class ToolPanel {
string configurationFile;
Button[] buttons;
void CreateButtons();
}
What's your opinions on this?
It’s a mess.
Can this architecture work in long
run?
No. (At least not without a lot of sweat.)
The names are insanely verbose. If you think about it, the long name prefixes are there to create a kind of separate ‘namespace’, to group related things together. There already is a better language construct for this very kind of thing – it’s classes. But the main problem is elsewhere.
User interfaces change often, concepts change seldom. If your code structure mirrors the user interface, you are locked to this particular interface. This makes reusing and refactoring the code quite hard. If you structure the code around the base concepts from the problem domain, you have a better chance to reuse already existing code as the software develops – the design will adapt to changes. And changes always happen in software.
(I hope that the ‘base concepts from the problem domain’ part is clear. For example, if you create a system for a local theater, you should base your design on the concepts of a Movie, Visitor, Seat, and so on, instead of structuring it around MovieList, SeatMap, TheaterPlan and such.)
Most of the time it is a good idea to decouple the core code from the GUI as much as possible (This is exactly what the Model–View–Controller design system is all about.) It is not an academic excercise, nor it is only required if the interface is going to change. A great example of decoupling the GUI from the rest of the code is the GUI programming on Mac OS X, with the Interface Designer, bindings and such. Unfortunately it takes a while to get into, you cannot simply skim the docs on the web and be enlightened.