Death and Respawning

版本检查: 5.3

-

难度: 中级

Currently, nothing happens to the player when the player’s current health reaches zero except for a message in the console on the Server. To make this current example behave more like a game, when the player’s current health reaches zero the player will be teleported back to the starting location with full health.

This will also serve as a way to introduce the [ClientRpc] attribute, which is another tool for State Synchronization.

ClientRpc calls can be sent from any spawned object on the Server with a NetworkIdentity. Even though this function is called on the Server, it will be executed on the Clients. ClientRpc's are the opposite of Commands. Commands are called on the Client, but executed on the Server. ClientRpc's are called on the Server, but executed on the Client.

To make a function into a ClientRpc call, use the [ClientRpc] attribute and add “Rpc” as a prefix to the name of the function. This function will now be run on Clients when it is called on the Server. Any arguments will automatically be passed to the Clients as part of the ClientRpc call. For more information on the [ClientRpc] attribute, please see the page on Remote Actions.

To enable respawning we will need to create a new Respawn function in the Health script and create a call to it in TakeDamage on the Server when the player’s current health reaches 0.

  • Open the Health script for editing
  • Create a new function called Respawn with the [ClientRpc] attribute and Rpc prefix.
[ClientRpc]
void RpcRespawn()
{
    if (isLocalPlayer)
    {
        // move back to zero location
        transform.position = Vector3.zero;
    }
}

Now, in TakeDamage when the player’s currentHealth reaches 0, we need to update the code to respawn the player.

  • Change the code in TakeDamage to reset the player’s currentHealth to maximum.
currentHealth = maxHealth;

  • Replace the Debug.Log line with a call to RpcRespawn
// called on the Server, but invoked on the Clients
RpcRespawn();

The final script should look like this:

Health

Code snippet

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;

public class Health : NetworkBehaviour {

    public const int maxHealth = 100;

    [SyncVar(hook = "OnChangeHealth")]
    public int currentHealth = maxHealth;

    public RectTransform healthBar;

    public void TakeDamage(int amount)
    {
        if (!isServer)
            return;
        
        currentHealth -= amount;
        if (currentHealth <= 0)
        {
            currentHealth = maxHealth;

            // called on the Server, but invoked on the Clients
            RpcRespawn();
        }
    }

    void OnChangeHealth (int currentHealth )
    {
        healthBar.sizeDelta = new Vector2(currentHealth , healthBar.sizeDelta.y);
    }

    [ClientRpc]
    void RpcRespawn()
    {
        if (isLocalPlayer)
        {
            // move back to zero location
            transform.position = Vector3.zero;
        }
    }
}

In our example the Client controls the position of the local Player GameObject. This is because the Player GameObject has local authority on the Client.

If the Server simply sets the Player GameObject’s position back to origin when the player’s currentHealth reaches 0, the Client would override the Server as the Client has authority.

To avoid this, the Server instructs the owning Client to move the player's GameObject to the restart position as a ClientRpc call. This position is then synchronized across all of the Clients because of the player GameObject's NetworkTransform.

  • Save the script.
  • Return to Unity.
  • Build and Run this scene as a standalone application.
  • Click the Host button from the in-game UI to start this game as a Host.
  • Move the player GameObject.
  • Return to Unity.
  • Enter Play Mode.
  • Click the LAN Client button from the in-game UI to connect to the Host as a Client.
  • Move the player GameObject, so neither player GameObjects are at the origin point.

When one player shoots the other and does enough damage to reduce the target’s current health to 0, the damaged player GameObject should be sent back to origin and its current health restored to maximum.

  • Close the standalone player.
  • Return to Unity.
  • Exit Play Mode.

相关文档