This is part 3 of a 3 part series. To view part 2, click here. If you get lost at any time during this tutorial, you can always refer to the solution code here.
In part 2 we completed our waiting room and enabled the creation of private rooms with socket.io. In part 3 we will create our players and game functionality.
Add Players:
Now that we’ve created the logic for joining our game room, we can implement what needs to happen upon joining. Inside of our ‘joinRoom’ socket listener callback function, let’s add our player to our game room object in the server state:

Now we can update our numPlayers variable on the gameRoom object. Additionally, we will emit the state to the client by sending the gameRoom object to the player that just joined via their socket:

Add a state property to the MainScene class:

In our create method inside MainScene, we can listen for ‘setState’. Inside of the callback function, we deconstruct off of the state object we receive, and assign it to our client site state object on the MainScene class.

Lets head back to socket/index.js to add an emition for our current player, and tell everyone in the game room about our new player that joined. Inside our ‘joinRoom’ callback, we can add these emitions:

Back in MainScene we add a listener for ‘currentPlayers’:

Here we use a method that we will create on the MainScene class for adding our player:

If the socket id that we receive is not ourself as the player, we call a different method on the class for adding other players:

You’ll notice that we depend on a scene.otherPlayers group to add the other players at the bottom of our method, add this towards the top of the create function:

Back to line 54 of our code, below our ‘currentPlayers’ socket listener, add another socket listener for ‘newPlayer’:

If you npm run start-dev and open your localhost:8080, you should see a player on the screen. Now, open an incognito window, go to localhost:8080 and enter the same room code you just used. There should be another astronaut on the screen now! But they cant move! Let’s fix that.
Add player Movement
Inside of our update function, let’s handle player movement. We place this inside of the update function because update can recognize these actions at any time, as opposed to create which runs once when the scene is launched.

First, we check if the astronaut exists to avoid reference errors. Inside of this if statement, we set our speed to a variable, and we use setVelocity to set the initial movement to 0. We check if the left cursor is being pressed, and if it is, we set the x axis velocity to our speed as a negative number, and if our right cursor is being pressed, we set the x axis velocity as a positive integer. If you take a look at vertical movement, we follow the same logic. Open your browser again and give it a try, your astronaut should be moving all over! But if you open an incognito, the movement isn’t emitted. Add the following code below the movement that we just created:

In our socket/index we add our listener, update the players movement on the server state, and broadcast it to the other players in our game room:

Back to MainScene to add the listener for ‘playerMoved’, this can go inside our create method, since its a listener, it can be pinged at any time if its initialized in create:

Give it a whirl in the browser and you should see that player movement is reflected on both browsers.
Handle Disconnect
In case someone leaves the came, we need to update our players object on the gameRoom, and update the client state. We tackle this in the following code:

On our client side in MainScene, at the bottom of the create method, we add the listener and update our client side state to reflect the servers players and numPlayers:

Try adding two players to your game and then closing one of your browsers, you should see the other player disappear and the console log in your terminal.
Add a Task Control Panel
Let’s add a control panel for tasks to pop up when it is clicked, just like in Among Us !
Create a control panel entity in our entity folder, and import it into MainScene. Also preload the image for our control panel, here we call it vending machine:


Create a control panel group and an instance of vending machine, and place is above players inside create:

The vending machine should now appear in your game. Now we will add functionality to it. We want our vending machine to become highlighted and clickable when we are overlapped with it.
First let’s create the overlap. At the bottom of the update method, we add an overlap to our player and the vending machine, and we add a callback function to our third argument of the overlap:

Now we will create the callback function as a method on our MainScene class.
Add the method to our class:

Now if you run your player over the vending machine in your browser it will highlight green. Notice that we aren’t emitting the highlight so it only shows on the client side. But oh no! It doesn’t un-tint when we walk away. Let’s fix that!

Inside of the if(this.astronaut) statement for our overlap, add another function that checks if it’s overlapped. Notice that this is not a method built into phaser, we are going to build it ourselves!

Here we are checking to see if the bounds of the player and vending machine overlap, and if they aren’t overlapping, we call an additional method called deactivateControlPanel, that clears tint and disables interactivity.
Add A Pop Up Scene for Tasks
Now that we have a clickable vending machine, we can setup logic to launch another scene that will handle the task when the vending machine is clicked.
In the scenes folder, add a scene called TaskScene.js.

We load a simple image to show the scene when we eventually launch it. Also notice the init() method on the class, this will be important in our next step as we pass our state to our new TaskScene when it’s launched from mainscene.

Notice that when we start TaskScene, we pass a second argument with an object holding the information that we want to pass to TaskScene. We then add these to the TaskScene class inside its init method.
Before we launch, we also need to add our TaskScene to our game instance:

You should now be able to walk up to a vending machine, click on it, and launch the TaskScene.
This concludes part 3 of this tutorial. You now have the tools to create an Among Us inspired, live-multiplayer game with private game rooms and task functionality using Phaser 3 and Socket.io.
Try:
- Creating a return button to exit the TaskScene
- Creating logic and graphics for a task in the TaskScene
- Adding a start button the uses sockets to trigger the game starting for all players and events that need to happen in the beginning of the game
- Adding a progress tracker with a scoring system
- Adding a database for tasks and global scores
And I’ll leave the rest up to you! I hope you enjoyed this tutorial and I would love to see how you choose to expand on this game.