16歩目 アニメーションをつける! Unityで1日1ステップ!ノンフィールドRPG開発日記

1日1歩開発日記

ふりかえり

前回は、プレイヤーと敵の画像を設定し、ゲーム画面がぐっとにぎやかになりました!

キャラ画像にアニメーションをつける

今回は、プレイヤーと敵にアニメーションを実装して、ゲームに動きを加えていきます!

実装するアニメーションは以下のとおりです:

  • 攻撃時
  • ダメージを受けたとき
  • 倒されたとき
  • リスポーンしたとき
  • レベルアップ時

🔧アニメーションには「DOTween」を使用

今回のアニメーションには、Unityで有名なアセット**DOTween** を使用します。

DOTweenは簡単なコードで多彩なアニメーションが実現できる優れもの!

導入方法や基本的な使い方は次回の投稿で詳しく解説します。

DOTween (HOTween v2) | Animation Tools | Unity Asset Store
Use the DOTween (HOTween v2) tool from Demigiant on your next project. Find this & more animation tools on the Unity Ass...

スクリプトの実装:AnimationManager.cs

アニメーションを管理するためのスクリプトを作成します。

using UnityEngine;
using DG.Tweening; // DOTweenを使用するために追加

public class AnimationManager : MonoBehaviour
{
    public Transform playerTransform; // プレイヤーのTransform
    public Transform enemyTransform; // 敵のTransform
    public SpriteRenderer playerSpriteRenderer; // プレイヤーのSpriteRenderer
    public SpriteRenderer enemySpriteRenderer; // 敵のSpriteRenderer
    public float attackDuration = 0.5f; // 攻撃アニメーションの時間
    public float attackDistance = 0.5f; // 攻撃アニメーションの距離
    public float damageDuration = 0.3f; // ダメージアニメーションの時間
    public float shakeStrength = 1f; // シェイクの強さ
    public int shakeVibrato = 100; // シェイクの振動数
    public float fadeOutDuration = 1.0f; // フェードアウトの時間

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    // プレイヤーの攻撃アニメーション
    public void PlayerAttackAnimation()
    {
        if (playerTransform != null)
        {
            // プレイヤーを敵の方向に少し移動させる
            playerTransform.DOMove(playerTransform.position + Vector3.right * attackDistance, attackDuration / 2)
                .SetEase(Ease.OutQuad)
                .OnComplete(() =>
                {
                    // 元の位置に戻る
                    playerTransform.DOMove(playerTransform.position - Vector3.right * attackDistance, attackDuration / 2)
                        .SetEase(Ease.InQuad);
                });
        }
    }

    // 敵の攻撃アニメーション
    public void EnemyAttackAnimation()
    {
        if (enemyTransform != null)
        {
            // 敵をプレイヤーの方向に少し移動させる
            enemyTransform.DOMove(enemyTransform.position + Vector3.left * attackDistance, attackDuration / 2)
                .SetEase(Ease.OutQuad)
                .OnComplete(() =>
                {
                    // 元の位置に戻る
                    enemyTransform.DOMove(enemyTransform.position - Vector3.left * attackDistance, attackDuration / 2)
                        .SetEase(Ease.InQuad);
                });
        }
    }

    // プレイヤーのダメージアニメーション
    public void PlayerDamageAnimation()
    {
        if (playerTransform != null)
        {
            // プレイヤーをシェイクさせる
            playerTransform.DOShakePosition(damageDuration, shakeStrength, shakeVibrato)
                .SetEase(Ease.OutQuad);
        }
    }

    // 敵のダメージアニメーション
    public void EnemyDamageAnimation()
    {
        if (enemyTransform != null)
        {
            // 敵をシェイクさせる
            enemyTransform.DOShakePosition(damageDuration, shakeStrength, shakeVibrato)
                .SetEase(Ease.OutQuad);
        }
    }

    // プレイヤーのレベルアップアニメーション
    public void PlayerLevelUpAnimation()
    {
        if (playerTransform != null)
        {
            // プレイヤーを少し大きくしてから元に戻す
            playerTransform.DOScale(playerTransform.localScale * 2f, 0.3f)
                .SetEase(Ease.OutQuad)
                .OnComplete(() =>
                {
                    playerTransform.DOScale(playerTransform.localScale / 2f, 0.3f)
                        .SetEase(Ease.InQuad);
                });
        }
    }

