2DアクションUnityゲームの作り方メモ

【Unity】2DアクションRPGの作り方④!敵の配置&攻撃システム編

2Dアクション

1. はじめに

Unityで2DアクションRPGを作るうえで、敵キャラの動作 は欠かせません。今回の記事では、敵の配置・移動・追跡AI・攻撃処理 を実装していきます!🎮✨

前回(パート3)では、HPバーの作成やカメラの追従設定 を行いました。今回は、プレイヤーが戦う相手となる 敵キャラの動作 を追加して、ゲームらしくしていきます!

この記事で学べること ✅ 敵をフィールドに配置する方法
✅ 敵をランダムに移動させる方法
✅ 敵がプレイヤーを追跡するAIを実装
✅ 敵とプレイヤーの攻撃処理

完成イメージ

  • 敵はエリア内をランダムに移動
  • プレイヤーが近づくと追跡を開始
  • 接触するとプレイヤーにダメージ
  • プレイヤーの攻撃が当たると敵がダメージを受ける

これらを実装すると、より アクションRPGらしい戦闘システム になっていきます!💥
それでは、さっそく 敵キャラの配置 から始めていきましょう!🚀




2. 敵の作成

ゲームを面白くするためには、プレイヤーだけでなく敵キャラの動きも重要です。このステップでは、敵キャラの配置、アニメーション設定、基本的な移動処理の準備 を行います。


2.1 敵の基本設定

まずは、敵の基本となるオブジェクトを作成し、アニメーションを設定していきます。

① 敵キャラのオブジェクトを作成

  1. Hierarchy ウィンドウで Create Empty を選択し、新しいオブジェクトを作成します。
  2. 名前を Enemy に変更します。
  3. Enemy を選択し、InspectorTagEnemy に設定します。

② 敵のアニメーションを作成

敵キャラのアニメーションは、待機(Idle)と移動(Move) の2種類を用意します。

  1. Sprite Renderer を追加
    • Enemy を選択し、Add Component から Sprite Renderer を追加。
    • 立ち絵となるスプライトを Sprite に設定。
  2. Animator を設定
    • Add Component から Animator を追加。
    • Animation ウィンドウを開き、新しいアニメーションを作成。
    • CreateNew Clip から Idle(待機)Move(移動) のアニメーションを作成。
  3. アニメーションの登録
    • Idle には停止しているときのアニメーションを設定。
    • Move には動いているときのアニメーションを設定。

2.2 敵の基本コンポーネントを追加

次に、敵キャラが物理演算に対応し、プレイヤーと衝突できるようにします。

  1. BoxCollider2D を追加
    • Add Component から BoxCollider2D を追加し、サイズを調整。
    • これにより、敵キャラとプレイヤーが当たり判定を持つようになります。
  2. Rigidbody2D を追加
    • Add Component から Rigidbody2D を追加。
    • Gravity Scale0 に設定(重力の影響を受けないように)。
    • Freeze Rotation (Z) にチェックを入れる(回転しないように固定)。

2.3 敵のアニメーション制御

敵の IdleMove のアニメーションを切り替えるために、Animator の設定を行います。

  1. Animator を開く
    • WindowAnimationAnimator を開く。
  2. パラメーターを追加
    • Parameters タブで + ボタンをクリックし、Bool 型のパラメーターを作成。
    • 名前を Moving にする。
  3. アニメーションの遷移を設定
    • Idle から Move へ矢印(遷移)を追加。
    • Move から Idle へ矢印(遷移)を追加。
  4. 遷移の条件を設定
    • Idle → Move の矢印を選択し、ConditionsMoving = true を追加。
    • Move → Idle の矢印を選択し、ConditionsMoving = false を追加。
  5. 遷移のスムーズ化
    • Idle → MoveTransition Duration0 に設定。
    • Move → IdleExit Time0 にし、Transition Duration0 に設定。

2.4 動作確認

ここまでの設定が正しく反映されているか確認しましょう。

  1. ゲームを再生
    • Enemy が正しく表示されるか確認。
    • Animator を開き、Moving の値を手動で変更して IdleMove が正しく切り替わるかチェック。

