关键词:SphereCollider,ClientRpc,Command
基本思路:为角色添加Sphere Collider,通过脚本其体积和碰撞事件,实现冲击效果。
Tips:
官网有很好的关于多人游戏的入门教程,非常值得一看:https://unity3d.com/learn/tutorials/s/multiplayer-networking
1 为角色添加额外的碰撞器,Sphere Collider, 勾选isTrigger,center可根据实际模型调整至中心位置。
2 重写OnStartLocalPlayer(),
public class PlayerControl : NetworkBehaviour {
// 启用生成本地角色时,可以修改一些属性值
public override void OnStartLocalPlayer()
{
// 将本地角色改为蓝色,便于区分,默认为白色
GetComponent<MeshRenderer>().material.color = Color.blue;
// 重设SphereCollider的半径,将其缩小至角色体内
GetComponent<SphereCollider>().radius = 0.4f;
}
}
3 冲击波碰撞和特效的实现
public class Spells : NetworkBehaviour {
// [SerializeField] 可以让私有变量在editor中可见,便于测试;
[SerializeField] private bool m_BombStart = false;
private SphereCollider m_SphCollider;
private float maxRadius;
void Start () {
m_SphCollider = GetComponent<SphereCollider>();
// maxRadius 用来设置冲击波的最大半径
maxRadius = m_SphCollider.radius * 10f;
}
// 法术释放后,控制SphereCollider随时间扩大半径
// 放在FixedUpdate()中,可以使半径增加的速度,在不同性能的机器上保持一致。
void FixedUpdate(){
if(!isLocalPlayer){
return;
}
// m_BombStart 用来控制开始和结束
if(m_BombStart){
if (m_SphCollider.radius < maxRadius) {
m_SphCollider.radius += 0.2f;
} else {
// 半径达到最大后,重置半径,并停止半径继续增加。
m_SphCollider.radius = 0.4f;
m_BombStart = false;
}
}
}
// 冲击波,在PlayerControl.cs中,通过按钮调用
public void Bomb(int groupindex){
// groupindex 区分法术类型,不同类法术设置不同CD,
if (!CD_Trigger[groupindex]) {
// 下个FixedUpdate Frame开始增加SphereCollider的半径;
m_BombStart = true;
// 开启冷却计时;
CDTrigger(groupindex);
// 在角色位置,调用施法效果;
CmdBombEffect(transform.position);
}
}
// 冲击波碰撞效果实现
void OnTriggerEnter(Collider other){
// if条件确保只有非本地角色,才会受到由本地角色所释放的冲击波法术的影响
if (other.CompareTag ("Player") &&
!other.GetComponent<NetworkIdentity> ().isLocalPlayer) {
// 计算冲击方向
var bounceDir = other.transform.position - transform.position;
// 直接调用下面这条语句,在多人游戏中不能实现预期效果,
// 因为本地虽然更改了角色的位置,但服务器端却没有,
// 因此只会看到角色受力后,被服务器迅速重置到之前的位置,最终只会有一个微小的抖动。
// other.attachedRigidbody.AddForce (bounceDir * 500f);
// 正确的做法是让服务器,通知所有客户端来执行这个动作
CmdBomb (bounceDir,other.gameObject);
}
}
// 简单理解,就是向服务器发出一条指令,由服务器来执行 (具体可参考API和开头给出的教程)
[Command]
void CmdBomb(Vector3 dir,GameObject other){
RpcBomb(dir,other);
}
// 简单理解,就是从服务器发出一条指令,在所有客户端上执行
[ClientRpc]
void RpcBomb(Vector3 dir,GameObject other){
// 实现角色受到冲击的效果
other.GetComponent<Rigidbody>().AddForce (dir * 500f);
}
// 同理,这个是用来触发冲击波特效的,如果不通过服务器给所有客户端发指令,那么只能在本机看到,其他客户端则看不到。
[Command]
void CmdBombEffect(Vector3 bombcenter){
RpcBombEffect(bombcenter);
}
[ClientRpc]
void RpcBombEffect(Vector3 bombcenter){
// 保存在EffectsManager.Instance.hitEffects中的一个本地粒子效果
var clone = (GameObject)Instantiate (EffectsManager.Instance.hitEffects[1], bombcenter, Quaternion.identity);
Destroy (clone,2f);
}
}
4 实现效果
(蓝色是本机,白色是另一个玩家。画面有点渣,各位看官见谅,不懂美术的程序员,目前只能这样了。。。)