    // プレイヤーの死亡アニメーション
    public void PlayerDeathAnimation()
    {
        if (playerSpriteRenderer != null)
        {
            // プレイヤーをフェードアウトさせる
            playerSpriteRenderer.DOFade(0f, fadeOutDuration)
                .SetEase(Ease.InQuad)
                .OnComplete(() =>
                {
                    Debug.Log("プレイヤーが消えました");
                });
        }
    }

    // 敵の死亡アニメーション
    public void EnemyDeathAnimation()
    {
        if (enemySpriteRenderer != null)
        {
            // 敵をフェードアウトさせる
            enemySpriteRenderer.DOFade(0f, fadeOutDuration)
                .SetEase(Ease.InQuad)
                .OnComplete(() =>
                {
                    Debug.Log("敵が消えました");
                });
        }
    }

    // プレイヤーの復活アニメーション
    public void PlayerReviveAnimation()
    {
        if (playerSpriteRenderer != null)
        {
            // プレイヤーをフェードインさせる
            playerSpriteRenderer.DOFade(1f, fadeOutDuration)
                .SetEase(Ease.OutQuad);
        }
    }

    // 敵の復活アニメーション
    public void EnemyReviveAnimation()
    {
        if (enemySpriteRenderer != null)
        {
            // 敵をフェードインさせる
            enemySpriteRenderer.DOFade(1f, fadeOutDuration)
                .SetEase(Ease.OutQuad);
        }
    }
}

プレイヤー・敵スクリプトの変更

PlayerManager.csにて:

  • 攻撃時:animationManager.PlayerAttackAnimation()
  • ダメージ時:PlayerDamageAnimation()
  • 死亡時:PlayerDeathAnimation()
  • 復活時:PlayerReviveAnimation()
  • レベルアップ時:PlayerLevelUpAnimation()

EnemyManager.csにて:

  • 攻撃時:EnemyAttackAnimation()
  • ダメージ時:EnemyDamageAnimation()
  • 死亡時:EnemyDeathAnimation()
  • 復活時:EnemyReviveAnimation()

必要なタイミングでアニメーション関数を呼び出すことで、よりリッチなバトル表現が可能になります!

using UnityEngine;

public class PlayerManager : MonoBehaviour
{
    public PlayerData player;
    public AnimationManager animationManager; // AnimationManagerの参照を追加

    void Start()
    {
        SpawnPlayer();
    }

    public void SpawnPlayer()
    {
        // 仮データで初期化
        player = new PlayerData
        {
            name = "勇者",
            level = 1,
            maxHP = 100,
            currentHP = 100,
            attack = 10,
            defense = 5,
            exp = 0,   // 初期経験値
            gold = 0,  // 初期お金
            expToNextLevel = 10 // 次のレベルに必要な経験値
        };

        Debug.Log($"{player.name}が作成されました。HP:{player.currentHP}/{player.maxHP}");
    }

    private void SpawnNewPlayer()
    {
        SpawnPlayer();

        if (animationManager != null)
        {
            animationManager.PlayerReviveAnimation();
        }
    }

    public void Attack(EnemyManager enemyManager)
    {
        // 攻撃アニメーションを再生
        if (animationManager != null)
        {
            animationManager.PlayerAttackAnimation();
        }

        int damage = Mathf.Max(0, player.attack - enemyManager.enemy.defense);
        enemyManager.TakeDamage(damage);

        Debug.Log($"{player.name}が{enemyManager.enemy.name}に{damage}ダメージ!");
    }

    public void TakeDamage(int damage)
    {
        // ダメージアニメーションを再生
        if (animationManager != null)
        {
            animationManager.PlayerDamageAnimation();
        }

        player.currentHP -= damage;
        if (player.currentHP <= 0)
        {
            player.currentHP = 0;
            Debug.Log($"{player.name}は倒された!");

            // 死亡アニメーションを再生
            if (animationManager != null)
            {
                animationManager.PlayerDeathAnimation();
            }

            Invoke("SpawnNewPlayer", 1.0f);
        }
    }

    public void GainRewards(int exp, int gold)
    {
        player.exp += exp;
        player.gold += gold;
        Debug.Log($"{player.name}は{exp}EXPと{gold}Gを獲得しました!");
        
        // レベルアップのチェック
        CheckLevelUp();
    }