このステップでは、敵キャラの配置と基本的なアニメーションの設定 を行いました。次のステップでは、敵がエリア内を徘徊するようにし、プレイヤーを追跡する動きを追加していきます!🔥




3. 敵の移動範囲を設定

敵キャラが無制限に移動してしまうと、マップの外に出たり、予期しない場所へ移動してしまうことがあります。そこで、敵が移動できる範囲を限定する「移動エリア」を作成 し、その範囲内で自由に動くように設定します。


3.1 敵の移動エリアを作成

まず、敵が移動できる範囲(エリア) を決めるために、BoxCollider2D を利用して移動可能エリアを定義 します。

① エリア用の空オブジェクトを作成

  1. Hierarchy ウィンドウを開く。
  2. 右クリック → Create Empty を選択し、新しい空オブジェクトを作成。
  3. 名前を「Area」に変更 する。
  4. InspectorTransformPosition(0, 0, 0) にリセット。

② BoxCollider2D を追加

  1. Area を選択した状態で、InspectorAdd Component ボタンをクリック。
  2. BoxCollider2D を追加。
  3. Size を変更し、敵が動き回る範囲を適切なサイズに調整。
    • エリアが狭すぎると敵が動けなくなるため、少し余裕を持たせるのがポイント!
  4. Is Trigger のチェックは外したまま にする。

3.2 敵をエリア内でランダム移動させる

敵が移動エリアから出ないように、移動範囲を BoxCollider2D の中に限定 します。
これを実現するために、EnemyController スクリプトに移動処理を追加します。

① スクリプトを作成

  1. Project ウィンドウで CreateC# Script を選択。
  2. 名前を EnemyController に変更。
  3. 作成したスクリプトを Enemy にドラッグ&ドロップしてアタッチ。

② スクリプトのコード

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

public class EnemyControler : MonoBehaviour
{

    private Rigidbody2D rb;
    private Animator enemyAnim;

    [SerializeField]
    private float moveSpeed, waitTime, walkTime;

    private float waitCountor, moveCounter;

    private Vector2 moveDir;

    [SerializeField]
    private BoxCollider2D area;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        enemyAnim = GetComponent<Animator>();

        waitCountor = waitTime;
    }

    void Update()
    {

        if (waitCountor > 0)
        {

            waitCountor -= Time.deltaTime;
            rb.velocity = Vector2.zero;

            if (waitCountor <= 0)
            {
                moveCounter = walkTime;

                enemyAnim.SetBool("Moving", true);

                moveDir = new Vector2(Random.Range(-1f, 1f), Random.Range(-1f, 1f));
                moveDir.Normalize();

            }
        }
        else 
        {
            moveCounter -= Time.deltaTime;

            rb.velocity = moveDir* moveSpeed;

            if (moveCounter <= 0)
            {
                enemyAnim.SetBool("Moving", false);

                waitCountor = waitTime;

            }
        
        }

        //エリア内しか動けないようにする
        transform.position = new Vector3(Mathf.Clamp(transform.position.x, area.bounds.min.x + 1, area.bounds.max.x-1),
            Mathf.Clamp(transform.position.y, area.bounds.min.y + 1, area.bounds.max.y - 1),transform.position.z);

    }
}

3.3 各パラメータの設定

スクリプトを適用したら、敵の移動設定をカスタマイズ します。

EnemyControllerInspector でパラメータを調整

項目説明
Move Speed移動速度3
Wait Time待機時間(動かない時間)2
Walk Time移動時間(動く時間)2
Area移動範囲の BoxCollider2DArea を設定

AreaEnemyController に紐づけ

  1. EnemyInspectorEnemyControllerArea フィールドを探す。
  2. Hierarchy から AreaEnemyControllerArea にドラッグ&ドロップ。

3.4 動作確認

  1. ゲームを再生 し、敵がランダムに動くことを確認。
  2. 敵がエリア外に出ないかチェック!
    • もし敵が外に出てしまう場合は、BoxCollider2D のサイズを見直す。

3.5 エリアのサイズを動的に変更する方法(応用編)

もしエリアの大きさをスクリプトで動的に設定したい場合、Start()BoxCollider2D のサイズを取得して制限できます。

