Unityに関連する記事です

 前回に続き、プレイヤーの向きに応じて傾く直線上に弾を配置して発射する機能の学習を行います。


<確認動画 ーよいパターン(弾を配置している位置に傾きが反映されている)ー>
動画ファイルへのリンク


 上の傾きがないパターンの場合、弾の配置される位置が固定化されています。
そのため、横方向に弾を発射した場合、同じ位置に重なって発射される形になります。



 弾の数が増えた場合、配置する位置を延長する機能も実装しています。


動画ファイルへのリンク



 事前に前回の手順の実装が必要になります。

  => 【2D】プレイヤーの向きに応じて傾く直線上に弾を配置して発射する機能



スクリプトを作成する


 前回の手順で学習した処理を組み合わせて、1つのロジックを組み立てていきます。

 プレイヤーの向いている方向から傾きを求めて水平にし、そこに新しく、傾きを回転角度として作成する処理を加えます。

 その後、弾を生成する位置を傾かせた直線上に対して等間隔になるように弾の位置を計算し、回転角度を加えることで処理を完成させます。
各処理の上にも詳細に内容を記述してありますので、1つずつ、処理の内容をイメージしながら理解を深めていくようにしてください。



BulletGenerator3.cs

 <= クリックすると開きます。


 非常に多くの計算処理があり、ロジックを組み立てています。
なるべく詳細なコメントを補記してありますが、読むだけではわかりにくいと思います。

 各種の計算結果については、細かく Debug.Log メソッドを入れてログ表示してみましょう。
変数にどのような値が使われているかを知ることで、処理のイメージが作れます。

 むしろ最初のうちは、1行の処理につき、1つの Debug.Log を書いてもいいです。
ログを使って処理を可視化し、ソースコードと見比べながら、焦らずに学習しましょう。



 Debug.DrawRay メソッドによる直線の可視化については、この機能を利用するかしないかを設定するためのスイッチ役の変数を設けて、処理を分岐しています。
確認したいときだけ見れるようにすることで、処理の負荷を下げることが出来ます。

 これは bool 型の変数を活用し、デバッグ用のスイッチを用意している例となっています。

 このようなスイッチ用の変数を用意しておくことで、シーンビューで確認したいときだけスイッチを入れる、という方法が実装出来ます。
インスペクターでスイッチを切れば(チェックを外せば)いつでも処理を停止できますので、その都度、ソースコードを編集する必要はありません。

 このようなデバッグ用の処理は、デバッグモードとも言います。

 ちょっとした気遣いをすることで、効率的かつ、便利な機能が作れます。



参考サイト
Unity 公式スクリプト・リファレンス
Mathf.Atan2
Unity 公式スクリプト・リファレンス
Mathf.Deg2Rad
Unity 公式スクリプト・リファレンス
Mathf.Lerp
Qiita @NNNiNiNNN(n n) 様
【Unity】ベクトルを角度に変換する【Atan2関数】
エクスプラボ 様
【Unity】MathfのDeg2RadとRad2Degの使い方ってちょっと迷うよね
PG日誌 様
【Unity】Mathf.LerpとInverseLerpの覚書
夜中に Unity 様
【Unity】便利な数学関数の Mathf クラスまとめ【Clamp, Abs など】


ゲームを実行して動作を確認する


 リファクタリングになりますので、いままでと同じように動作していることを確認してください。





<確認動画>
動画ファイルへのリンク

動画ファイルへのリンク

動画ファイルへのリンク

検証  七彁蚕萢の流れー


 各処理について、Debug.Log メソッドを利用し、実数値を当てはめて処理の流れを読み解いていきましょう。



 まずは bulletLevel を2として、具体的な数値を使って計算してみましょう。
仮に以下の値を設定するとします。

bulletDistance = 10(直線の長さ)
bulletLevel = 2(弾の数)

 まず、currentBulletLine を計算します。

currentBulletLine = bulletDistance / 2 * bulletLevel
                  = 10 / 2 * 2
                  = 10

 このようにして、ソースコードに実数値を当てはめて、計算結果を算出していくことで処理が可視化できます。

 次に、t の値を計算します。
t は 0 から 1 までの範囲で変化する値で、弾同士の配置の比率を表します。

<i = 0 の場合>

t = 0 / (2 - 1)
  = 0


<i = 1 の場合>

t = 1 / (2 - 1)
  = 1

 i の値により、t の値が 0 から 1 まで変化することに注目してください。
つまり、計算の結果が変わってきている、ということになります。

 次に、angle の値を計算します。
