Building a Skribbl.io Clone: From Concept to Completion
Creating a real-time multiplayer game like Skribbl.io is an exciting challenge that combines various aspects of web development. In this article, I'll talk about my implementation and thinking in building a real time clone how you can handle a game which is round based and timer system
If you want to checkout the source code for the project you can find it here Github
Tech Stack
Before diving into the details, let’s briefly look at the tech stack used for this project:
- Node.js: For the backend server.
- Socket.IO: For real-time communication.
- Redis: For efficient data handling.
- Vite: For fast development with React.
- TypeScript: For type safety in both frontend and backend.
- React: For building the user interface.
- Docker: For containerizing the application.
Setting Up the Backend
The backend is powered by Node.js and Socket.IO, which are perfect for handling real-time interactions. Here’s a quick overview of the main components:
1. WebSockets for Real-Time Communication
Socket.IO allows for seamless communication between the server and clients. We use it to handle events such as players joining rooms, starting games, and sending drawing data.
2. Room System
Each game is hosted in a unique room, identified by a room ID. Players join a room using this ID and interact with others in the same room. The system also handles player connections and disconnections.
But here we have a problem how can we ensute that our server retains the data which was in the game if so the server ever crashes
Here we use a database which is fast and also a separate body from the server
Redis
is a great choice for such type of use case. Its an in-memory database which is fast and can be run separately on a different server
We will talk about that more in the post later.
3. Event Handling
The server listens for and emits various events:
-
Client Events:
connect
,disconnecting
,joinRoom
,leaveRoom
,startGame
,draw
,guess
,changeSettings
,wordSelect
-
Server Events:
joinedRoom
,playerJoined
,playerLeft
,gameStarted
,gameEnded
,drawData
,guessed
,turnEnded
,chooseWord
,wordChosen
,settingsChanged
,guessFail
Developing the Frontend
For the frontend, I used React with TypeScript and Vite for a smooth development experience.
1. Building the UI
The user interface includes components for drawing, guessing, and managing game settings. React’s component-based architecture made it easy to create a dynamic and responsive UI.
2. Handling Game State
The frontend manages the game state, including player scores, current turn, and drawing data. TypeScript ensures that the data structures are well-defined and error-free.
3. Real-Time Updates
Using Socket.IO, the frontend updates in real-time based on server events. For example, when a player draws, the drawing data is sent to all clients in the room.
Game State Management
Effective game state management is crucial for ensuring a smooth and enjoyable experience in a real-time multiplayer game like Skribbl.io. Here’s a detailed look at how various aspects of the game state are managed:
Player Joining and Leaving
Managing players joining and leaving a room involves several key steps:
-
Joining:
-
Event Emission: When a player wants to join a room, they send a
joinRoom
event with the room ID to the server. - Validation: The server validates the room ID and checks if the room exists.
-
Player Addition: If valid, the player is added to the room's player list. The server then updates the game state and emits a
playerJoined
event to all clients in the room, informing them of the new player’s arrival. - UI Update: On the frontend, the new player’s presence is reflected in the room’s player list, ensuring that everyone sees the most current player roster.
-
Event Emission: When a player wants to join a room, they send a
-
Leaving:
-
Event Emission: When a player decides to leave, they send a
leaveRoom
event to the server. - Player Removal: The server removes the player from the room’s player list and updates the game state accordingly.
-
Notification: The server emits a
playerLeft
event to all remaining clients, notifying them that the player has left the room. - UI Update: The frontend reflects this change by removing the player from the player list and adjusting any ongoing game mechanics if necessary.
-
Event Emission: When a player decides to leave, they send a
Word Selection
Choosing a word and managing whose turn it is to choose involves several mechanisms:
-
Current Player Turn:
- Turn Management: The server maintains a record of whose turn it is to choose a word. This is managed by the game state, which includes a property indicating the current player’s ID.
-
Word Selection Prompt: When it’s a player’s turn to choose a word, they receive a
chooseWord
event from the server, prompting them to select a word.
-
Preventing Word Leakage:
- Turn-Restricted Access: The chosen word is not immediately broadcasted to other players. Instead, it is only shared when it is the drawer's turn, to prevent any unfair advantage.
-
Event Emission: Once the drawer has chosen the word, the server emits a
wordChosen
event to all players. This event includes a notification that the word has been selected and is ready for guessing.
-
Notification of Word Selection:
-
Broadcast: The
wordChosen
event includes a notification that a word has been selected, which is sent to all players in the room. - Frontend Handling: On the client side, players are updated to indicate that the drawing phase has begun, and they can now start guessing.
-
Broadcast: The
Handling Timeouts for Word Selection
To handle cases where the current player might delay word selection:
-
Automatic Assignment:
- Timeout Mechanism: The server implements a timer that starts when it is the player’s turn to choose a word. If the player does not select a word within the allotted time, a timeout event is triggered.
- Word Assignment: The server automatically selects a word from a predefined list and assigns it to the player. This ensures the game continues without unnecessary delays.
-
Notification: A
wordChosen
event is then emitted to notify all players that a word has been assigned and that the drawing phase is beginning.
Drawing Data Handling
Handling drawing data is essential for maintaining synchronization between players:
-
Real-Time Drawing:
-
Drawing Events: Players send drawing data to the server using the
draw
event. This data includes brush color, radius, and coordinates of the drawn points. -
Broadcasting: The server receives this data and broadcasts it to all clients in the room using a
drawData
event. This ensures that every player’s canvas is updated in real time with the latest drawing information.
-
Drawing Events: Players send drawing data to the server using the
Handling Player Guess Events
Managing player guesses involves processing and validating each guess:
-
Guess Submission:
-
Event Handling: When a player makes a guess, they send a
guess
event to the server with their guess word. - Validation: The server processes the guess, checking it against the correct word. If the guess is correct, the server updates the game state and player scores.
-
Event Handling: When a player makes a guess, they send a
-
Broadcasting Results:
-
Guess Result: The server emits a
guessed
event to all players, indicating whether the guess was correct or not. - UI Update: On the frontend, the result is displayed to all players, showing who guessed correctly and updating the game’s progress.
-
Guess Result: The server emits a
Timeouts for Drawing and Guessing
Managing time constraints is key to keeping the game engaging:
-
Draw Time Over:
-
Time Management: Each round has a set time limit for drawing. The server tracks this time and triggers a
turnEnded
event when the time expires. - Transition: This event signals the end of the drawing phase, and the game transitions to the guessing phase or the next round.
-
Time Management: Each round has a set time limit for drawing. The server tracks this time and triggers a
-
All Players Guessed:
-
Guess Completion: If all players guess the word before the time runs out, the server triggers a
turnEnded
event early. - Game Flow: This event updates all clients that the guessing phase is complete and transitions the game to the next phase or round.
-
Guess Completion: If all players guess the word before the time runs out, the server triggers a
This approach to managing game state ensures a smooth, interactive, and fair experience for all players, enhancing the overall enjoyment of the game.
Conclusion
Building a Skribbl.io clone involves a complex interplay of real-time communication, game state management, and user interactions. Through this project, we’ve explored various facets of game development, from handling player connections and word selection to managing drawing data and player guesses.
Key Takeaways
- Real-Time Communication: Leveraging Socket.IO allows for seamless and interactive gameplay, ensuring that all players stay synchronized.
- State Management: Efficient handling of game state—such as player joining, word selection, and drawing data—is crucial for a smooth user experience. Implementing timeouts and automatic assignments ensures the game flows without interruption.
- User Experience: Maintaining an engaging and responsive interface enhances player satisfaction. Clear feedback on actions like drawing and guessing, combined with timely updates, keeps players informed and invested in the game.
Next Steps
If you’re inspired to take this project further, consider:
- Adding New Features: Implement additional game modes, customizations, or enhancements to make the game more dynamic.
- Optimizing Performance: Explore ways to improve performance, such as optimizing drawing data transmission or reducing latency.
- Enhancing UI/UX: Refine the user interface and experience based on player feedback to make the game more enjoyable.
This project has been an exciting journey into real-time game development, combining various technologies and techniques to create a fun and engaging multiplayer experience. I hope this article has provided valuable insights into game state management and inspired you to explore more in the world of game development.
Feel free to share your thoughts, questions, or improvements on this project in the comments below. Happy coding!