unity征服Unity3dunity3D技术分享

[Unity3D] 多人游戏中以角色为中心释放冲击波

2017-11-10  本文已影响112人  薯條

关键词: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 实现效果

(蓝色是本机,白色是另一个玩家。画面有点渣,各位看官见谅,不懂美术的程序员,目前只能这样了。。。)


冲击波.gif
Enjoy It!
上一篇下一篇

猜你喜欢

热点阅读