Turn-based RPG control model

I am making 2D RPG game in Unity, similar to first Ultima games. Player is traveling on world map where enemies spawn and go to attack him. Difference is that I am using separate battle scene similar to Pokemon games, with selecting action etc.

I have working world to battle and back transition, switching world-map sprites for battle scene sprites for both player and the enemy and I was just about to start svripting enemy movement. And that’s when I realised I might have started in a wrong way.

So far I have movement control script attached to player. But if I want player, enemies and NPC taking turns, I need a manager that will control state of the game, like in battle scene.

And my question is: for a game like this, would it be better to have player movement, enemy movement and others handled through the game manager object/class instead of individual scripts attached to each game object?
For current situation I simply considered making a list of enemies on map, and after player was done his movement to simply run enemy move function via some simplified manager.

Would concetrating this into one class be better?

(opinion)
It’ll be easier to do this with a “battle manager”.

Trying to make turn-based combat through drone swarm approach (individual scripts, completely disconnected from each other) will likely quickly turn into trying to herd cats.

Basically, in case of “separate scene battle”, the battle scene itself is a different object separate from the world, and it needs to maintain some internal state, like turn order.

However, avatars used in the battle can have their own attached components for the purposes of decision making. So you could have the “battle manager” manage turn order and have combatant components decide their actions.

Got it. Now that I think about it, it seems easier than what I had planned.

One thing that I’m not entitely sure about in regards of World-Battle transition:

Should I have one Manager object wuth singleton on it for both World and Battle turn management? And shoild this all ve contained within one class?

Example:

World:
Player turn
Enemy turn
NPC turn

Battle:
Battle setup
Player turn
Enemy turn
End battle (won, lost, ran)

A JRPG battle screen is a completely separate scene from the world, if that’s what you’re going after.

.

In this you’d spawn battle prefab or load battle scene, and then return to the world when the battle is over.

If you were going after Jagged Alliance/Fallout 2 turn based combat, then that’s would be different.

In this scenario the world would remain the same, but battle mode alters rules for everybody involved.

In general it is better to have multiple objects with clearly defined responsibilities, isntead of making a “god object” that tries to do everything.

2 Likes

I usually run turn based combat as a series of nested coroutines.

So i take a component/manager that coordinates which asks different things for IEnumerators, then runs them in sequence. Simple, flexible and scales reasonably well I think.

So an AI component will have a:

public IEnumerator GetTurnRoutine(){...}

Player turn has something like a player input controller that also returns a routine.

Then all you need to do is grab the routine for whatever needs to happen and return it. If you need interrupts or whatever, these are just nested routines.

1 Like

I have a world map in same style like Ultima 1 for example. 1x1 unit grid, movement only in X and Y direction, one step (or action) = 1 turn

Battle scene is handled as separate scene, like in JRPG.

Player movement is handled via script attached to player object. I have raycast check before every step for collision. If I detect object in “enemy” layer, I trigger a method from class attached to enemy that will give him “DontDestroyOnLoad” property. With this, both player and enemy are taken to the battle scene where Battle System class takes all the info it needs from them. If enemy is defeated, the enemy object is destroyed and player returns back.

7451198--914159--upload_2021-8-26_18-22-38.png

I wanted to transfer as less as possible in between the scenes. So I have both player and enemy prefabs attached both sprites and animators for world and battle.

But when it comes to world map turns, I will need some GameManager as well. I planned to have some methods within the manager that would be called by playerObject when he makes a move. This is probably close to what @frosted suggested, but I am fairly new to coding so I’m not sure.

In short, do I need to have some persistant World Manager that just stays dormant during battle scene, or should I work towards making World Manager independent of informations stored during scene transfer?

(Am I even making sense?)

I’m not sure if my approach is good for a new coder or not. I think its really simple, but I’ve been writing code forever, so ymmv. Nested routines and stuff may be a little much if you’re new to coding.

Regardless of the actual process for how you run turns, I think the answer to this is yes.

You don’t necessarily need to load a separate scene if the battle screen is very simple, but you should completely transfer control to a separate component/manager/thing.

These two screens are completely separate. The code should be also.

Loading a separate scene is nice because it makes it easy to initialize both screens cleanly and you don’t need to cleanup after yourself much. The code for saving/loading a game can be pretty much the same as loading a scene, so you kinda kill two birds with one stone.

Like you have a “GameState” object that has all the game state data (you can serialize/deserialize to save/load) - then the scene unpacks what it needs from that object to initialize itself. The process for loading directly into that scene from a save or another scene can be pretty much the same.

1 Like

I think I understand now. “GameState” object did not come to my mind at first, that would be probably best solution.

And I can use both World and Battle Controllers to take needed informations from it. I am storing player and enemy world position in them, I could move that information to GameState too, together with all the other enemies spawned on map, etc.

I will probably transfer player movement script to World Controller, this way I can keep whole turn process at one place.

Yep. Just focus on the basics.

Think about how you’re going to save and load the game. You’re going to need some kind of object that has all the info on your party, enemies, etc.

You can use that object for loading between scenes or for loading from a save file, it should generally be very similar, if not identical code.

It’s worth noting that if you wanna write it to a file - you need to not directly link unity objects - all the data should be in plain c# objects, that give you the information you need to spawn the unity objects. If you’re a beginner coder, this part may be very challenging - so if anyone else has better advice, feel free to jump in.

And that is reasonable. Except that you can also get rid of raycasts and implement a world grid. And then ask the grid “what’s in that cell”.

However…

You don’t need to transfer anything anywhere. As in you don’t need to remove the player from the world when the battle starts. Instead you can simply pause the world, load/start the battle, and tell the battle manager which character types participate so it can load sprites for them. The actual data can be stored in a “floating” datablock implemented as a normal class and you could pass that into the battle manager.

You also don’t need to unload the world and load battle screen, because you can simply disable or pause them. So you could stop the world and draw the battle screen on top.

It doesn’t matter. Implement whatever works.

World grid is something I need to look at, but sounds like something I should definitely do.

Drawing battle on top of a paused world seems like a great idea! This could actually save a lot of loading time in the future as well simplify some coding. I won’t have to change player and enemy sprite, but just choose corresponding graphical representations. Thanks a lot!

@frosted : Also thanks for the tip of saving game state in a manner that could also will be base for save/load system. That is a good and useful point, that will help me from some headaches in the future. :slight_smile:

Modern computes are very powerful so you don’t need to load/unload stuff every time and can have world and battle screen placed into the scene in advance. Then you can hide/show both of them as needed. GameObject.SetActive…

Now if you start running into problems then you could consider unloading them.

1 Like

yeah if your battle system is simple and especially if you aren’t loading in tons of geometry and the like, scene changes aren’t needed. You can still do it if you want, but its more a question of what’s easier for you to do, as either enable/disable or load/unload should be pretty close to the same result.