無敵時間
ゲームを作っているとよく実装したくなる無敵時間ですが、
UpdateとOnTriggerEnterなどで実装するとなると少し頭を捻ります。
(少なくとも私は。。。)
そこで、UniRxを使うことにしました。
特に当てはなかったのですが、UniRxならいい感じのオペレーターが既にあるだろう
と思って探してみたら、やはりありました。
下記リンクで「まさにこれだ!」ってのがあったので
メモ残します。
【参考リンク】:UniRx オペレータ逆引き
ThrottleFirst
直訳(最初の一回の絞り弁)通りの意味で
最初に発行された値が通ったあと、
引数で指定した時間分だけ値を遮断してくれます。
this.OnTriggerEnterAsObservable().Where(collision=>collision.gameObject.tag=="Enemy").ThrottleFirst(TimeSpan.FromSeconds(遮断したい秒数))あとはSubscribeの中でコルーチンを動かして
残りの細かい処理を委譲して完成です。
コード
コルーチンを使っているので重複して動かないようにだけ気を使いました。
Rxの導入により非常にシンプルに実装できました。
usingSystem;usingSystem.Collections;usingUnityEngine;usingUniRx;usingUniRx.Triggers;usingSystem.Linq;/// <summary>/// Playerにアタッチ/// </summary>publicclassPlayerDamaged:MonoBehaviour{[SerializeField]MaterialdamageMaterial,normalMaterial;[SerializeField]AudioSourcedamageSound;CoroutinedamageEffectCoroutine;floatinvincibleTime=1.0f;MeshRendererplayerMeshRenderer;voidStart(){playerMeshRenderer=this.gameObject.GetComponent<MeshRenderer>();//敵に当たったら音が鳴ってマテリアル変更→無敵時間を作って終わったらマテリアルを元に戻すthis.OnTriggerEnterAsObservable().Where(collision=>collision.gameObject.tag=="Enemy").ThrottleFirst(TimeSpan.FromSeconds(invincibleTime)).Subscribe(_=>{if(damageEffectCoroutine!=null){StopCoroutine(damageEffectCoroutine);}damageEffectCoroutine=StartCoroutine(DamageEffect());}).AddTo(this);;}IEnumeratorDamageEffect(){Debug.Log("Damage");damageSound.Play();playerMeshRenderer.material=damageMaterial;yieldreturnnewWaitForSeconds(invincibleTime);playerMeshRenderer.material=normalMaterial;if(damageEffectCoroutine!=null){damageEffectCoroutine=null;}}}デモ
音が無いのでわかりにくいですが、
しっかりと無敵時間が反映された挙動となりました。
