1、场景中创建空物体(重命名为NetworkManager)

  • 添加组件:Network Manager
  • 添加组件:Network Manager HUD。

2、创建游戏物体(重命名为Player):

  • 此物体需要有一个点作为子弹发射位置(重命名为bulletPos)。
  • 使用slider为此物体添加血条(UGUI知识点,此处暂略)。
  • 添加组件:Network Identity,将Local Player Authority打上对勾,表示此物体可以应用到每个客户端。
  • 添加组件:Network Transform。用于在服务端与客户端同步。
  • 将此物体设为预制体。
  • 将此预制体拖到物体NetworkManager的Network Manager组件的Spawn Info下的Player Prefab中,使得每个客户端开启即显示此预制体。
  • 为预制体添加下面脚本。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;//引入命名空间

public class Player : NetworkBehaviour//继承此类
{
    public GameObject bullet;//子弹
    public Transform bulletPos;//子弹发射位置
    void Update()
    {
        if (isLocalPlayer == false)//此物体非本地(只控制当前端的物体)
        {
            return;
        }

        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        transform.Rotate(Vector3.up * h * 100 * Time.deltaTime);//控制旋转
        transform.Translate(Vector3.forward * v * 3 * Time.deltaTime);//控制移动

        if (Input.GetKeyDown(KeyCode.Space))//发射子弹
        {
            CmdFire();
        }
    }

    /// <summary>
    /// 此方法只在本地角色被创建时调用
    /// </summary>
    public override void OnStartLocalPlayer()
    {
        GetComponent<MeshRenderer>().material.color = Color.blue;//为当前端角色设置颜色,方便区分
    }

    [Command]//使得此方法在客户端调用,在服务端运行。
    void CmdFire()//在Command特性下,方法标识符以Cmd开头
    {
        GameObject obj = Instantiate(bullet, bulletPos.position, bulletPos.rotation) as GameObject;//实例子弹
        obj.GetComponent<Rigidbody>().velocity = obj.transform.forward * 20;//为子弹添加速度使产生射击效果
        Destroy(obj, 2);//2秒后子弹销毁

        NetworkServer.Spawn(obj);//将生成的物体同步到客户端
    }
}

下面脚本绑定在血条上使血条一直朝向主相机。 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LookAtCamera : MonoBehaviour
{
    void Update()
    {
        transform.LookAt(Camera.main.transform);
    }
}

3、创建新物体作为子弹。

  • 添加刚体组件:Rigidbody,Network Identity,Network Transform。
  • 将炮弹设为预制体,并将此预制体添加到NetworkManager物体的Network Manager组件的Registered Spawnable Prefabs列表中。
  • 为预制体绑定下面脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bullet : MonoBehaviour
{
    private void OnCollisionEnter(Collision collision)
    {
        GameObject hit = collision.gameObject;//碰撞到的物体
        Health health = hit.GetComponent<Health>();//物体身上的Health组件/脚本
        if (health)//此脚本存在
        {
            health.TakeDamage(10);//调用减血方法
        }
        Destroy(this.gameObject);//销毁当前物体,即子弹
    }
}

4、创建新的游戏物体作为敌人(重命名为Enemy)

  • 添加组件:Network Identity(Local Player Authority打对勾),Network Transform。
  • 设为预制体,然后将此预制体添加到Registered Spawnable Prefabs列表中。

5、创建空物体(重命名为EnemySpawner)控制敌人生成

  • 添加组件Network Identity。将Server Only打上对勾。
  • 绑定下面脚本。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class Enemy : NetworkBehaviour
{
    public GameObject enemy;//敌人预制体
    public int num;//场景中生成的敌人数量

    public override void OnStartServer()
    {
        for (int i = 0; i < num; i++)
        {
            Vector3 pos = new Vector3(Random.Range(-10f, 10f), 0, Random.Range(-10f, 10f));//位置随机
            Quaternion rot = Quaternion.Euler(0, Random.Range(0, 360), 0);//旋转随机
            GameObject ene = Instantiate(enemy, pos, rot) as GameObject;//实例敌人
            NetworkServer.Spawn(ene);//同步
        }
    }
}

6、创建n个空物体作为复活点

  • 每个复活点都添加组件:Network Start Position。
  • 将NetworkManager物体中Spawn Info中Player Spawn Method改为Round Robin。

7、为Player与Enemy预制体添加下面脚本。

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

public class Health : NetworkBehaviour
{
    public const int maxHealth = 100;//最大血量
    [SyncVar(hook = "OnChangeHealth")]//实现字段同步,检测并调用方法
    public int currentHealth = maxHealth;//当前血量(初始值设为最大血量)
    public Slider slider;//血条
    public bool destoryOnDeath = false;//是否允许销毁
    private NetworkStartPosition[] nsp;//复活点数组

    private void Start()
    {
        if (isLocalPlayer)//当前端人物
        {
            nsp = FindObjectsOfType<NetworkStartPosition>();//获取复活点
        }
    }

    public void TakeDamage(int damage)
    {
        if (isServer == false)//只在服务器运行
        {
            return;
        }

        currentHealth -= damage;//掉血
        if (currentHealth <= 0)//血量小于等于0
        {
            if (destoryOnDeath)//允许销毁
            {
                Destroy(this.gameObject);//销毁当前物体
                return;
            }
            currentHealth = maxHealth;//恢复血量(在复活点复活)
            RpcRespawn();
        }

        slider.value = currentHealth / (float)maxHealth;//血条控制
    }

    void OnChangeHealth(int health)
    {
        slider.value = health / (float)maxHealth;
    }

    /// <summary>
    /// 复活
    /// </summary>
    [ClientRpc]//远程调用,每个客户端调用
    void RpcRespawn()//ClientRpc下方法标志符以Rpc开头
    {
        if (isLocalPlayer == false)
        {
            return;
        }

        Vector3 spawnPos = Vector3.zero;//复活点归零
        if (nsp != null && nsp.Length > 0)//复活点存在
        {
            spawnPos = nsp[Random.Range(0, nsp.Length)].transform.position;//随机复活点
        }
        transform.position = spawnPos;//确定在此复活点复活
    }
}

8、将所有绑定的脚本中未绑定的物体或未设置的值进行绑定与设置。

9、将项目打包,打开n个端。

unity镂空mask unity添加空物体_ide

10、一个选择LAN Host(H)作为服务器,其它的选择LAN Client(C)作为客户端。