趣味のゲーム開発 vol.24

今回からは、自分のゲームに必要な機能を制作していきたいと思います!
ちょっと楽しくなってきましたね〜。

とはいえ、いくつか懸念事項がありますね。

・キャラクターの横移動で、キーを離した時にピタッと止まらない
・スクリプトの整頓がしたい
・地面のカドで引っかかる
・ジャンプからジェットパックの挙動がしたい

あと、実装したい機能としてはこんなものですね。

・銃を打つ
・ヒットポイント制
・ポーズ機能
・HPのゲージ表示
・ダメージ表示
・装備の変更と見た目への反映
・ステージ選択
・お金
・必殺技

できればソースをきれいにしてから機能を追加していきたいですが、モチベーションが心配です。
そこで、シューティングゲームらしくするために、銃を打てるようにしたいと思います。

まずは弾の画像を準備。

画像1

次に、弾をコントロールするクラスを作成します。
この時点では、とりあえず横に進むようにします。
後々、進む方向や角度等を変更できるようにしたいです。

ちなみに、サンプルを以下のサイト様で参考にさせていただいたのですが

インスタンス生成の第3引数がよくわかりませんでした。
これはRotationを渡しているようです。
しかし、Unityではオイラー角ではなくクォータニオンという構造体で処理しているようです。
要勉強ですね・・・

今後、銃を変更できるようにすることを考えて、単独のメソッドにしておこうと思います。

・弾丸をコントロールするクラス:発射後の弾丸の操作のみ定義(速さ、射程、進み方)
・弾丸を生成するメソッド:弾丸インスタンスの生成を定義(フルオート、セミオート、発射角、装弾数)
  →こちらを後々独立させる予定
  →ひとまずプレイヤー操作クラスに定義

しかし、プレイヤーの向きに応じて弾丸の向きを変更しなければいけないので、
やはりクォータニオンについて理解しなければいけません。
現時点ではオイラー角のように使いたければ「Quaternion.Euler」をつかえば良いという理解です。

この時点でのソースは以下の感じです。

○弾丸コントロールクラス

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletController : MonoBehaviour
{
   [Header("弾丸の速度")] public float speed = 0.2f;
   [Header("射程距離")] public float range = 7.0f;
   private float limitPoint;
   private void Awake()
   {
       // 射程距離を計測するため、発射時点の座標を取得
       limitPoint = transform.position.x + range;
   }
   
   // Update is called once per frame
   void Update()
   {
       
       transform.Translate(speed, 0, 0);
       // 射程距離分進んだら消える
       if (transform.position.x >= limitPoint)
       {
           Destroy(gameObject);
       }
   }
}

○弾丸生成メソッド(プレイヤー操作クラスに記述)

/// <summary>
   /// 銃を打つ
   /// </summary>
   private void ShootGun()
   {
       bool isAutomatic = false; // 連射の可不可
       float shootAngle = 0.0f; // 発射角
       // プレイヤーの向きに応じて発射角を調整
       if (transform.localScale.x > 0)
       {
           // 右向き
           shootAngle = 0.0f;
       }
       else
       {
           // 左向き
           shootAngle = 180.0f;
       }
       if (isAutomatic)
       {
           // オートマティックの銃
           if (Input.GetKey(KeyCode.LeftCommand))
           {
               Instantiate(bullet, transform.position, Quaternion.Euler(0.0f, 0.0f, shootAngle));
               GManager.instance.PlaySE(shootSE);
           }
       }
       else
       {
           // 単発の銃
           if (Input.GetKeyDown(KeyCode.LeftCommand))
           {
               Instantiate(bullet, transform.position, Quaternion.Euler(0.0f, 0.0f, shootAngle));
               GManager.instance.PlaySE(shootSE);
           }
       }
   }

あとは、弾丸にあたり判定を付け、敵を倒せるようにすればOKです。
ColliderとRigidbodyを付け、IsTriggerをオンに。
あとはソースの方で衝突時に消してあげれば良さそうですね。

しかし、ここでどうあがいても弾が出てこなくなる問題が発生!
デバッグしてみた結果、Cinemachineに使っていた移動範囲指定用のコライダーに反応してしまっていました。

そこで、スクリプトの方でタグで判断して逃がすようにしました。
また、進行方向が左の場合、弾が消えなかったので、その点も修正しました。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletController : MonoBehaviour
{
   [Header("弾丸の速度")] public float speed = 0.2f;
   [Header("射程距離")] public float range = 7.0f;
   private string playerTag = "Player";
   private string cameraTag = "MainCamera";
   private string itemTag = "Item";
   private Vector2 startPos;
   
   private void Awake()
   {
       // 射程距離を計測するため、発射時点の座標を取得
       startPos = transform.position;
   }
   
   // Update is called once per frame
   void Update()
   {
       
       transform.Translate(speed, 0, 0);
       // 射程距離分進んだら消える
       if (Vector2.Distance(transform.position, startPos) >= range)
       {
           Destroy(this.gameObject);
       }
   }
   // 衝突判定
   private void OnTriggerEnter2D(Collider2D collision)
   {
       if(collision.tag != playerTag && collision.tag != cameraTag && collision.tag != itemTag)
       {
           Destroy(this.gameObject);
       }
   }
}

とりあえず、弾を撃って敵を倒す(現状正面に当てた時のみ)事はできました。
しかし、敵周りのスクリプトがごちゃついているので、整理したいですね。

次回はそこからですかね〜
ではまた!

この記事が気に入ったらサポートをしてみませんか?