Photon Unity Networking (PUN) can be used for turn-based games, such as strategy titles or board games. This document gives an overview how to implement such games, based on our Rock Paper Scissors Demo, which is in the PUN Package.
The demo revolves around few Component Scripts:
PunTurnManager is a generic Component Class that can be reused for similar games and logics. It's important to realize that it's not mandatory, but a simple and nice wrapper for you to get up and running with turn-based games quickly. This is for sure a great starting point for building more complex and original gameplays.
In terms of data storage, it solely relies on Room Custom Properties, which is a very efficient way to keep game data around during the game life cycle. So if you need additional features and data, it's strongly suggested that you carry on expanding on Room Custom Properties to define, read and write game related data. Don't forget you can have Webhooks for a third party system to catch Room Custom Properties (but not just!) and treat them data, you could maintain highscores, send notifications, maintain statistics with this.
IPunTurnManagerCallbacks Interface, you can listen to the main turn-based message callbacks. Refer to
RpsCore Script to see how
PunTurnManager can be binded.
It's a critical aspect of turn-based Management to properly listen to these callbacks to keep track across all clients of the current situation. You can/should depend on that to detect game outcome.
You'll find across various known classes in PUN new properties and methods that are extensions specifically design for turn-based system. These extensions are declared in the PunTurnManager.cs in the
TurnExtensions class. This provides for a clean api and makes code more readable.
By all means, feel free to create your own extensions to answer specific needs. Especially hiding away the use of custom properties of players and rooms from your game's logic. By doing so, you allow more flexibility and easier refactoring over time as your project becomes more and more complex.
RpsCore Component Script is dedicated to this demo and implements the specific rules and data for a typical Rock-Paper-Scissor game. It acts as a middle man between the visual interface, the game logic and the
PunTurnManager, implements all its callbacks and controls the various UI elements to reflect the current status of the game. It also handles user input.
It's always good to try and separate what's generic and what's only necessary or different in a particular game. Try to keep that in mind when developing new features.
RpsDemoConnect component is very similar to a regular PUN project for connecting, joining room and lobby.
However, it contains a very important feature: the ability to rejoin a room, which is essential for turn-based games. The idea is to keep track of the room the user is playing in so that when reconnecting and we detect that we were indeed previously connected to a room, and we rejoin that room.
This is done using PhotonNetwork.ReJoinRoom(string roomName) and it depends on the RoomOptions.PlayerTtl (Player Time to Live) for successful re-join call. For example, if your game allows the user to be disconnected for several days, you'll need to set the RoomOptions.PlayerTtl to "(number of days) * 24 * 60 * 60 * 1000"
RpsDemoConnect component meets the basic requirements for connecting and playing. In a real project, you'll likely want to expand on this to provide more feedback on various connectivity status, the lobby, all social aspects such as friends list, etc. This aspect of the game development is the same for the vast majority of networked games, turn-based or not.
Do's and Don'ts
Creating a turn-based game using PUN implies the correct use of PUN features as well as avoiding certain features not supported in turn-based context.
- Properly set RoomOptions.PlayerTtl when creating rooms.
- Properly set the RoomOptions.EmptyRoomTtl when creating rooms. Usually you only need RoomOptions.PlayerTtl but this adds flexibility to your setup.
- Make use of Room Properties to keep track of data inherent of the ongoing game.
- Make use of Custom Player Properties to keep track of player's data that needs to persist between play sessions.
- Use PhotonPlayer.ID to keep track of players
- Use PhotonPlayer.GetNext() to iterate through the players to pass the turn.
- Make use of
PunPlayerScoresextension, and/or get inspired from it to create more complex score or data management.
- Players can become inactive in the room. Check PhotonPlayer.IsInactive to find who's not online currently.
- Don't use PhotonView components and derivates. PUN would hand over control of those when the owner is inactive (not in the room).
- Don't use PunRPC, because they need PhotonViews. Instead use PhotonNetwork.RaiseEvent
- Don't use PhotonNetwork.Instantiate()