關鍵詞: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