Unityに関連する記事です

 この手順では、最終的な実装目標を「キャラの位置から、クリック(タップ)した方向に向けてバレットを移動させる」とし、この処理を実装するにあたり、
4つの工程を通して、どんな風に1つの処理が作られていくのか、実装を行うまでの過程を含めて学習していきます。

 以下の内容で順番に実装を進めていきます。

手順8 −タップした位置情報をゲーム内に反映する処理を実装−
14.PlayerController スクリプトを修正し、マウスの左クリック(タップ)をした時の位置情報を取得できる処理を追加する
15.PlayerController スクリプトを修正し、タップの位置情報とキャラの位置から方向を計算する処理を追加する
16.Bullet スクリプトと PlayerController スクリプトを修正し、バレットに方向の情報を利用して移動するように制御を修正する
17.PlayerController スクリプトを修正し、方向の情報を正規化処理して、画面をタップした位置による速度差を修正する



 新しい学習内容は、以下の通りです。

 ・Input.mousePosition 変数
 ・Camera.ScreenToWorldPoint(Vector3 position) メソッド
 ・Vector3.Scale メソッド
 ・Vector3.normalized 変数を利用した正規化処理



14.PlayerController スクリプトを修正し、マウスの左クリック(タップ)をした時の位置情報を取得できる処理を追加する

1.設計


 最終的な目標である、バレットをクリックした方向に移動させる処理には、「キャラからみた、クリックした方向」という情報が必要になります。
方向の情報は計算することで算出できますが、そのためには、2つの位置情報が必要になります。
そのうちの1つが、クリックした位置情報になりますので、この手順では、このクリックした位置の情報を取得するための制御処理を実装していきます。

 クリックした位置情報ですが、Unity が用意している Camera クラスには、カメラの画面の位置情報を通じてワールド座標に変換するメソッドがありますので、こちらを利用します。
このメソッドは引数として Vector3 型を準備して指定する必要があります。また戻り値も Vector3 型です。

 引数にも Unity が用意している Input クラスにはマウスのクリックした位置情報を Vector3 型にして取得できる変数がありますので、
こちらを組み合わせて利用していきます。


2.PlayerController スクリプトを修正し、マウスの左クリック(タップ)をした時の位置情報をカメラを通じて取得する処理を追加する


 マウスの左クリックをした時、という処理自体はすでに Update メソッド内に if 文の条件式として用意してありますので、
こちらの中にカメラを通じてクリックした位置情報を取得する処理を追記していきます。

 設計で考えた方法の変数やメソッドの解説が次の段から載っていますので、内容を確認しながら処理を考えてみてください。


PlayerController.cs

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



3.<Input.mousePosition 変数>


 Unity が用意している Input クラスの持つ static 変数です。クラス名.static 変数と記述することで利用できます。
今回の場合であれば、Input.mousePosition と書くことによって、この変数を利用できます。

 この変数では、現在のマウスの位置のピクセル座標(x, y)を取得します。マウスの情報は平面であるため、z 座標の情報はありません
この情報と次の ScreenToWorldPoint メソッドを組み合わせることにより、マウスの位置をゲーム内の座標に変換しています。

 どういった値が取得できているかは Debug.Log を使用することが確認できますので、実際に記載して値を確認してみてください。

参考サイト
Unity公式スクリプトリファレンス
Input.mousePosition
https://docs.unity3d.com/ja/2019.4/ScriptReference...


4.<Camera.ScreenToWorldPoint(Vector3 position)メソッド>


 Unity が用意している Camera クラスの持つメソッドの1つです。カメラを使い、引数の座標をワールド座標に変換します。

 // 画面をタップ(クリック)した位置をカメラのスクリーン座標の情報を通じてワールド座標に変換
  Vector3 tapPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);

 Camera.main と記述することで、ヒエラルキーにある Main Camera タグの設定されているゲームオブジェクトの Camera コンポーネントの情報を利用できます。
通常であれば Main Camera ゲームオブジェクトがこのゲームオブジェクトに当たります

 今回は引数にマウスの座標(Input.mousePosition)を指定し、その位置をゲームのワールド座標に変換(戻り値)する処理を行うことでマウスの位置とゲーム画面の位置の情報を同期させています

 戻り値としては Vector3 型で設定されていますので、処理の左辺に Vector3 型の変数を用意しておくことによって、このメソッドの処理結果の情報を受け取ることが出来ます

参考サイト
Unity公式スクリプトリファレンス
Camera.ScreenToWorldPoint
https://docs.unity3d.com/ja/current/ScriptReferenc...


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


 ゲームを実行し、Gameビューをマウスの左クリックをしてください。左クリックをするたびに、if 文内の処理が実行されますので、
