Making a Multiplayer Game in Scratch

Guide for when life is too peaceful and quiet

TutorialsScratchNetworkingPosted February 26, 2025 2 months ago15 min read

Have you ever had the major issue that life isn't being painful enough for you? Would you like to take on a challenging but useless project? Then this is for you!

Ever since Scratch added cloud variables, multiplayer games have been created and Scratch's servers keep exploding(even while I was making the game). Luckily this isn't a very common thing to do for most Scratchers.

Cloud variables offer the one and only way to communicate with other Scratch instances (or you can also hook up your sound output to another machine's sound input and vice versa and attempt to create a network with that). Originally it's intended for things like high scores, but since you can store anything on there, why not use it to make multiplayer games?

Networking Basics

Networking is very complex, particularly in gaming. Scirra's Construct 3 engine comes with a very good guide on networking in gaming and all that stuff about network conditions, but we don't need to worry about that here - with cloud variables, you already expect it to be slow enough or possibly lose packets. I doubt you will be making a competitive game that requires less than 10ms ping.

Fundamentally, when you are in the middle of a game, there are two types of data being sent:

  • Synced variables(Unreliable): This is stuff like your character's movement and where they are looking at. In a shooter game for example it's important to keep this up to date as frequently as possible, or your enemies will be teleporting all over the place. However, if 1 or 2 packets are being lost out of, for example, 30 or 60 packets a second, it will quickly be up to the date with the following packet.
  • Events(Reliable): This is things that aren't happening as regularly as somebody moving: chat messages, picking up items, firing a shot, etc. They may take longer to deliver(since if packets are lost they need to be redelivered and confirmed) but they are expected to arrive eventually.

Scratch Networking Basics

In regular multiplayer games, data is being sent by packets. For something reliable like chat events, all you need to do is send/receive and display them accordingly, since they are fired once, just like the packets themselves. Syncing a variable like player position on the other hand requires manual work.

In Scratch networking however, there's no such thing as "sending" data - Scratch handles that for you. You are left with cloud variable(s) that will stay persistent and synced across all instances of the game, but you can't really "send" events other by detecting the differences in the variable changing.

So, to put the above into scratch perspective:

  • Synced variables(Unreliable): That's what cloud variable is for. You also very likely don't need to worry about losing packets as much as making actual multiplayer games.
  • Events(Reliable): You can really only do this by implementing an event system yourself. For example, player 1 can temporarily append an event to their cloud variable with a random ID so that events don't get mixed up. Player 2 can then read that event, acknowledge that it's received via its ID, and act accordingly. This of course isn't the only way, but it is the implementation I will talk about below.

Session

To be able to talk to each other in a multiplayer game in the first place, you have to get connected with each other - so that they know you are online. In regular multiplayer networking, regardless of whether you are talking to a server or to a peer/host(p2p), there will be a handshake process(so that they know you've joined), and then data packets sent over an interval so that they know you are online. Whenever you unexpectedly disconnect from games, this means that the server couldn't receive a packet indicating that you are online, since there's not many other ways to tell.

When you are in Scratch however, it's a little different.

First, you are limited to a networking model very different than most regular games. Most competitive games like Counter-Strike 2 have a server that relays information to everyone. Even if you don't have servers, in peer-to-peer networking, there would still be a client that acts as a server(the host) that does the same job. If you have ever seen a host migration in some games, it's because it uses p2p and the host left. With scratch however theres not really a host you can connect to; you can only figure things out by reading the variables yourself. That's not to say it is impossible - it will be difficult to try replicate a p2p system with host migration in Scratch.

Second, since there is no packets anymore, you can only let others know that you are online by constantly updating your variable - and let them constantly read your variable for changes, which is why you can leave out a section of your variable that is to be constantly updated with a random - or incrementing number(as long as it's chagnging). This is how most(if not all) scratch multiplayer games work.

My Game

So, with the above established, I present: My implementation of a multiplayer tetris game in Scratch. It's perfect for working with all the above issues because:

  • It only has(or my implementation at least only has) two players. This means that each player that joins can quickly figure out where they should be - it's either player one or player two, and if player one is taken, it's gotta be two. You can obviously have spectators for the third player and onward, but they don't need to interact with the first two players at all; they just need to receive and display data from the first two.
  • Interaction between players doesn't need a lot of work. Even though tetris itself is very competitive, the networking part doesn't need to be as precise as it would be in a shooter game or a racing game, as all you need to do is send lines to each other and make sure the other side receives it. Tetr.io for example has a delay in sending lines as the client needs a second to replay what the other player did on their board, so when you add latency on top of that, it won't be as disruptive as most other competitive games.
  • A host is not needed for controlling the game state. Since there's only two players, the game technically starts when the second player joins, and ends when the second player joins. If a third player is present here, then the game might require a host to tell everyone what's happening, and whether the game has started. (Although it doesn't really matter in my game since there's no win/lose)

My Netcode

For each of the two players, their state is stored in a cloud variabled called Player1State and Player2State respectively, which looks something like this:

152024292135121928140304040404

This is the encoded form of the following values:

152 024 292...0404 
|   |   |
|   |   Player name data in integer format
|   Length of Player name
Player Activity Check, increases every tick

As you can see, this actually contains my name and the aforementioned online indicator. The reason why I'm including the length is so that the game knows where the next bit starts, which is the event sent by a player. The following is an event of type 1, with a unique ID 24, a size of 01 and a data of 4. This translates to an attack event, sending 4 lines to the opponent.

1 24 01  4 
|  |  |  |
|  |  |  Outbound Event data
|  |  Outbound Event data size
|  Outbound Event ID(Used to track event receiving)
Outbound Event Type(0 for none active)

These are all the events currently in game. And of course, events don't stay in the playerState variable; it will show up for a second and then disappear. I've also implemented an event queue so that in the case of multiple events happening, it will be slowly sent over once every second. Note that this is the absolute opposite of a best implementation, lacking any form of validation for example, but it was working with my game.

Type Length Description Example Data
[1]Attack 1 Data is the amount of lines sent. 4(tetris)
[2]KO'd 0 Tell the opponent that you got KO'd. N/A

Acknowledgements

  • The tetris code I used is completely stolen borrowed from Tech-Coder's project on Scratch. It is the entire reason that my project exists today.
  • Basic concepts of game networking from Scirra.
  • The tetris game I made isn't compliant with any tetris guidelines out there. Please don't hurt me.

PS: I wrote this then left it halfway. When I came back now I forgot what I wanted to write so just feel free to email if you have any questions