ゴマちゃんフロンティア

アザラシが大好きなエンジニアの開発日記です

【開発日記】ダメージを受けた位置によってダメージモーションを変化させる方法

time 2018/10/21

というわけで、今回は開発中のゲームに関するちょっとしたお話です。
プレイヤーキャラがダメージを受けたとき、今まではどの方向から攻撃を受けても後ろに仰け反るので、3Dゲームとしてはちょっと不自然でした。
同じ仰け反るでも、例えば後ろからダメージを受けたときは下のようなモーションにしたいところです。

ちょっと前の記事で「オブジェクトの衝突位置を取得」を考えたので、これを元にダメージを受けた位置に応じてモーションを変えるようにしてみました。

【Unity】物理演算を(なるべく)行わずにオブジェクトの衝突位置を取得する方法

ダメージ位置用の列挙型作成

コード上でダメージ位置の処理をしやすくするため、「前方上半身」「前方下半身」「後ろ」などを定義した列挙型を作成します。

public enum DamagePosition
{
    FrontUpperBody = 1,
    FrontLowerBody = 2,
    Back = 3,
    Other = 99
}

今回はこの4つですが、より厳密にダメージ位置を分けたいゲームではもっと要るかと思うので、必要に応じて追加しましょう。

攻撃判定用クラスでの処理

ダメージを与える側の関数のOnTriggerEnter()内でCollider.ClosestPoint()を使い、プレイヤーキャラとの位置に応じてどの列挙型に相当するか判定します。
ちょっとコードが長くなるので専用の関数を作ってみました。

/// <summary>
/// ダメージ発生位置の算出
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
protected DamagePosition CalcDamagePosition(Collider c)
{
    // 大まかな衝突位置を取得
    Vector3 collisionPoint = c.ClosestPoint(transform.position);

    // キャラクター正面から見た衝突位置の角度を取得
    Vector3 diff = transform.position - c.transform.position;
    Vector3 axis = Vector3.Cross(c.transform.forward, diff);
    float angle = Vector3.Angle(c.transform.forward, diff) * (axis.y < 0 ? -1 : 1);

    // 角度が前方90度以内か判定
    if (Mathf.Abs(angle) <= 90f) {
        // 衝突位置とキャラクターの高さ比較
        if (collisionPoint.y <= c.transform.position.y) {
            return DamagePosition.FrontUpperBody;
        } else {
            return DamagePosition.FrontLowerBody;
        }
    } else {
        return DamagePosition.Back;
    }
}

「キャラクター正面から見た衝突位置の角度を取得」が大変厳しい…というか全然分からなかったので他のサイト様に頼りまくりでした。
私の数学力は中学校の「連立方程式」で挫折したくらいへっぽこなので、そのツケがこういうとこで出てきてしまいます。趣味でやっているから許されるもので、とても仕事にはできないと改めて思う次第です。

ダメージ時の処理

先ほど算出した列挙型でどのダメージモーションを再生するか判定します。こちらも専用の関数を通すようにしました。

/// <summary>
/// ダメージモーションの再生
/// </summary>
protected void DoDamageMotion(DamagePosition damagePosition)
{
    switch (damagePosition) {
        case DamagePosition.FrontUpperBody:
            animator.Play("UpperDamage");
            break;

        case DamagePosition.FrontLowerBody:
            animator.Play("LowerDamage");
            break;

        case DamagePosition.Back:
            animator.Play("BackDamage");
            break;

        default:
            animator.Play("UpperDamage");
            break;
    }
}

単純なゲームであればAnimator.Play()でモーションを再生するだけです。
「背後からダメージを受けた場合は2倍のダメージになる」などをやりたい場合でも、上記関数のcase内で書けば事足りるかと思います。

down

コメントする