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. 子弹同步到客户端
- 首先在NetWorkManager 中添加 需要生成的子弹
- 所有的子弹都需要是服务端生成,然后同步到各个客户端。在生成子弹的fire方法前加上【Command】然后方法名更改为CmdFire(),表示这个方法是在服务端调用。
- 给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添加血条显示
- 创建Slider
- Slider 的Canvas 加上LookAtCamera 脚本,防止血条跟随Player旋转
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LookAtCamera : MonoBehaviour
{
void Update()
{
transform.LookAt(Camera.main.transform);
}
}
- 编写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;
}
}