その都度、Console ビューに位置情報の値が表示されていれば、マウスの座標位置を正常にゲーム内の位置情報として変換処理が出来ています


<実行動画>
動画ファイルへのリンク


 この段階ではまだバレットは上方向に発射されています。
次以降の手順で、順番にこの位置情報を利用してバレットをクリックした方向へ発射できるように改良していきます。


15.PlayerController スクリプトを修正し、タップの位置情報とキャラの位置から方向を計算する処理を追加する

1.設計


 クリックして取得した位置情報はいわば「」の情報です。
「点」として、どの位置であるかはわかるのですが、その位置が、どの位置からみてどの位の距離に当たるのか、という目標としての情報がありません。

 そのため、もう1つの「点」となる、いわば始点となる情報を用意し、それらを結んで「」とすることによって、
始点から見て、どの位置にあるのか、どの位の距離にあるのか、そして、どの向きにあるのか、という「方向」を導き出すことが出来ます。

 一方の点の情報はマウスのクリック位置ですので、それに対して方向を求めたい始点の情報はキャラの位置になります。

 つまり、キャラの位置から見て、マウスのクリックした位置までの距離を計算することで「方向」を算出することが出来ます。
これは点の情報(どちらも Vector3型)を減算することで求められます。

 キャラの位置とはすなわち、PlayerController スクリプトがアタッチしているゲームオブジェクトの位置情報を指しています。
これらを元に計算式を考えて処理を実装してみましょう。


2.PlayerController スクリプトを修正し、マウスクリックの位置情報(A)とキャラの位置(B)から方向を計算する処理を追加する


 それでは先ほどの位置情報の取得の処理のあとに、方向を計算する処理を追加します。

 まずはどの位置に処理を追加すればよいのかを、日本語でコメントを書いてみてください。
それから、プログラムとして計算式を記述していきます。
こういった内部の計算の場合、Debug.Log メソッドを利用して計算結果を Console ビューに出力し、計算できているかを確認してください。


PlayerController.cs

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



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


 ゲームを実行し、Gameビューをマウスの左クリックをしてください。
Console ビューに、位置情報の値に続いて、方向の値が表示されるようになれば、マウスの位置とキャラの位置から正常に方向の計算処理が出来ています。


<実行動画>
動画ファイルへのリンク


 方向を計算することはできましたが、現在この情報は PlayerController スクリプトのみが把握している情報です。
この情報をバレット側にも伝えるようにします。

 メソッドには引数(ひきすう)という、変数を介して情報を送受信する機能があります。これを利用しましょう。


16.Bullet スクリプトと PlayerController スクリプトを修正し、バレットに方向の情報を利用して移動するように制御を修正する

1.Bullet スクリプトの設計


 PlayerController スクリプトでは方向の情報を計算して取得することが出来るようになりました。
バレットにもこの「方向」の情報を届けることが出来れば、バレットを移動させる際の「方向」として利用できるように、バレットの移動先を変更できます。

 そのためには、PlayerController スクリプトから ShotBullet メソッドを呼び出す命令を行う際に、引数として「方向」の情報を ShotBullet メソッドに渡してもらうようにします。
つまり、情報を送り出す(発信する)側です。これに対して、情報を受け取る側である ShotBullet メソッドにも情報を受け取るための引数を、同じ型で用意する必要があります。

 方向の情報は Vector3 型ですので、ShotBullet メソッドの引数にも Vector3 型の変数を宣言して追加します。
引数に変数を宣言する場合も、型と変数名を併記します。変数名は任意ですが、方向の情報とわかるように、direction という変数名としておきます。



 引数として受け取った情報は direction 変数に代入されますので、この情報は、ShotBullet メソッド内であれば自由に利用することが出来ます
逆に考えると、このメソッド外では利用できない情報になります。変数にはスコープ(有効範囲)という考え方がありますので、もう一度、復習しておいてください。

 いままではバレットを移動させる際の方向として、AddForce メソッドに transform.up 変数を利用していました。
そのため、常に Y軸の上方向に向かってバレットが移動する処理になっていました。

 この部分を、引数として受け取った direction 変数の情報に変更します。つまり、タップした方向の値です。
こうすることによって、PlayerController スクリプトで計算した「方向」の情報をバレットにもおいても利用し、ゲーム処理の内容に反映することが出来るようになります。

 ここまでの処理を Bullet スクリプトの ShotBullet メソッドを修正することで実装します。


2.Bullet スクリプトを修正して、ShotBullet メソッドに引数を追加し、方向の情報を受け取ってメソッド内で利用できるようにする


 設計の内容をふまえて、Bullet スクリプトの処理を修正してみましょう。