void Start()
{
rb = GetComponent<Rigidbody2D>();
enemyAnim = GetComponent<Animator>();

waitCounter = waitTime;

// エリアのサイズを自動取得
if (area != null)
{
float minX = area.bounds.min.x + 1;
float maxX = area.bounds.max.x - 1;
float minY = area.bounds.min.y + 1;
float maxY = area.bounds.max.y - 1;

transform.position = new Vector3(Random.Range(minX, maxX), Random.Range(minY, maxY), transform.position.z);
}
}

この処理を追加すると、敵が必ずエリア内のランダムな位置にスポーン するようになります!


3.6 まとめ

  • 「Area」オブジェクトを作成し、BoxCollider2D で移動エリアを定義。
  • 敵がエリア内をランダムに移動するようにスクリプトを作成。
  • Clamp() を使って、敵がエリア外へ出ないように制限。
  • Inspector から移動速度や待機時間をカスタマイズ可能に!

これで、敵がエリアの外に出ることなく、適切な範囲内で動き回るAIが完成 しました!
次のステップでは、敵がプレイヤーを追跡するAI を実装していきます!🔥




4. 敵がプレイヤーを追跡する

敵キャラがエリア内を移動するだけでは物足りませんよね?
そこで、今回は 敵がプレイヤーを追跡するAI を実装します!

プレイヤーが一定範囲に入ると、敵が追いかけてきて、距離が離れると再び徘徊を開始するようにします。


4.1 プレイヤーのタグを設定

敵がプレイヤーを認識できるように、プレイヤーに “Player” タグ を設定しておきます。

  1. HierarchyPlayer を選択
  2. InspectorTagPlayer に変更(もし “Player” がなければ Add Tag から追加)

4.2 敵の追跡処理を追加

  1. EnemyController に以下の変数を追加します。
[SerializeField]
private bool chase; // 追跡モードのON/OFF

private bool isChasing; // 追跡中かどうか

[SerializeField]
private float chaseSpeed, rangeToChase; // 追跡速度と追跡範囲

private Transform target; // 追跡するプレイヤーの位置

[SerializeField]
private float waitAfterHitting; // 攻撃後の待機時間

[SerializeField]
private int attackDamage; // 敵の攻撃力
  1. Start() メソッドでプレイヤーを探してターゲットとして設定します。
void Start()
{
target = GameObject.FindGameObjectWithTag("Player").transform;
}

4.3 追跡ロジックの実装

敵は プレイヤーとの距離をチェックし、範囲内なら追跡を開始 します。

  1. 敵が通常のランダム移動をしている状態
    • isChasing = false のときは、ランダムな方向に移動する
    • rangeToChase の範囲内にプレイヤーを検知すると isChasing = true に変更し、追跡開始
