敵を攻撃したときにダメージがでるようにしたいと思います。
今回はダメージを出すのが目的でダメージ計算はしません。とりあえず、ランダム値で出していきます。
Canvasを作成し、TextMeshProを置く
Hierarchyに右クリックを押し
UI > Text – TextMeshPro
を選択、自動でCanvasが作られその子にText – TextMeshProが作成されます。
Canvas置いてその子にText – TextMeshProを置いても同じです。

今回は、ダメージは敵に攻撃が当たったら、敵の頭上に出したいと思います。
なのでCanvasのRender Modeを「World Space」にします。

スクリーンの位置ではなく、3D座標の位置・回転(Rect Transform)で指定することができるようになります。
見えるとこまで移動してみます。

だいぶデカいですね。位置やサイズを調整します。

まだ大きい気もしますが、このくらいですかね。変更したところです。細かい説明は割愛します。

Prefab化する
ProjectのAssetsの中にPrefabsフォルダを作成してそこにドラッグ&ドロップで移動する。文字が青くなればOKです。

ダメージを表示するスクリプトの作成
DamagePopupGeneratorという名前でファイルを作成します。
using TMPro;
using UnityEngine;
public class DamagePopupGenerator : MonoBehaviour
{
public static DamagePopupGenerator current;
public GameObject prefab;
private void Awake() {
current = this;
}
public void CreatePopup(Vector3 pos, string text)
{
//インスタンス作成
var popup = Instantiate(prefab, pos, Quaternion.identity);
//テキストを設定
var temp = popup.transform.GetChild(0).GetComponent<TextMeshProUGUI>();
temp.text = text;
//削除タイマー(1秒で消える)
Destroy(popup, 1f);
}
}
シングルトン(currentのとこ)にすることでどのオブジェクトからもGetComponentなしで参照することができるようになります。他のオブジェクトから呼ぶときはDamagePopupGenerator.current.CreatePopupで呼べます。
Hierarchyにオブジェクトを作成し、スクリプトをセットします。

Prefabもセットしておきます。
武器が敵にヒットしてダメージ判定を行うところに記述します。
private void OnTriggerEnter(Collider other) {
//現在のAnimation情報を取得
AnimatorStateInfo currentBaseState = animator.GetCurrentAnimatorStateInfo(0);
if (currentBaseState.tagHash != AttackTag) return;
//EnemyだけHitする
if (other.tag != "Enemy") return;
Debug.Log("OnTriggerEnter!:" + other.name);
//当たった位置を取得する
Vector3 hitPos = other.ClosestPointOnBounds(this.transform.position);
//ここにパーティクルを生成
Instantiate(hitParticle, hitPos, Quaternion.identity);
//ダメージ表示
DamagePopupGenerator.current.CreatePopup(other.transform.position + Vector3.up * 1.5f, UnityEngine.Random.Range(0, 1000).ToString());
}
アニメーションする
アニメーションさせるためにPrefab化したオブジェクトにスクリプトを追加します。
Overrideを忘れずに
DamagePopUpAnimationというスクリプトを作成しました。
using TMPro;
using UnityEngine;
public class DamagePopUpAnimation : MonoBehaviour
{
public AnimationCurve opacityCurve; //透過処理用
public AnimationCurve scaleCurve; //サイズ変更用
public AnimationCurve heightCurve; //高さ変更用
private TextMeshProUGUI textMesh;
private float time = 0;
private Vector3 origin;
private void Awake()
{
textMesh = transform.GetChild(0).GetComponent<TextMeshProUGUI>(); //テキストの取得
origin = transform.position; //基準となる初期位置の取得
}
private void Update()
{
textMesh.color = new Color(1, 1, 1, opacityCurve.Evaluate(time)); //透過処理
transform.localScale = Vector3.one * scaleCurve.Evaluate(time); //スケール(サイズ)の処理
transform.position = origin + new Vector3(0, 1 + heightCurve.Evaluate(time), 0); //高さの処理
time += Time.deltaTime; //時間管理
}
}

カーブはそれぞれ以下のように設定しました。点を右クリックし、Edit Keyで設定します。Both TangentsをLinearにすることでカーブをなくし直線になります。

横軸が時間、縦軸が値になっています。
いいかんじではないでしょうか。もし表示時に一瞬スケール調整前の文字が出てしまう場合は、文字の色でAlphaを0にしておくとよいと思います。
テキストをこちらに向ける
ダメージは薄い板に表示しているようなものなので、角度を変えると

このように斜めになってしまう。対策としてはカメラのほうに常にむく、Billboardingと呼ぶみたいです。スクリプト(UIBillboarding)を新しく作成します。
ちなみにDamagePopUpAnimation に入れてもいいのですが、他にも使いまわしたいということもあって分けます。
using UnityEngine;
public class UIBillboarding : MonoBehaviour
{
private Camera cam;
private void Awake()
{
cam = Camera.main;
}
private void Update()
{
//カメラのほうを向く
transform.forward = cam.transform.forward;
}
}
これをPrefab化したオブジェクトに追加します。overrideを忘れずに!
他のオブジェクトに重なっても見えるようにする
ここまでは、敵キャラクターの上に数字を出していました。できればキャラクターのとこに出したいので、OnTriggerEnterの関数内で以下のように変更しました。
//ダメージ表示
DamagePopupGenerator.current.CreatePopup(other.transform.position, UnityEngine.Random.Range(0, 1000).ToString());
すると・・・。
文字が重なって見えなくなってしまいました。これを修正するにはShaderを変更します。
ただし、Fontのマテリアルのシェーダーを変更するので同じフォントを使いまわす場合は注意が必要です。
ダメージ用フォントとして分けたほうがいいです。フォントをコピーして使います。

フォントをコピーしてOverlayってつけました。Shaderを変更します。

変更したシェーダーをテキストに適用します。

確認します。
OKかと思います。


コメント