今回はUnityのアクションゲームで高い所から落下した時にキャラクターにダメージを与えたいと思います。
キャラクターが地面から離れた時にその位置を記憶しておき、再度地面にふれた時にその距離を計算します。
高い所から落下した時にダメージを与えると言ってもキャラクターが30cmぐらいの高さから落ちた時にもダメージを与えていたのではシャレになりません・・・(+_+)
その為、落下する前の地面のY座標から、落下した後の地面のY座標の距離を計算し、ある程度の高さ(これは設定出来るようにします)を越えていたらダメージを与えるようにしたいと思います。
また、ジャンプをした時に最初の落下地点より上に飛んだ場合の事も考慮し、ジャンプの最高到達点から地面までの距離でダメージを計算するようにします。
(ジャンプした時を考慮しない場合は最初の落下地点を使って計算してください)
キャラクターのHP表示UIを作成
まずはキャラクターのHPを表示するUIとカメラの方を向かせるスクリプトを取りつけ、視覚的にキャラクターのHPが見えるようにしておきます。
キャラクターのHP機能に関しては
も参照してください。
HP表示UIの作成
キャラクター(Ethan)の直下に右クリック→UI→Canvasを作成し名前をHPとします。
その直下にUI→Textを作成します。
HPのインスペクタは↑のようにRect TransformのWidthやHeight、Scaleを変更し、
CanvasのRencer ModeをWorld Spaceに変更します。
HPのUIを常にカメラの向きにするスクリプト
RotateJumpDamageUIとMyHPスクリプトを取りつけます。
RotateJumpDamageUIはHPのUIを常にカメラの方向を向かせるスクリプトです。
1 2 3 4 5 6 7 8 9 10 11 | using UnityEngine; using System.Collections; public class RotateJumpDamageUI : MonoBehaviour { void LateUpdate () { transform.rotation = Camera.main.transform.rotation; } } |
Update関数で角度を変更すると画面のチラつきが発生するのでLateUpdate関数内で処理しています。
HPの管理スクリプトの作成
MyHPスクリプトはキャラクターのHPを管理しているスクリプトでHPをUIに表示したりダメージの処理をしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | using UnityEngine; using System.Collections; using UnityEngine.UI; public class MyHP : MonoBehaviour { // 現在のHP private int hp; // HP表示用テキスト private Text myHpText; void Start () { hp = 100; myHpText = GetComponentInChildren<Text>(); myHpText.text = hp.ToString(); } public void TakeDamage(int damage) { hp -= damage; myHpText.text = hp.ToString(); } } |
外部スクリプトからTakeDamageメソッドを呼び出しHPを減らします。
↑がTextの設定でキャンバスであるHPとサイズを合わせたり位置を調整して設定してあります。
↑が実際にキャラクターの上にHPのUIを表示した画像になります。
ここまででHPの処理に関しての設定が終わりました。
HPの処理に関しての詳しい内容はさきほど紹介した記事を参照してください。
キャラクターが落下した時のダメージ処理の作成
キャラクターが落下したと判断する場合
次にキャラクターが落下した時の処理を作成していきます。
キャラクターが落下する時というのは地面からキャラクターが離れた時です。
キャラクターが離れた時を検知するには地面のコライダのOnCollisionExitで検知出来そうですがCharacterControllerの場合検知出来ないっぽいです。
それにゲーム内の地面全部に検知するスクリプトを設定するのは現実的ではありません。
そこでキャラクターの体からレイを飛ばし地面と接地しているかどうかを常に監視しておきます。
レイが地面に当たっていなければ落下したと判断し落下位置を設定するようにします。
CharacterControllerで接地をレイで確認する方法は
を参照してください。
キャラクターが落下した時のダメージを計算するスクリプトToFallFromAHeight
キャラクターの落下と地面との距離を計算し、ダメージを与えるスクリプトToFallFromAHeightを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | using UnityEngine; using System.Collections; public class ToFallFromAHeight : MonoBehaviour { // レイを飛ばす場所 [SerializeField] private Transform rayPosition; // レイを飛ばす距離 [SerializeField] private float rayRange = 0.85f; // 落ちた場所 private float fallenPosition; // HP処理スクリプト private MyHP myHp; // 落ちた地点を設定したかどうか private bool isFall; // 落下してから地面に落ちるまでの距離 private float fallenDistance; // どのぐらいの高さからダメージを与えるか [SerializeField] private float takeDamageDistance = 2f; void Start() { fallenDistance = 0f; fallenPosition = transform.position.y; isFall = false; myHp = GetComponentInChildren<MyHP>(); } void Update() { Debug.DrawLine(rayPosition.position, rayPosition.position + Vector3.down * rayRange, Color.blue); // 落ちている状態 if(isFall) { // 落下地点と現在地の距離を計算(ジャンプ等で上に飛んで落下した場合を考慮する為の処理) fallenPosition = Mathf.Max (fallenPosition, transform.position.y); Debug.Log (fallenPosition); // 地面にレイが届いていたら if(Physics.Linecast(rayPosition.position, rayPosition.position + Vector3.down * rayRange, LayerMask.GetMask("Field", "Block"))) { // 落下距離を計算 fallenDistance = fallenPosition - transform.position.y; // 落下によるダメージが発生する距離を超える場合ダメージを与える if(fallenDistance >= takeDamageDistance) { myHp.TakeDamage((int)(fallenDistance - takeDamageDistance)); } isFall = false; } } else { // 地面にレイが届いていなければ落下地点を設定 if(!Physics.Linecast(rayPosition.position, rayPosition.position + Vector3.down * rayRange, LayerMask.GetMask("Field", "Block"))) { // 最初の落下地点を設定 fallenPosition = transform.position.y; fallenDistance = 0; isFall = true; } } } } |
isFallがtrue(落ちている状態)の時は現在の位置とfallenPositionの値の大きい方をfallenPositionに設定します。
これは地面からジャンプした時の落ちる位置を更新する為です。
レイを飛ばしてFieldレイヤーやBlockレイヤーにぶつかった時は地面に到達したとし、ダメージを計算します。
落下のダメージが発生する距離を越えた落下だった場合はMyHPスクリプトのTakeDamageメソッドを呼び出します。
今回はダメージを
落下距離 – ダメージを受けない限界距離
で計算しています。
TakeDamageメソッドはint型の引数を受け取る為、int型にキャストした値を引数として渡します。
isFallがfalseの時は落下していない時で、レイを飛ばしてFieldレイヤー、Blockレイヤーにぶつかっていなければ地面に接地していないとし落下地点を設定します。
キャラクターを落下させ動作確認をする
ToFallFromAHeightをキャラクターに取りつけ、
インスペクタで↑のように設定します。
takeDamageDistanceを1に設定し、1m上から落下した時にダメージを与えるようにします。
これで機能が完成したのでUnityの実行ボタンを押して確認してみましょう。
↑のように1mより上から落下した時にキャラクターのHPが減るようになりました。
より高い位置から落下させると距離分だけダメージ量が大きくなっているのがわかりますね!
ゲームなので高いところから落下してもダメージを受けないというものも多いですが、
リアルな感じのゲームを作成したい時は高いところから落下した時にダメージを与えたり、より高いところから落下したら一発で終わり。
というゲームにすると緊張感も増してくると思います。
わたくしの場合リアルなゲームだと3D酔いをしたり、高いところから落ちたりすると実際に落ちたような感じを受けてしまうので、ものによっては避けてしまいます。
バーチャルリアリティを使ったゲームをやったら体に悪そう・・・・(^_^;)