void Update()
{
if (!isChasing)
{
if (waitCountor > 0)
{
waitCountor -= Time.deltaTime;
rb.velocity = Vector2.zero;

if (waitCountor <= 0)
{
moveCounter = walkTime;
enemyAnim.SetBool("Moving", true);
moveDir = new Vector2(Random.Range(-1f, 1f), Random.Range(-1f, 1f));
moveDir.Normalize();
}
}
else
{
moveCounter -= Time.deltaTime;
rb.velocity = moveDir * moveSpeed;

if (moveCounter <= 0)
{
enemyAnim.SetBool("Moving", false);
waitCountor = waitTime;
}
}

// プレイヤーが追跡範囲内に入ったら追跡開始
if (chase)
{
if (Vector3.Distance(transform.position, target.position) < rangeToChase)
{
isChasing = true;
}
}
}
  1. プレイヤーを追跡している状態
    • isChasing = true の場合、プレイヤーの方向を向いて移動
    • rangeToChase 以上にプレイヤーが離れたら、追跡をやめて通常の移動に戻る
   else 
{
if (waitCountor > 0)
{
waitCountor -= Time.deltaTime;
rb.velocity = Vector2.zero;

if (waitCountor <= 0)
{
enemyAnim.SetBool("Moving", true);
}
}
else
{
moveDir = target.position - transform.position;
moveDir.Normalize();
rb.velocity = moveDir * chaseSpeed;
}

// プレイヤーが追跡範囲外に出たら追跡をやめる
if (Vector3.Distance(transform.position, target.position) > rangeToChase)
{
isChasing = false;
waitCountor = waitTime;
enemyAnim.SetBool("Moving", false);
}
}

4.4 敵がエリア内でのみ移動するように制限

このままだと、敵がマップの外まで行ってしまうことがあります。
そこで、敵の transform.positionエリアの範囲内に制限 しましょう。

// エリア外に出ないように制限
transform.position = new Vector3(
Mathf.Clamp(transform.position.x, area.bounds.min.x + 1, area.bounds.max.x - 1),
Mathf.Clamp(transform.position.y, area.bounds.min.y + 1, area.bounds.max.y - 1),
transform.position.z
);

4.5 インスペクターでの設定

スクリプトを Enemy にアタッチしたら、Inspector でパラメータを設定しましょう。

項目設定値(例)
Chase✅(チェックを入れると追跡ON)
Chase Speed2.0
Range To Chase5.0
Wait After Hitting1.0
Attack Damage10

4.6 動作確認

  1. プレイヤーが近づくと敵が追いかけてくる
  2. 距離が離れると敵が追跡をやめてランダム移動に戻る
  3. エリアの外には出ない

これで、敵がプレイヤーを追跡するようになりました!
次は、敵がプレイヤーに攻撃できるようにする 仕組みを作っていきます!💥🔥




5. 敵とプレイヤーの攻撃システム

この記事では、敵とプレイヤーの戦闘システムを実装 します!

  • 敵にぶつかるとダメージを受けてノックバック
  • プレイヤーの剣で敵を攻撃
  • 敵のHPがゼロになると消滅

この流れをスクリプトで作成していきましょう。


5.1 プレイヤーがダメージを受ける&ノックバック処理

敵にぶつかったときに、プレイヤーがダメージを受けてノックバックするようにします。

① PlayerController にノックバック処理を追加

  1. PlayerController スクリプトを開き、以下のコードを追加します。
private bool isKnockingBack;
private Vector2 knockDir;

[SerializeField]
private float knockbackTime, knockbackForce;
private float knockbackCounter;

[SerializeField]
private float invincibilityTime;
private float invincibilityCounter;

void Update()
{
// 無敵時間をカウントダウン
if (invincibilityCounter > 0)
{
invincibilityCounter -= Time.deltaTime;
}

// ノックバック中の処理
if (isKnockingBack)
{
knockbackCounter -= Time.deltaTime;
rb.velocity = knockDir * knockbackForce;

if (knockbackCounter <= 0)
{
isKnockingBack = false;
}
else
{
return;
}
}
}

// ノックバックの処理
public void KnockBack(Vector3 position)
{
knockbackCounter = knockbackTime;
isKnockingBack = true;

knockDir = transform.position - position;
knockDir.Normalize();
}

// ダメージを受ける処理
public void DamagePlayer(int damage)
{
if (invincibilityCounter <= 0)
{
CurrentHealth = Mathf.Clamp(CurrentHealth - damage, 0, MaxHealth);
invincibilityCounter = invincibilityTime;

if (CurrentHealth == 0)
{
gameObject.SetActive(false);
}
}

// HPバーを更新
GameManager.instance.UpdateHealthUI();
}

② エディタでパラメータを設定

  • knockbackTime0.2
  • knockbackForce30
  • invincibilityTime0.5

5.2 敵がプレイヤーにダメージを与える

次に、敵がプレイヤーにぶつかったときにダメージを与える処理 を追加します。

① EnemyController にダメージ処理を追加

  1. EnemyController スクリプトを開き、以下のコードを追加します。
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Player")
{
if (isChasing)
{
PlayerController player = collision.gameObject.GetComponent<PlayerController>();

// プレイヤーにノックバック&ダメージを与える
player.KnockBack(transform.position);
player.DamagePlayer(attackDamage);

waitCountor = waitAfterHitting;
enemyAnim.SetBool("Moving", false);
}
}
}

これで、敵がプレイヤーに当たると ノックバックしてHPが減る 仕様になりました!


