Multi-player Online feature (part 2 — on player connect)
In part 1 of our mini series, we created a simple Phaser game with a background image, our character sprite, and some setups for the WebSocket server and connection. Before we dive into today’s topic, you can download the starter code from here.
The goal for today’s blog will be: when a new player connects, this character is created onto the screen; All other logics such as that player’s information is sent to all other existing players, so his sprite will be created for all those players; and all those existing players’ information will be sent to the new player, and a sprite will be created for those players will be discussed in a future blog.
Let’s pull up our game and make some changes before we implement the connection feature.
First, in our game.js file, let’s set the correct width and height to 747x374px.
Next, we will add a walking animation for all 4 directions to the character, and create a cursors variable to control our character with the arrow keys. In our scene1.js file, add the following codes:
All of the codes should be familiar by now, as we have used movement and animation in almost all of our previous blogs. I will quickly go over them:
Line 16, we assign a variable name to our sprite so we can reference it later.
Line 17, we enable physics to allow our sprite to have velocity and be able to collide with other objects in our game.
Lines 19–23, from our sprite sheet named “character” on line 11, we create animations for idle, walking left, right, up, and down. The start and end config indicates which frame is the starting, and which is the ending.
Line 27, we create a cursors variable in order to control our character with arrow keys.
And finally in our update(), we listen for arrow key presses, play the associated animation and move our sprite in that direction.
Now let’s move onto implementing what happens when a new player connects to the server. Let’s break it down step by step as many events triggered when a connection occurs.
So the first thing I want to do is for the server to generate a random number to represent the player ID, and a random position on the map. Notice after we generate a player ID, we won’t be checking if that ID already exists and associated with a player. In the very unlikely event that 2 players share the same player ID, one player could control the movement of the other player, and if one disconnects, the other player’s sprite will also get deleted. But for our demo, we don’t need to worry those details.
The player ID is significant for our server and our game to differentiate each player, and manipulate each player’s sprite based on their player ID.
At the end of our server.js file, let’s add those 3 functions for generating a random player ID, random X, and random Y coordinate.
For the player ID, we will generate 3 random integers between 0 to 99, then add them together. For the X coordinate, it will be a number between 35 to 700, and the Y coordinate will be a number between 50 to 300. So no sprite will be created outside of the bounds of our map’s height and width.
Since we already have a players array, we can store those important information pertaining to a particular player, whenever a new player connects to our server. And we can save a player’s information as an object onto the players array.
From the above code, whenever a connection comes in, the server will call the gpid, randomX, and randomY methods, then put those, along with the player’s unique connection into a playerInfo object with the appropriately named keys. We can then add the new player’s information to our players array by players.push(playerInfo) method.
Now we have the necessary information to create a unique player, we can send those information back to our game, and let our game handle the logic of creating a player.
From lines 47 to 52, the payLoad object is going to be what we send back to our game. Line 55, before we send it, we stringify the object. The property “method”: “connect” on line 48 will be discussed shortly.
Now the server sends the player’s information back to our game, (notice the server only sends 1 player’s data back to that player) we can implement our game logic to create a player instead of hardcoding.
First let’s delete line 16, since we will create another method to make the player based on the data from the server. And comment out line 17 for now. Then move line 25 where we initialized our WebSocket to the inside of init() on line 6.
In our init(), we first create a playerId, x, y class variables and set them to null. When we get those data from the server, we can then set them accordingly.
When we get that information from the server, we store it in a variable named response, and the only information from the response we’re interested in is the data property.
Then, we check the “method” property of the response. If it matches “connect”, then we will set our class variables to the data. At this point, we only have 1 more thing to do, create a custom method to make a player sprite.
After the update() method, still inside of our scene class, let’s create a createPlayer() method, and set its initial location to this.x, this.y variables from our init().
Back to our create(), we can call the createPlayer(), and add physics to it after creation.
If we run the server.js file, then go to localhost:5500 to launch our game, we will see a random position, as well as a playerId for our character. Refresh the page, and you will see those values change each time.
The finished code for today’s blog can be downloaded here. It seems like we did the exact same thing as last time: put a sprite onto the screen, only this time its location is random on the map. But the takeaway is our server can send data to a connection, and a connection (client) can receive those data and manipulate them. All of the logics that follow are the same: the server will broadcast some data to every connection, and those connection will update the game state.
Hopefully you get a chance to try out the code! See you next time!!