1. 创建NetWorkManager 空对象管理联网

新建一个场景,场景下挂载一个空的对象NetWorkManager,为其添加NetWorkManager 和 NetworkManagerHUD 组件

2. 添加Player 对象

  • 添加一个Player 对象 并将其生成为预制体Prefab
  • 挂载PlayerController 脚本 控制对象的旋转和移动

3. 实现客户端和服务端对象同步

  • 加载预制体后发现服务端和客户端的两个player同时在移动。解决方案:将playercontroller 继承 NetworkBehaviour, 其中有一个isLocalPlayer 属性,如果不是本地player就不做任何操作return.
  • 同步两边的位置:在player中挂载NetworkTransform,就能实现同步功能

4. 给本地对象改变颜色

public override void OnStartLocalPlayer()
    {
        //只在本地对象初始化完成后调用
        GetComponent<MeshRenderer>().material.color = Color.blue;
    }

5. 控制主角的射击

按下空格键 发出子弹

private void fire()
    {
        GameObject bullet = Instantiate(bulletPrefab, bulletPos);
        bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 10f;
        Destroy(bullet, 2);
    }

6. 子弹同步到客户端

  1. 首先在NetWorkManager 中添加 需要生成的子弹
  2. 所有的子弹都需要是服务端生成,然后同步到各个客户端。在生成子弹的fire方法前加上【Command】然后方法名更改为CmdFire(),表示这个方法是在服务端调用。
  3. 给bullet子弹对象添加NetWorkTransform ,同步子弹
[Command]
   private void CmdFire()
   {
       GameObject bullet = Instantiate(bulletPrefab, bulletPos);
       bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 10f;
       Destroy(bullet, 2);


       //同步到各个客户端
       NetworkServer.Spawn(bullet);
   }

7. 给Player添加血条显示

  1. 创建Slider
  2. Slider 的Canvas 加上LookAtCamera 脚本,防止血条跟随Player旋转
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LookAtCamera : MonoBehaviour
{
  

   void Update()
   {
       transform.LookAt(Camera.main.transform);
   }
}
  1. 编写Health逻辑 使其与slider数据绑定
public class Health : MonoBehaviour
{
   // 固定血量
   public int bloodCount = 100;
   public int allBlood = 100;
   public Slider slider;

   public void takeDemage()
   {
       //受到伤害
       if (bloodCount > 0)
       {
           bloodCount -= 10;
           slider.value = bloodCount / (float)allBlood;
       }
   }
}

8. 同步血条和血量

比较坑的一点是,你会发现上面第7步做完后,服务端的血量一直在掉,然而客户端的血量要么不掉,要么掉的很少。这是因为咱们的开火逻辑是服务端在处理,由于网络和传输的问题,不管怎么样服务端执行的一定要比客户端快,当服务端的碰撞完了后销毁了这个对象,客户端就没有这个对象了,从而不能时效的进行碰撞检测,减少血量。

解决方法:血量减少的逻辑也让其只在服务端处理,客户端同样只做同步操作。

public class Health : NetworkBehaviour
{
    // 同步血量
    [SyncVar(hook ="OnChangeHealth")]
    public int bloodCount = 100;
    public int allBlood = 100;
    public Slider slider;

    public void takeDemage()
    {
        if (!isServer) return;
        //受到伤害
        if (bloodCount > 0)
        {
            bloodCount -= 10;
        }
    }

    //检测到SncVar 标准的变量变化后,就会执行 OnChangeHealth 这个方法
    void OnChangeHealth(int health)
    {
        slider.value = bloodCount / (float)allBlood;
    }
}