    private void CheckLevelUp()
    {
        if (player.exp >= player.expToNextLevel)
        {
            LevelUp();
        }
    }

    private void LevelUp()
    {
        player.level++;
        player.maxHP += 20; // HPを20増加
        player.currentHP = player.maxHP; // HPを全回復
        player.attack += 5; // 攻撃力を5増加
        player.defense += 3; // 防御力を3増加
        player.expToNextLevel += 10; // 次のレベルに必要な経験値を10増加
        player.exp = 0; // 経験値をリセット

        // レベルアップアニメーションを再生
        if (animationManager != null)
        {
            animationManager.PlayerLevelUpAnimation();
        }

        Debug.Log($"{player.name}がレベルアップ!レベル{player.level}になりました!");
        Debug.Log($"HP: {player.maxHP}, 攻撃力: {player.attack}, 防御力: {player.defense}");
    }
}
using UnityEngine;

public class EnemyManager : MonoBehaviour
{
    public EnemyData enemy;
    public PlayerManager playerManager; // PlayerManagerの参照を追加
    public AnimationManager animationManager; // AnimationManagerの参照を追加

    private void Start()
    {
        SpawnEnemy(); // 初期の敵を生成
    }

    private void SpawnEnemy()
    {
        enemy = new EnemyData
        {
            name = "スライム",
            level = 1,
            maxHP = 50,
            currentHP = 50,
            attack = 8,
            defense = 2,
            expReward = 10, // 経験値報酬を設定
            goldReward = 5  // お金報酬を設定
        };

        Debug.Log($"{enemy.name} が出現しました。HP: {enemy.currentHP}/{enemy.maxHP}");
    }

    private void SpawnNewEnemy()
    {
        // 新しい敵を生成
        SpawnEnemy();
        
        // 復活アニメーションを再生
        if (animationManager != null)
        {
            animationManager.EnemyReviveAnimation();
        }
    }

    public void Attack(PlayerManager playerManager)
    {
        // 攻撃アニメーションを再生
        if (animationManager != null)
        {
            animationManager.EnemyAttackAnimation();
        }

        int damage = Mathf.Max(0, enemy.attack - playerManager.player.defense);
        playerManager.TakeDamage(damage);

        Debug.Log($"{enemy.name}が{playerManager.player.name}に{damage}ダメージ!");
    }

    public void TakeDamage(int damage)
    {
        // ダメージアニメーションを再生
        if (animationManager != null)
        {
            animationManager.EnemyDamageAnimation();
        }

        enemy.currentHP -= damage;
        if (enemy.currentHP <= 0)
        {
            enemy.currentHP = 0;
            Debug.Log($"{enemy.name}を倒した!");

            // 死亡アニメーションを再生
            if (animationManager != null)
            {
                animationManager.EnemyDeathAnimation();
            }
            
            // プレイヤーにEXPとGを与える
            if (playerManager != null)
            {
                playerManager.GainRewards(enemy.expReward, enemy.goldReward);
            }
            
            Invoke("SpawnNewEnemy", 1.0f); // 新しい敵を生成
        }
    }
}

Unityでの設定

  1. DOTweenの導入(※次回説明予定)
  2. Hierarchyで「Create Empty」からオブジェクトを作成し、  AnimationManager.cs をアタッチ
  3. Inspectorで以下を設定:
    • playerTransform → PlayerImageオブジェクト
    • enemyTransform → EnemyImageオブジェクト
    • playerSpriteRenderer / enemySpriteRenderer → 各SpriteRenderer
  4. PlayerManager・EnemyManagerにも AnimationManager をアサイン

動作確認

ゲームを開始して「Player Attack」ボタンをクリックすると、

キャラクターが動いたり、ダメージアニメーションが表示されるようになります!

動きが加わると、一気にゲーム感がアップしますね!


まとめ

今回は、DOTweenを使ってキャラ画像にアニメーションを追加しました!

動きがあるだけで、ゲームのクオリティがぐっと高まります!


次回予告

次回は、効果音(SE)の実装に挑戦します!

アニメーションと音が組み合わさると、さらに臨場感が出てきますよ!

お楽しみに!

コメント

タイトルとURLをコピーしました