angle は -currentBulletLine / 2 から currentBulletLine / 2 の範囲で変化し、これによって弾の位置が決まります。

<i = 0 の場合>

angle = Mathf.Lerp(-currentBulletLine / 2, currentBulletLine / 2, t)
      = Mathf.Lerp(-10 / 2, 10 / 2, 0)
      = Mathf.Lerp(-5, 5, 0)
      = -5


<i = 1 の場合>

angle = Mathf.Lerp(-currentBulletLine / 2, currentBulletLine / 2, t)
      = Mathf.Lerp(-10 / 2, 10 / 2, 1)
      = Mathf.Lerp(-5, 5, 1)
      = 5

 この計算によって、angle の値が -5 から 5 まで変化し、それぞれの弾の位置が決定されます。

 最後に、GenerateBullet メソッドに渡す distance を計算します。
これは angle と lineDirection の積です。


<i = 0 の場合>

distance = angle * lineDirection
         = -5 * (lineDirectionの値)

<i = 1 の場合>

distance = angle * lineDirection
         = 5 * (lineDirectionの値)

 このように、angle の値によって弾の位置が変化し、プレイヤーの向いている方向から等間隔で配置されることが確認できます。



 では同じようにして、bulletLevel を 3 として、具体的な数値を使って計算してみましょう。

 以下の値を設定するとします。

bulletDistance = 15(直線の長さ)
bulletLevel = 3(弾の数)

 まず、currentBulletLine を計算します:

currentBulletLine = bulletDistance / 2 * bulletLevel
                  = 15 / 2 * 3
                  = 7.5

 次に、t の値を計算します。
t は 0 から 1 までの範囲で変化する値で、弾同士の配置の比率を表します。


<i = 0 の場合>

t = 0 / (3 - 1)
  = 0


<i = 1 の場合>


t = 1 / (3 - 1)
  = 0.5


<i = 2 の場合>


t = 2 / (3 - 1)
  = 1

 t の値が 0 から 1 まで変化することに注意してください。

 次に、angle の値を計算します。
angle は -currentBulletLine / 2 から currentBulletLine / 2 の範囲で変化し、これによって弾の位置が決まります。

<i = 0 の場合>

angle = Mathf.Lerp(-currentBulletLine / 2, currentBulletLine / 2, t)
      = Mathf.Lerp(-7.5 / 2, 7.5 / 2, 0)
      = Mathf.Lerp(-3.75, 3.75, 0)
      = -3.75


<i = 1 の場合>

angle = Mathf.Lerp(-currentBulletLine / 2, currentBulletLine / 2, t)
      = Mathf.Lerp(-7.5 / 2, 7.5 / 2, 0.5)
      = Mathf.Lerp(-3.75, 3.75, 0.5)
      = 0


<i = 2 の場合>


angle = Mathf.Lerp(-currentBulletLine / 2, currentBulletLine / 2, t)
      = Mathf.Lerp(-7.5 / 2, 7.5 / 2, 1)
      = Mathf.Lerp(-3.75, 3.75, 1)
      = 3.75

 この計算によって、angle の値が -3.75 から 3.75 まで変化し、それぞれの弾の位置が決定されます。
先ほどの処理とは変化の範囲が変わりましたね。

 最後に、GenerateBullet メソッドに渡す distance を計算します。これは angle と lineDirection の積です。

<i = 0 の場合>

distance = angle * lineDirection
         = -3.75 * (lineDirectionの値)


<i = 1 の場合>

distance = angle * lineDirection
         = 0 * (lineDirectionの値)
         = 0


<i = 2 の場合>

distance = angle * lineDirection
         = 3.75 * (lineDirectionの値)

 このように、処理の内容を読み解いていく過程で、実数を当てはめて考えていくことで、
今回の場合であれば、bulletLevel の値により、最終的に angle の値によって弾の位置が変化し、
プレイヤーの向いている方向から等間隔で配置されることが確認できます。


検証◆ Mathf.Lerp メソッドー


 このメソッドの第3引数がわかりにくいと思いますので、補足します。

 第1引数は、この処理の最小値となる値、第2引数は、この処理の最大値となる値です。
最後の第3引数は、この最小値と最大値の中の何割になる値を使うか、というもので、ここは必ず 0〜1の範囲で指定します。
これは % として読み変えて利用することができるので、その場合、0 は 0 %、1 は 100% になります。

 よって、

