Uno Multiplayer
Spring 2020
I aimed to replicate the timeless UNO card game, primarily to enjoy it with my friends during the COVID lockdown. This endeavour offered an excellent opportunity for me to explore the complexities of multiplayer game logic. To achieve this, I chose to use Socket.IO due to its swift functionality and straightforward player tracking capabilities. It also worked well on the web, allowing friends to easily join via a browser link.
Key Features
- Server-Side Game Logic: The Uno game logic is entirely calculated on the server, which receives actions from the current player. The Uno game also keeps track of whose turn it is and handles players disconnecting. Once the server processes the game logic, the results are sent to all players to synchronize their clients.
- Client Side Preemptive Actions: The client also maintains awareness of game logic, including the current player's status, to synchronize graphics. It calculates valid moves to prevent users from selecting invalid actions, ensuring smoother gameplay. When a move is submitted to the server, the client proactively updates its visuals to provide a highly responsive gaming experience. If the action is found to be invalid, the client will revert its visuals to match the server-side state during the resynchronization process.
- Lobby System: Originally, this project had a single lobby system, allowing only one game to start at a time. This design enabled players to join progressively and wait for the current game to finish. Later, I introduced functionality for multiple lobbies, allowing clients to create lobbies with specific names and passwords. Players can join and leave these lobbies, and when all members within a lobby are ready, the game begins as usual.
Challenges, solutions and lessons learnt
As this was my first multiplayer project, it was quite challenging to plan out the communication between clients and the server. My objective was to minimize the amount of information sent to the clients to reduce client-side waiting. However, I learned that attempting to send only specific information can introduce significant complexity when bugs arise. If I were to work on a similar project in the future, I would consider organizing the data that needs to be synchronized with clients separately to make it clear where data enters and exits the system.