Bullet.cs

 <= クリックしたら開きます


 スクリプトを修正したらセーブしておきます。
次に、PlayerController スクリプトを修正し、ShotBullet メソッドに方向の情報を渡すように処理を修正します。


3.PlayerController スクリプトの設計


 Bullet スクリプトの修正が終了したら、ShotBullet メソッドを呼び出している PlayerController スクリプト側の修正を行います。

 ShotBullet メソッドに引数を追加したことによって、このメソッドが実行される際には Vector3 型の情報を扱えるようになりました。
ですが、肝心の値がこの Vector3 型の変数に届いていなければ、メソッド内の処理に利用することが出来ません。

 ShotBullet メソッドに必要な情報は PlayerController スクリプトで計算して求めている「方向(direction 変数)」の情報です。
この値が Vector3 型ですので、ShotBullet メソッドを呼び出す際に、この direction 変数を指定して渡してあげるようにすれば、
ShotBullet メソッドでも、この方向の情報を利用して処理を実行出来るようになります。


4.PlayerController スクリプトを修正し、Bullet スクリプトの ShotBullet メソッドに方向の情報を伝達する処理を追加する


 設計の内容をふまえて、PlayerController スクリプトの処理を修正してみましょう。

PlayerController.cs

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



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


 スクリプトの修正が済みましたので、ゲームを実行して Game ビューを左クリックしてみてください。
PlayerController スクリプトで計算した方向の情報が Bullet スクリプトの ShotBullet メソッドに伝わっていれば、
いままでと異なり、キャラの位置からクリックした位置の方向に向かってバレットが移動するようになります。


<実行動画>
動画ファイルへのリンク


 もしもまだ上方向にしかバレットが移動しない場合には、Bullet スクリプトの ShotBullet メソッド内の処理を見直します。
引数で届いてる direction 変数の情報をしっかりと AddForce メソッドにて活用しているか、確認してください。


 同時に問題点も見えてきたと思います。
キャラとクリックした位置の距離によって、バレットの移動速度が変化してしまっています
 
 最後に、このクリックした位置よる速度の差をなくす制御処理を実装しましょう。


17.PlayerController スクリプトを修正し、方向の情報を正規化処理して、画面をタップした位置による速度差を修正する

1.設計


 クリックした位置によってバレットの速度が変化してしまう原因は、方向として計算した値に設定されているマグニチュードという速度情報にあります。
このマグニチュードの値は、距離が離れるほどに大きくなる値であるため、キャラの位置から遠い位置でクリックすると、速度も一緒に大きくなってしまいます。
 
 改善するには、速度情報を正規化することで対応できます。正規化とは、マグニチュードの値を単位ベクトルという情報に変換する処理のことです。

 単位ベクトルとなった値は、方向の情報はそのままに、速度の値を一定値(0 か 1)に統一されますので、
キャラから遠い位置をクリックしても、近い位置をクリックしても、常に同じ速度を保つことが出来るようになります。

 またこの処理を行う前には、方向の情報から Z成分の情報を除去(0)にしておく必要があります。そうしないと正確な単位ベクトルが作成されません。
そのため、クリックした位置に向かって同じ速度でバレットを移動させるには、方向の計算のあとに、Z軸の情報を 0 にし、その後、正規化の処理を加えることが必要になります。


2.PlayerController スクリプトを修正し、クリックした位置による速度の差を修正して一定速度にする処理を追加する


 設計を元に、日本語でコメントを書いてから、処理の実装を行います。

 プログラムは上から下に処理が実行されていきますので、処理を書く順番が大切になります。

 方向の計算 → Z成分の除去(direction,z を 0 にする) → 正規化

 この順番で処理を実行することによって、方向の値が正規化されます。

 どのように、Z成分の除去や正規化処理を行うか、ですが、Z成分の除去する方法は色々あります。Vector3.Scale メソッドを利用する方法がわかりやすい方法になります。
また正規化処理は、Unity の用意している Vector3.normalized 変数を利用すれば実行できます。Vector3 型の部分に正規化を行いたい変数を指定します

 どちらも下に解説がありますので、目を通してからスクリプトの修正に挑戦してみてください。

 自分が実装したい処理がイメージ出来た場合には、それを実現するためにどんな処理があれば上手くいくのか、自分ですべて処理を書く必要があるのか、
あるいは Unity が用意している情報があるのか、そういったことを調べてみてください。


PlayerController.cs

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



3.<Vector3.Scale メソッド>


 Unity の Vector3 の扱える情報の1つです。

 第1引数の各成分と、第2引数の同じ成分を乗算した結果を、戻り値として Vector3 型で取得します。