Mathf.Lerp(最小値、最大値、そのうちの % のときの値の指定)

 となります。

 例えば、currentBulletLine = 10、i = 0 のときは

Mathf.Lerp(-currentBulletLine / 2, currentBulletLine / 2, t)
  ↓
Mathf.Lerp(-5, 5, 0)

 です。

これは、-5 と 5 の範囲を 0 -1(0 -100%) で表現するとしたとき、0 % のときの値を計算してください、という内容になります。
よって、0 のときは、-5 です。

 それを使って計算に使っている部分を見てみましょう。

angle = Mathf.Lerp(-currentBulletLine / 2, currentBulletLine / 2, t)
      = Mathf.Lerp(-10 / 2, 10 / 2, 0)
      = Mathf.Lerp(-5, 5, 0)
      = -5

 そのため、このような結果になります。



 i = 1 の場合は

Mathf.Lerp(-currentBulletLine / 2, currentBulletLine / 2, t)
  ↓
Mathf.Lerp(-5, 5, 1)

 です。

これは、-5 と 5 の範囲を 0 -1(0 -100%) で表現するとしたとき、100 % のときの値を計算してください、という内容になります。

angle = Mathf.Lerp(-currentBulletLine / 2, currentBulletLine / 2, t)
      = Mathf.Lerp(-10 / 2, 10 / 2, 1)
      = Mathf.Lerp(-5, 5, 1)
      = 5

 そのため、5 の値が適用されています。
 
特に、bulletLevel を3以上にして計算した結果を ChatGPT に出してもらうと、この範囲内での % の指定が具体的な数字になります。


検証 ー弾の配置の幅ー


[SerializeField] private float bulletLine;  //直線

 直線の長さです。
この長さを元に、プレイヤーからみてどの位の位置に弾を配置するかを決めています。

 この値を固定値としてソースコード内に使ってしまうと、弾の数が増えても、弾を配置する上限は固定化されているため、
1つ辺りの弾の配置の幅が狭くなっていくことになります。

 そこで

//レベルに応じて、直線の長さを調整する(適宜、計算方法を検討する)
float currentBulletLine = bulletDistance / 2 * bulletLevel;

 この処理を行い、レベルが上がるごとに、直線の長さを少しずつ長くして、弾の配置できる範囲も一緒に広げています。



 図にしてみましょう。
「 | 」が bulletLine で、○がバレットとします。

 バレットが2つのときは、このようなイメージです。

            |○
            |
            |○

 その後、バレットが3つに増えると

            |○
            |○
            |○

 このように、弾を配置する直線の長さが固定化されていると、1つ辺りの弾の幅が狭くなっていきます。

 そこで
            |○
            |
            |○
            |
            |○

 このように弾の幅も取れるように、bulletLine の値を大きくして設置できる範囲を広げています。

 試しに

//レベルに応じて、直線の長さを調整する(適宜、計算方法を検討する)
float currentBulletLine = bulletDistance / 2 * bulletLevel;

  ↓

//レベルに応じて、直線の長さを調整する(適宜、計算方法を検討する)
float currentBulletLine = bulletDistance;

 このようにそのままいれてみてください。
そうすると、直線の長さはレベルに関係なく、固定化されます。

 そうなったとき、弾を4つ5つと増やしてみるとわかるのですが、上記の範囲内で弾を4つ5つと発射します。
初の弾と最後の弾の位置は固定化され、他の弾も、直線の長さが変わらないため、弾が増えるごとに配置する際の間隔が狭くなっていきます。
それだと攻撃の範囲が広がらないので、今回の場合は、レベルを使って補正している形になります。



 補正部分にコメントによる補足があるのは、「今回はレベルで補正しているけど、他の方法もあるよ」という意味です。

 あまり急激に直線の長さを増やしすぎても、弾の間隔が広くなりすぎます。

 例えば
            |○
            |
            |
            |○
            |
            |
            |○
            |
            |
            |○

 これだと、幅が広すぎて敵をすり抜けそうです。

 それで、今回は、直線を半分にしてからレベルを掛ける事で

            |○
            |
            |○
            |
            |○
            |
            |○

 こういう感じで、弾の発射位置を広くしつつ、間隔が急に広がりすぎないようするために、直線の長さを調整して伸ばしています。



 この辺りの表現は、作り手にかかっているので、あくまでも参考値として考えていただけるとよいでしょう。
ほかにも計算方法はありますので、実際には、色んな値を入れ込んでいって調整していく部分、という認識でいてもらえばと思います。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3Dレールガンシューティング(応用編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます