0
\$\begingroup\$

This is my first time using Unity (and my third time creating a game in general), so I hope I can provide the needed information to solve this problem.

I want to create a turn-based system for my 2D Top/Down Roguelike. After the generation of the dungeon, there will be x enemies spawned based on chosen difficulty and chosen quest.

How should each turn look like?
Player for example is an Orc, so he gets 7 movement (meaning he can move 7 tiles). In his turn he can move for example 3 tiles, then attack, 2 tiles, use a potion and then uses his last 2 tiles of movement. And then he presses "End Turn" and then the enemies go through their turns (based on which type of creature they are). The player can skip his turn completely, attack and don't move or only move. But he always needs to press the "End Turn" button.

What I would do, to solve this issue:
I would create a boolean for every single enemy and the player, then turn them true or false. And whenever boolean is true, that person can do his turn. But to check this, I would need to put it in the "Update" method. So on every frame there would be x+1 checks (all enemies plus player), who can move or not.

A second idea would be to put the player and the enemy in an array, sort by speed variable (so who goes first, and who goes last) and then I would have my turn order without any boolean. But this still leaves the question, how I would prevent the player of moving or doing stuff while it is not his turn.

I don't think any of them would be a good idea. Since I use now Unity, I hope there is a better option for this. And just a heads up, English isn't my first language, but I hope you can understand me. I will happily answer any question.

\$\endgroup\$
2
  • \$\begingroup\$ Can you give us some more information? For example does the player know what the enemies do in their turn? Can he see them at every time or does he only know they are there if the player can see them? \$\endgroup\$ – PSquall Sep 27 '19 at 19:08
  • \$\begingroup\$ He does not see the enemy or what they do, only if there are in line of sight to each other. \$\endgroup\$ – Christopher Sep 27 '19 at 20:33
0
\$\begingroup\$

You'll need two subsystems -

the one chooses who'll be acting next, and the other handles his(her, its) turn until it is over. Since it is a turn-based game, no more than one entity can be active at once. This will simplify things for you.


The choosing system

There are many ways to make it:

  • A queue (the simplest). Just make it based on a queue. Its not necessary to use the Queue class (but you may). A list with a counter will do.
  • A sorted queue. Based on entities' initiative. You'll need to carefully update the order when the initiative changes somewhere.
  • A deck. It's the same as a queue, but shuffled after each full iteration. You may use Fisher-Yates shuffle or invent your own custom algorithm (not recomended).
  • A priority queue. The key is the moment when an entity will become active, and the value is that entity itself. Take the entity with the eariest turn time, make a move, put it again with updated time, repeat. It time exceeds current time then wait, render and increment time. If the initiative changes, you remove that entity and insert it with new priority. This method is more flexible, but also more bug-prone.

The updating system

The simplest way is to store the active entity there and call its update method repeatedly (if it derives from MonoBehaviour then use a different name for its update method).

If it's player controlled entity, check input here. If it's a bot, write its logic here.

Make it return a value: is the turn completed or not? If yes, put the entity back into queue and take the next. If no, just wait - it's what the world does here in turn-based games.

If your game has reactions, you will have to implement the concept of suspended turns. In that case you need a stack of active entities. If a reaction triggers, new entity is pushed to the stack. When its work is done, the suspended turn continues (or ends, depending on the code).


Be careful

When an entity spawns, despawns or changes initiative, the choosing system should handle it (add, remove etc.). Incorrect code may update dead entities, skip entities or handle them twice like here:

entities: ABCD
active:    ^
it's B's turn!
during B's turn A was removed
entities: BCD
active:    ^
turn has ended, the counter is incremented as usual
entities: BCD
active:     ^
it's D's turn!

We skipped the entity C.

\$\endgroup\$
4
  • \$\begingroup\$ Can you explain more, what you mean with "If no, just wait", how can I just wait.? Lets say I have the "End turn" button for the player. How can I go back to my array/queue, after pressing the button. Apart from that, you answered all my questions :D \$\endgroup\$ – Christopher Sep 27 '19 at 21:17
  • \$\begingroup\$ @Christopher "wait" means do nothing until next frame. If you have a button, you should check in update method of player entity if it was pressed, and if it was, return the value representing the turn's end. \$\endgroup\$ – trollingchar Sep 28 '19 at 8:21
  • \$\begingroup\$ So : while endTurnButton Not Pressed { repeat update method }? \$\endgroup\$ – Christopher Sep 28 '19 at 9:32
  • \$\begingroup\$ Thanks will try out 😀 \$\endgroup\$ – Christopher Sep 28 '19 at 9:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.