How to make Among Us in Unity | Part 5 — Killing other Players with RPCs

Welcome to the series that will teach you how to create a game similar to Among Us, in Unity3D Engine.

This is the 5th part of the series. For the first part and the full index follow this link.

I have released the project presented in this tutorial series! It is in form of a Game Kit, with the progress mirroring the one in the videos. If you want a shortcut, instead of creating everything from scratch — or, want to learn — grab your copy right now.

Also, you might want to check How to Make Among Us in Unity series on my channel, Redefine Gamedev. If you prefer the video version, I highly recommend you check that one as well.

In this episode we will look into:

  • How to set up the UI for the killing functionality
  • How to create the Player Body prefab
  • How to detect if other players are in range & display this visually
  • How to work with Remote Procedure Calls in Photon Network

Let’s get started!

Setting up the UI for the killing

Creating buttons in Unity is quite easy (Game Object > UI > Button). We will position it bottom right and give it a proper name. Don’t forget that in order to render UI, Unity needs the objects to be parented to the Canvas.

Scripting-wise, we will create a script called UIControl. It’s main functionalities is to:

  • enable/disable the kill button
  • trigger on kill when the button was clicked

UIControl.cs

The OnKillButtonPressed() will be called by the kill button so don’t forget to assign the onClick event to it.

In Update(), happening every frame, we enable or disable the button based on the fact that the target is in the range or not.

Creating the Player Body Prefab

The body prefab will be spawned whenever a kill was successfully performed. The create a prefab, we initially will create a game object in the hierarchy, add a sprite renderer with the correct texture and drag & drop the object in the project side.

To make this object network-enabled, we need to attach a photonView component. Notice that we also attached a script called PlayerDeadBody and we observe it in the photonView.

In the PlayerBody script we will perform a couple of different things:

  • assign the color for the correct player
  • propagate the color to all the other clients

The assignment of the color on the local game is simple.

The multiplayer information sending is a little more complex.

Firstly, we need to implement MonoBehaviourPun and IPunObservable. These will enable our script to be PhotonNetwork enabled and to be able to send data streams over the network.

IPunObservable requires OnPhotonSerializeView(PhotonStream stream,
PhotonMessageInfo info)
where the magic happens.

Split into two parts, receiving (remote) and sending (owner) we can send the color from the local player to the remote one.

Compressing the color from Color type to 3 floats Red, Green and Blue.

Decompressing the color from R G B to Color unity type.

PlayerBody.cs

Killing Range Detection + Visualization

To detect if the player is in range we will create a new script called Killable. It will be attached to the player prefab.

The variables that we will need for this are:

  • the range of action
  • the line renderer to display if the player is in range
  • the target (killable)

And, of course, this script needs to be attached to the player. Don’t forget to add and customize a line renderer as well. I opted for a line width of 0.5f and the WireMaterial which will draw the line on top of the other UI elements.

Since the script will be on our player as well as the enemies, there are some things we want to avoid e.g. showing the enemy kill lines between themselves. Knowing that information can tell you who is the Impostor!!!

To fix this, we need to prevent initialization of the line renderer if the component is not for the current player:

Notice that we are starting a coroutine. A coroutine is a function that can have it’s action split through multiple frames, minutes or other time frames. We will use a coroutine to continuously detect the target.

Why are we not using the Update() function for this? Because update is called every frame and it’s not good for the optimization purposes to check so often. A coroutine will limit that.

Here we take all the object that have the Killable component Killable[] killList = FindObjectsOfType<Killable>() and iterate through them. FindObjectsOfType is a slow function so it’s important not to use it in the Update loop.

Next, we check if it’s not the current player and if it’s a different one check the distance.

To visually display the line to the target, we will make use of the line renderer in the Update loop this time.

Remote Procedure Calls

But what happens if we want to kill the other player? We set up the Kill button and rigged it up to send a signal. We receive that signal in the Killable script (of the current player).

UI Script:

Killable Script:

And, here, is the first time we will introduce the concept of RPC — Remote Procedure Calls — .

RPC are functions which are called on other people’s machines. They are used to transmit things that are important to arrive on the other side: like a player kill, a score change, a different game state.

To call such a function we need to do 2 things:

  • make sure we annotate the function as RPC
  • call it via the photonView

RPC annotation:

RPC calling:

Notice that Photon allows us to specify the target of this RPC. It can be the master client only, the other clients only, everyone or more.

When we receive it on the other end, we don’t know if it’s the correct player that received it or not.

We can check this via the if (!photonView.IsMine) { return; } call.

Lastly, if we are the correct receiver we will spawn a player body and assign it our color. Make sure that the PlayerBody prefab is located in a Resources folder otherwise Photon cannot remotely instantiate it.

And this is the killable script:

Killable.cs

Want More?

You are covered! Head over to Youtube at Redefine Gamedev channel and check the video tutorial.

Gamedev tips, tutorials & more