Design for a board/chess-like game.

Started by
5 comments, last by Simon Larsson 8 years, 4 months ago

Hello people who most likely are vastly more experienced in programming and specifically game-programming than myself!

Beware of tl;dr.

I am currently developing a board/chess/tilebased game. And I am about to implement Unit-Magic in the game, a.k.a each unit in the game will have its own magic. And I have been thinking about using a design I came up with that will probably help me be able to implement this magic in the game. But I am not sure if the solution will work, and I would prefer not spending countless hours on a solution that will not work. So I was thinking of presenting it here and hearing your thoughts and ideas.

So the problem is: Implementing a system where each unit can have unique magic abilities without having to implement code in every part of my system just to handle a new type of magic. Also having an easy implementation of movement and combat between units and the Gameboard.

Example: Unit A has the magic: "Throw a fireball at enemy Unit B". Unit C has the magic "Fly forward five tiles then shoot a rocket launcher at enemy Unit B". Unit D has the magic "Put a firewall up on Tile 1, 2 and 3". And so on...

My Idea of a solution: Keep each class separated from each other. That means that all units reside in one class, the gameboard in another class and the all the magic-abilities reside in a third class. Then have a MessagePasser-class combine them all and force each class to send messages to the other classes through a MessagePasser. The MessagePasser in turn has a queue of messages that it will process one at a time so a class can send three messages simultaneous without problems. (See Picture below).

iqSj4ha.jpg

Examples of the solution: In this solution when you click a certain unit it could work like this:

If the state is Movement: The UnitContainer sends a message to the Gameboard to let it calculate which tiles the clicked unit can move to. A tile that the unit can move to is then clicked and the Gameboard sends a message to the UnitContainer to tell it where the unit should move.

If the state is Magic: The UnitContainer sends a message to the Magic-class to ask what this unit can do for magic. The Magic is "Throw Fireball at enemy unit". The magic-class then sends a message back to the UnitContainer telling it, that the unit should "equip" a fireball-projectile and update the units range attack values. The UnitContainer then sends a message to the Gameboard to let it calculate units in range of the fireball-attack. The Gameboard then sends back on which positions the enemy units in range are on to the UnitContainer. An enemy unit in range is clicked and the unit throws the fireball at the clicked enemy unit.

With this solution "Throw Fireball at enemy unit" would probably be split into several messages such as: Update projectile range, Update projectile damage, Update projectile animation, Do Projectile Attack.

So do you think this solution would work in a game design?

Is there any other design that you think would work or solve the problem better?

It is most definitely some kind of event-system, do you have any suggestion of design-patterns or the like I should take a look on?

And any other comments and suggestions are also more than welcome!

Thank you for your time, I hope my description of the design was sufficient to make it understandable of what I am trying to accomplish.

EDIT: Using Unreal Engine 4 to build it.

Advertisement

To start with, I'm not sure what all this message passing complexity gets you.

Instead of "receive message" just have a method that gets called. Instead of "send message" just call a method. Then you don't need this MessagePasser thing.

"Magic" just can be a function or interface implementation that does the special case stuff needed for that particular magic.

You don't need a special UnitContainer class, just use an array or vector of Units. Units can have some pluggable code that indicates where they can move.

To start with, I'm not sure what all this message passing complexity gets you.

Instead of "receive message" just have a method that gets called. Instead of "send message" just call a method. Then you don't need this MessagePasser thing.

"Magic" just can be a function or interface implementation that does the special case stuff needed for that particular magic.

You don't need a special UnitContainer class, just use an array or vector of Units. Units can have some pluggable code that indicates where they can move.

Hello, thanks for answering.

Uhm I thought doing this way before but I'm not sure It is going to work, or I feel every class will get too coupled if I do this way.

To clear things up, UnitContainer is basically a class with has two arrays that holds player1's units and player2's units. Because I'm using Unreal Engine 4 I have made this class as an actor to initialize and spawn every unit in the array to be able to manage them all. The same way the Gameboard is an class that has an array of BoardSquares that it spawns and manages.

This is just how I think about it, if each unit will have their own magic function they will need to be coupled with all the systems in the game for example the Gameboard to be able to calculate where they can move, the UnitContainer to be able to reach other units (meaning circular coupling) and basically every class that the magic will touch. This is what I was trying to avoid.

Therefore I was trying to decouple things but putting some kind of messager in the middle which instead of coupling everyone to each other they are instead just coupled to the messenger.

This is maybe a redundant way and coupling isn't as bad as I have been lead to believe, but from what I have learned and heard coupling is something you rather want to avoid.

I don't see that your design really decouples anything though. Unit is still dependent on Gameboard and Magic - it's just that that dependency is expressed at runtime by messages (whatever they are) instead of at compile time. Unit won't function properly without Gameboard and Magic around to receive and process those messages. You haven't really improved anything IMO, but you've added cruft and lost type safety (I'm just guessing how your messages might be implemented).

You can decouple your code from relying on a specific implementation of a class by using interfaces (abstract base classes). So anything that queries the board goes through IBoard instead of Board. And Board is just a specific implementation of the IBoard abstract class. But if you'll only ever have one implementation of board, there's no need to make that change (at least not yet).

You *can*, however, remove dependencies of Unit on Board, or Board on Unit, etc... by having some code that sits *above* Unit and Board. Unit can simply express "this is how I can move", and Board can answer the question "What are the places someone can move?". Then code that exists outside of those classes (and which can dependent on Unit and Board) can ask the Unit where it can go, then ask Board which of those are legitimate spots, and the present those options to the player.

Agreed with phil_t. I wrote a checkers online game a couple of years ago, and I didn't have anything half as complicated as your graph.

Just make yourself a 2D array representing the board data, a few methods for different pieces movement, some basic game logic and voila. Add in the badass stuff like your fireball projectiles anywhere.

Agreed with phil_t. I wrote a checkers online game a couple of years ago, and I didn't have anything half as complicated as your graph.

Just make yourself a 2D array representing the board data, a few methods for different pieces movement, some basic game logic and voila. Add in the badass stuff like your fireball projectiles anywhere.


Do that and you have a system that you can't upgrade.
-----------------------------

First rule, use proper object oriented design and interfaces.

Secondly , Keep simple classes that focus on one behavior.

Third, Know what would change and make an interface for it.

(There are tons of rules and principles you can use but these three are the most important for you).

Your design has a lot of flaws,

Too many update messages, you'll focus on managing these messages and states instead of writing game logic.

When you get to a point of many update messages, you'll start having god classes which perform almost everything.

Use events instead of messages classes to show that something happend (Example: The unit has been attacked and dealt fatal damage -> Raise death event -> Play death animation).

If you need design patterns, replace those message handlers with strategy pattern and observable.

If you need state managing, use the state pattern.

For you actual design,

Decouple your update logic from the actual calculations.

A board game such as yours would have a lot of them, Therefore you need to make it enough managable so you could replace calculation as easy as possible.

This replaces your "Update projectile range" to -> "Calculate projectile range".

A decorator pattern could be used but I won't actually use it, A "Handler" pipeline would suffice. (Iterate over calculations, You could also implement calculation priority using a PriorityQueue class).

To summrize my thoughs about it,

- More decoupling.

- Less managers.

- Use events.

- If a class "holds everything"- It probably won't work well.

- Put a lot of though about the design, or else you'll have trouble implementing it.

- Don't over-design it, If you think something won't change, You can even hard-code it. From my experience, over-designing turns into hell.

Thank you for all answers. I will take the advices and rebuild the design to what I've learned and hopefully it will turn out to something good in the end! :)

This topic is closed to new replies.

Advertisement