この講座はロックマン風2Dアクションの作り方講座の第8回です。
前回はショットや敵キャラクターや被弾処理などの戦闘システムの実装を開始しました。
前回の記事:
今回は様々な行動パターンを持つザコ敵を増やしていきます。多くの種類の敵を作成してステージにバリエーションを持たせられるようにしましょう!
作る敵の種類は以下の通り。
- ヘビ(Snake) プレイヤーが近づくと加速する
- オオカミ(Wolf) 壁にぶつかると方向転換
- カエル(Frog) プレイヤーの方を向き前方にジャンプする
- ハチ(Bee) 空中で上下に往復移動する
- カラス(Crow) 空中で横向き移動
- サカナ(fish) 水中を移動
- サソリ(Scorpion) 横方向に飛び道具で攻撃
全エネミー共通クラスの拡張 敵被弾・被撃破処理の実装
前回扱ったDOTweenを用いて敵が撃破された時の処理を共通クラス内に書きこんでいきます。
EnemyBase.csを修正
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using DG.Tweening; /// <summary> /// 全エネミー共通処理クラス /// </summary> public class EnemyBase : MonoBehaviour { // オブジェクト・コンポーネント [HideInInspector] public AreaManager areaManager; // エリアマネージャ protected Rigidbody2D rigidbody2D; // RigidBody2D protected SpriteRenderer spriteRenderer;// 敵スプライト protected Transform actorTransform; // 主人公(アクター)のTransform // 画像素材 public Sprite sprite_Defeat; // 被撃破時スプライト(あれば) // 各種変数 // 基礎データ(インスペクタから入力) [Header ("最大体力(初期体力)")] public int maxHP; [Header ("接触時アクターへのダメージ")] public int touchDamage; [Header ("ボス敵フラグ(ONでボス敵として扱う。1ステージに1体のみ)")] public bool isBoss; // その他データ [HideInInspector] public int nowHP; // 残りHP [HideInInspector] public bool isVanishing; // 消滅中フラグ trueで消滅中である [HideInInspector] public bool isInvis; // 無敵モード [HideInInspector] public bool rightFacing; // 右向きフラグ(falseで左向き) // DoTween用 private Tween damageTween; // 被ダメージ時演出Tween // 定数定義 private readonly Color COL_DEFAULT = new Color (1.0f, 1.0f, 1.0f, 1.0f); // 通常時カラー private readonly Color COL_DAMAGED = new Color (1.0f, 0.1f, 0.1f, 1.0f); // 被ダメージ時カラー private const float KNOCKBACK_X = 1.8f; // 被ダメージ時ノックバック力(x方向) private const float KNOCKBACK_Y = 0.3f; // 被ダメージ時ノックバック力(y方向) // 初期化関数(AreaManager.csから呼出) public void Init (AreaManager _areaManager) { // 参照取得 areaManager = _areaManager; actorTransform = areaManager.stageManager.actorController.transform; rigidbody2D = GetComponent<Rigidbody2D> (); spriteRenderer = GetComponent<SpriteRenderer> (); // 変数初期化 rigidbody2D.freezeRotation = true; nowHP = maxHP; if (transform.localScale.x > 0.0f) rightFacing = true; // エリアがアクティブになるまで何も処理せず待機 gameObject.SetActive (false); } /// <summary> /// このモンスターの居るエリアにアクターが進入した時の処理(エリアアクティブ化時処理) /// </summary> public virtual void OnAreaActivated () { // このモンスターをアクティブ化 gameObject.SetActive (true); } /// <summary> /// ダメージを受ける際に呼び出される /// </summary> /// <param name="damage">ダメージ量</param> /// <returns>ダメージ成功フラグ trueで成功</returns> public bool Damaged (int damage) { // ダメージ処理 nowHP -= damage; if (nowHP <= 0) {// HP0の場合 // 被ダメージTween初期化 if (damageTween != null) damageTween.Kill (); damageTween = null; // 消滅中フラグをセット isVanishing = true; // 消滅中は物理演算なし rigidbody2D.velocity = Vector2.zero; rigidbody2D.bodyType = RigidbodyType2D.Kinematic; // 点滅後に消滅処理を呼び出す(DoTween使用) spriteRenderer.DOFade (0.0f, 0.15f) // 0.15秒*ループ回数分の再生時間 .SetEase (Ease.Linear) // 変化の仕方を指定 .SetLoops (7, LoopType.Yoyo) // 7回ループ再生(偶数回は逆再生) .OnComplete (Vanish); // 再生が終わったらVanish()を呼び出す設定 // 被撃破時スプライトがあれば表示 if (sprite_Defeat != null) spriteRenderer.sprite = sprite_Defeat; // その他撃破時処理 if (isBoss) {// ボス撃破時 } else {// ザコ撃破時 } } else {// まだHPが残っている場合 // 被ダメージTween初期化 if (damageTween != null) damageTween.Kill (); damageTween = null; // 被ダメージ演出再生 // (一瞬だけスプライトを赤色に変更する) if (!isInvis) { spriteRenderer.color = COL_DAMAGED; // 赤色に変更 damageTween = spriteRenderer.DOColor (COL_DEFAULT, 1.0f); // DoTweenで徐々に戻す } } return true; } /// <summary> /// エネミーが消滅する際に呼び出される /// </summary> private void Vanish () { // オブジェクト消滅 Destroy (gameObject); } /// <summary> /// アクターに接触ダメージを与える処理 /// </summary> public void BodyAttack (GameObject actorObj) { // 自身が消滅中なら無効 if (isVanishing) return; // アクターのコンポーネントを取得 ActorController actorCtrl = actorObj.GetComponent<ActorController> (); if (actorCtrl == null) return; // アクターに接触ダメージを与える actorCtrl.Damaged (touchDamage); } /// <summary> /// オブジェクトの向きを左右で決定する /// </summary> /// <param name="isRight">右向きフラグ</param> public void SetFacingRight (bool isRight) { if (!isRight) {// 左向き // スプライトを通常の向きで表示 spriteRenderer.flipX = false; // 右向きフラグoff rightFacing = false; } else {// 右向き // スプライトを左右反転した向きで表示 spriteRenderer.flipX = true; // 右向きフラグon rightFacing = true; } } } |
- ボス敵の実装に備えてisBossパラメータを増やしましたが、今章では使用しません(全てのザコ敵でオフ)。
- sprite_Defeatパラメータに画像をセットすると撃破時にこの画像を表示するようになります。省略可(未セット=nullならその処理を省く)。
被弾時のアニメーションをDOColorで、被撃破時の点滅をDOFadeのループで実装しています。
TweenにおいてOnCompleteオプションを付与する事で、再生完了のタイミングで任意のメソッドを呼び出せるようになります。
この後各種ザコ敵の動作の制作に入っていきますが、BodyAttackColliderオブジェクトについては全ての敵にそれぞれ子オブジェクトとして付加するのでプレハブ化しておきましょう。
ザコ敵1:ヘビ(Snake) プレイヤーが近づくと加速する
前回作成したEnemy_Snakeクラスを拡張し、まずはヘビの動作を完成させていきます。
- 普段は地上で静止している
- アクターが近づくと自身もアクターに向かって移動開始(加速)
- アクターが離れると減速して静止する
Enemy_Snake.csを修正
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 個別敵クラス:Snake /// /// アクターが近くにいると接近する /// 攻撃してこないが体当たりはしてくる /// </summary> public class Enemy_Snake : EnemyBase { // 設定項目 [Header ("移動速度")] public float movingSpeed; [Header ("最大移動速度")] public float maxSpeed; [Header ("移動条件(アクターとの距離がこの値以下なら移動)")] public float awakeDistance; [Header ("非移動時減速率")] public float brakeRatio; // 各種変数 private bool isBreaking; // ブレーキ作動フラグ trueで減速する /// <summary> /// このモンスターの居るエリアにアクターが進入した時の起動時処理(エリアアクティブ化時処理) /// </summary> public override void OnAreaActivated () { // 元々の起動時処理を実行 base.OnAreaActivated (); } // Update void Update() { // 消滅中なら処理しない if (isVanishing) return; // アクターが近くにいると接近する処理 float speed = 0.0f; // x方向移動速度 Vector2 ePos = transform.position; // エネミー座標 Vector2 aPos = actorTransform.position; // アクター座標 // アクターとの距離が離れている場合はブレーキフラグを立て終了(移動しない) if (Vector2.Distance (ePos, aPos) > awakeDistance) { isBreaking = true; return; } isBreaking = false; // 離れてないならブレーキフラグfalse // アクターとの位置関係から向きを決定 if (ePos.x > aPos.x) {// 左向き speed = -movingSpeed; SetFacingRight (false); } else {// 右向き speed = movingSpeed; SetFacingRight (true); } // 移動処理 Vector2 vec = rigidbody2D.velocity; // 速度ベクトル vec.x += speed * Time.deltaTime; // x方向の速度の最大値を設定 if (vec.x > 0.0f) // 右方向 vec.x = Mathf.Clamp (vec.x, 0.0f, maxSpeed); else // 左方向 vec.x = Mathf.Clamp (vec.x, -maxSpeed, 0.0f); // 速度ベクトルをセット rigidbody2D.velocity = vec; } // FixedUpdate void FixedUpdate () { // アクターが近くに居ない時のブレーキ処理 if (isBreaking) { Vector2 vec = rigidbody2D.velocity; // エネミー速度 vec.x *= brakeRatio; // x方向のみ減速 rigidbody2D.velocity = vec; } } } |
テストプレイしながらの調整を行いやすくするため、移動速度などのパラメータはInspectorから指定する形をとっています。
講座では以下のような設定にしておりますので、困った方は参考にしてみてください。
おおむね以下のような挙動になっていれば成功です。
ザコ敵:ヘビが完成したらプレハブ化します。Assets/Prefabs以下にEnemyフォルダを作り、その中に格納すると良いでしょう。また、Scriptsフォルダ以下にもEnemyフォルダを作りEnemy関連のスクリプトをまとめて格納しておくと良いでしょう。
プレハブ化出来たらシーン上から次のザコ敵制作で使いまわせるように右クリック→[Prefab]→[Unpack]を選択してプレハブとの繋がりを解除しておくと良いでしょう。
ちなみにInspectorビュー上の各コンポーネント名右側にある縦の[…]マークをクリックし、[Remove Component]を押下するとそのコンポーネントを取り外せます。「オブジェクトは使いまわすけどこのコンポーネントはいらない」という時に使えるので覚えておきましょう。
以降、新しい敵キャラを作成した後は
- 完成した敵オブジェクトをプレハブ化して保存
- プレハブをアンパック
- Enemy_○○オブジェクトの名前を変更
- スクリプトを新しく作成したものに付け替え
- インスペクターの数値とSpriteの変更&コライダーの大きさを自動調整
- 動作テスト
このような流れでザコ敵を1体ずつ実装します。最後まで一緒に制作していきましょう。
ザコ敵2:オオカミ(Wolf) 壁にぶつかると方向転換
まずは先ほどUnpackしたEnemy_Snakeのオブジェクト名をEnemy_Wolfに変更します。そしてEnemy_SnakeコンポーネントをRemoveしておきましょう。このオブジェクトを次は新しいザコ敵Enemy_Wolfに作り替えていきます。
今回用いるサンプル画像:Textures/Enemies/wolf1.png~wolf5.png
行動パターン
- 地上を直進する
- 壁にぶつかると方向を反転して直進する
Enemy_Wolfクラスを作成し、Enemy_Wolfオブジェクトにアタッチします。
まとめ
(↑7種類のザコ敵を配置してみました。倍速です)
以上で7種類のザコ敵の作成を完了しました。一通りの流れを覚え、余裕が出てきたらぜひあなたオリジナルの敵の作成にもチャレンジしてみてください!
次回はステージ上に配置できる各種障害物(ギミック)を順番に作成していきます。これでバリエーション豊かなステージを作れるようになります!引き続き開発がんばっていきましょう。
次の記事:
コメント