そのため、計算結果を代入する Vector3 型の変数を用意しておく必要があります。

direction = Vector3.Scale(direction, new Vector3(1, 1, 0))

 上記の場合、(direction.x * 1, direction.y * 1, direction.z * 0) という計算が行われることになります。
Z 軸のみ常に 0 の値が乗算されるため、処理の結果として、direcion の値は、X と Y の情報はそのまま、Z は 0 という結果が戻り値として得られて、
元の direction の値を上書きして代入されます。そのため、direction の値から Z 成分のみ除去し、0 にすることが出来ています。


参考サイト
Unity公式スクリプトリファレンス
Vector3.Scale
https://docs.unity3d.com/ja/current/ScriptReferenc...


4.<Vector3.normalized 変数を利用した正規化処理>

 
 正規化処理です。magnitude(マグニチュード。長さ)を1としたベクトル(単位ベクトル)を返します。戻り値は Vector3 型になります。

  // 正規化処理を行い、単位ベクトルとする(方向の情報は持ちつつ、距離による速度差をなくして一定値にする)
  direction = direction.normalized;

 現在のベクトルの方向を維持したまま、magnitudeが1、あるいは0の単位ベクトルを作成することが出来ます。(ベクトルの値が小さいと0になります。)

 この処理を行わないとクリックした位置への magnitude がそのまま維持されてしまうため、
A地点(クリックした位置)とB地点(始点)の距離が離れている程、速度が速くなり、近いほど速度が遅くなります。
今回の場合は、バレットのゲームオブジェクトの速度が距離によって変化してしまいます。

 この正規化を行うことによって、クリックした位置の遠近に関わらず、magnitude がすべて 1、あるいは 0 に統一された単位ベクトルの値となるため、
方向はそのままで、打ち出す力のみを一定値に統一することが出来ます
 
Unity公式スクリプト・リファレンス
https://docs.unity3d.com/ja/current/ScriptReferenc...
TechProjin様
UnityのVector3でよく使うものまとめ
https://tech.pjin.jp/blog/2016/02/16/unity_vector3...


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


 今回の実装により、方向の情報から不要な Z軸の情報をなくして正規化を行うことによって、
クリックした位置とキャラの位置との距離にかかわらず、方向の情報のみを計算することができるようになりました。

 ゲームを実行して、先ほどと同じように Gameビューの色々な位置をクリックしてみてください。
先ほどとは異なり、どの位置をクリックしても、同じ速度でそのクリックした方向に向かってバレットが移動するようになれば制御成功です。


<実行動画>
動画ファイルへのリンク


 以上ですべて完成です。

 このように、1つの処理を実装するにあたっても、複数の工程が必要になります。また、最終的な目標も見えていないと完成できません
逆に言えば、1つずつ順番に組み立てていくことができれば、イメージしている処理を実装できるとも言えます。

 以前にも説明したように、一度にすべての処理を実装しようとはせずに、順番に積み重ねて処理を構築していくことが大切です
そうすることができれば、手順を見直すことも出来るようになりますので、自分で修正したり、追加することも可能になります。

 ロジックの組み方、考え方を継続して学習していきましょう。


6.<応用>


 方向の計算式は現在3つの処理を順番に行って処理を制御していますが、C#ではこれを1行にまとめて記述することも出来ます。

<現在の書式>
  // 方向を計算
  Vector3 direction = tapPos - transform.position;

  // 方向の情報から、不要な Z成分(Z軸情報) の除去を行う
  direction = Vector3.Scale(direction, new Vector3(1, 1, 0));

  // 正規化処理を行い、単位ベクトルとする(方向の情報は持ちつつ、距離による速度差をなくして一定値にする)
  direction = direction.normalized;

 これは、次の式で記述できます。

<1行でまとめて記述する書式>
  // 方向を計算(方向の情報から、不要な Z成分(Z軸情報) の除去を行い、正規化する)
  Vector3 direction = Vector3.Scale(tapPos - transform.position, new Vector3(1, 1, 0)).normalized;

 この1行の記述で、3行分と同じ処理を行っています。この処理にもピリオドの処理が利用されているのが分かります。

 処理を理解して読み解けるようになると、色々な記述方法が使えるようになってきます。少しずつ慣れていきましょう。



 以上でこの手順は終了です。

 次は 手順9 −エネミーの作成と制御− です。

コメントをかく


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

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

Menu



技術/知識(実装例)

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

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

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

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

レースゲーム(抜粋)

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

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

3D脱出ゲーム(抜粋)

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

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

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

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

VideoPlayer イベント連動の実装例

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

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

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

private



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

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