5.3 プレイヤーの攻撃処理

次に、プレイヤーの剣で 敵を攻撃できるようにする 仕組みを作ります。

① 剣にコライダーを追加

  1. SwordPolygonCollider2D を追加。
  2. IsTrigger にチェックを入れる。
  3. コライダーのサイズを剣の大きさに調整

② 敵のタグを作成

  1. InspectorTagAdd Tag をクリック。
  2. Enemy タグを作成し、Enemy オブジェクトに設定。

5.4 剣のスクリプトを作成

  1. 新しい C# スクリプト Weapon.cs を作成 し、以下のコードを記述します。
using UnityEngine;

public class Weapon : MonoBehaviour
{
[SerializeField]
private int attackDamage;

private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Enemy")
{
collision.gameObject.GetComponent<EnemyController>().TakeDamage(attackDamage, transform.position);
}
}
}
  1. Weapon スクリプトを Sword にアタッチ。

5.5 敵のダメージ処理

敵がプレイヤーの攻撃を受けると、ダメージを受けてノックバックするようにします。

① EnemyController にダメージ処理を追加

  1. EnemyController スクリプトに以下のコードを追加します。
[SerializeField]
private int currentHealth;
private bool isKnockingBack;

[SerializeField]
private float knockBackTime, knockBackForce;
private float knockBackCounter;
private Vector2 knockDir;

void Update()
{
if (isKnockingBack)
{
if (knockBackCounter > 0)
{
knockBackCounter -= Time.deltaTime;
rb.velocity = knockDir * knockBackForce;
}
else
{
rb.velocity = Vector2.zero;
isKnockingBack = false;
}
return;
}
}

// ノックバック処理
public void KnockBack(Vector3 position)
{
isKnockingBack = true;
knockBackCounter = knockBackTime;

knockDir = transform.position - position;
knockDir.Normalize();

enemyAnim.SetBool("Moving", false);
}

// ダメージを受ける処理
public void TakeDamage(int damage, Vector3 position)
{
currentHealth -= damage;

if (currentHealth <= 0)
{
Destroy(gameObject);
}

KnockBack(position);
}

5.6 エディタでパラメータを設定

  1. PlayerControllerattackDamage を設定。
  2. EnemyControllercurrentHealth, knockBackTime, knockBackForce を設定。

5.7 動作確認

敵に剣が当たるとダメージを受ける!
敵が倒れると消滅!
敵にぶつかるとプレイヤーがダメージ&ノックバック!

これで、プレイヤーと敵の基本的な攻撃&ダメージ処理が完成しました!🎮✨




6. まとめ

この記事では、敵キャラの配置、移動AI、プレイヤーとの戦闘システム を実装しました。
これにより、プレイヤーが探索中に敵と遭遇し、戦闘できるようになりました!🎮✨

① 敵の配置と移動

  • Enemy オブジェクトを作成し、プレイヤーと同様にアニメーション(Idle / Move) を設定。
  • BoxCollider2DRigidbody2D を追加し、敵がゲーム内で動けるようにしました。
  • EnemyController スクリプトを作成し、ランダムに徘徊 するように実装。

② プレイヤーを追跡する敵AI

  • エリア内のみ移動 するように制御しつつ、プレイヤーが近づいたら追跡 する処理を追加。
  • Vector3.Distance() を使用し、プレイヤーとの距離が rangeToChase より短くなると追跡を開始。
  • 距離が離れると再びエリア内を徘徊 するように設定しました。

③ 敵とプレイヤーの戦闘

  • 敵がプレイヤーに衝突するとダメージを与え、ノックバック する処理を追加。
  • プレイヤーの攻撃(剣)を PolygonCollider2D で判定し、敵にダメージを与えられるようにしました。
  • 敵がダメージを受けるとノックバックし、HPが0になると消滅 するように実装。

④ 戦闘システムをさらに強化するなら?

手動でのAI作成も楽しいですが、もっと高度な戦闘システムを実装したい場合は、
TopDown Engine のようなアセットを活用するのもおすすめです!
このアセットを使うと、移動、攻撃、スキル、敵AI などのシステムを一括で管理でき、よりスムーズに開発できます。


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