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个端。
10、一个选择LAN Host(H)作为服务器,其它的选择LAN Client(C)作为客户端。