天天看點

Unity 多人聯機遊戲(一)1. 建立NetWorkManager 空對象管理聯網2. 添加Player 對象3. 實作用戶端和服務端對象同步4. 給本地對象改變顔色5. 控制主角的射擊6. 子彈同步到用戶端7. 給Player添加血條顯示8. 同步血條和血量

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 中添加 需要生成的子彈
    Unity 多人聯機遊戲(一)1. 建立NetWorkManager 空對象管理聯網2. 添加Player 對象3. 實作用戶端和服務端對象同步4. 給本地對象改變顔色5. 控制主角的射擊6. 子彈同步到用戶端7. 給Player添加血條顯示8. 同步血條和血量
  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
    Unity 多人聯機遊戲(一)1. 建立NetWorkManager 空對象管理聯網2. 添加Player 對象3. 實作用戶端和服務端對象同步4. 給本地對象改變顔色5. 控制主角的射擊6. 子彈同步到用戶端7. 給Player添加血條顯示8. 同步血條和血量
  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;
    }
}