Unity入門11
Tanks!②
(タンク)
前回までで、ステージとタンクの動きができました。
次は、タンクの色や走る時のエフェクトをつけてみましょう。
前回の確認
このタンクは【
TankRenderers
】という子オブジェクトの中に、4つのオブジェクトに分かれて作られています。
タンクの色を変える
このうち【
TankChassis
】がタンクの車体、【
TankTracksLeft
】が左のタイヤ、
【
TankTracksRight
】が右のタイヤ、【
TankTurret
】が大砲部分のオブジェクトです。
この内、1つを変えると全部の色が変わりますので【
TankChassis
】の色を変えましょう。
色の変え方は、【
TankColour
】の【
Albedo
】を変更すればOKです。
自由にかえてみましょう。
次に、タンクが動く度に砂煙が上がるようにしましょう。
砂煙用のエフェクトは【
Prefab
】フォルダの中の【
DustTrall
】です。このエフェクトは動く度にもくもくと砂煙のように見えます。
これをTankオブジェクトの子オブジェクトにしましょう。またこの砂煙は2つ必要になりますので、2つ子オブジェクトにしましょう。
名前を【
DustTrall
Right
】と【
DustTrall
Left
】にしておきます。
砂煙をつける
後は、これを右タイヤ(キャタピラ)、左タイヤの位置にセットしておくだけです。
それぞれの座標を以下のようにしてください。これで完了です。試しておきましょう。
では、次は弾を撃てるようにしていきます。まずは弾を作ります。
弾の3Dデータは【
Models
】フォルダの【
Shell
】でしたね。
まずはこれをオブジェクトにして、【
Rigidbody
】と【
Collider
】を追加しましょう。ここらへんは障害物と同じですね。
※基本的に、3Dデータなどからオブジェクトを作る場合は、すべて同じ流れですね。
今回は【
CapsuleCollider
】にしておけば、合わせやすいです。以下の感じに大きさを調整しました。
弾をうつ
【
is Trigger
】をチェック入れていることと、【
Direction
】を【
Z-Axis
】にしているのも注意です。※
【
Z-Axis
】は
コライダーの向きをZ方向に向けさせる意味でしたね。
この弾は複数必要になるので、Prefabにしておきましょう。
Prefabにしたら、元オブジェクトは削除しておきましょう。
また、この弾は少し光ったように見せているので、弾自身に【
Light
】コンポーネントを追加します。
【
Add Component
】の【
Rendering
】の中に【
Light
】を選択します。
【
Light
】
コンポーネントを追加したら、下のように設定しておきましょう。
弾をうつ
次に、弾が出て来る場所を作っておきたいと思います。
普通に考えるとタンクから出てくるのですが、タンクの中心から出ると見た目が変になってしまいます。やはり大砲(主砲)部分から出てきてほしいですよね?
そのために出てくる場所をタンクとは別のオブジェクトとして作っておきます。この出現場所のことをSpawn(スポーン)ポイントなどと言われます。(マイクラとかでお馴染みですね)
ちなみに元々、スポーンは”産む”という意味ですが、ゲーム業界では”出現”と同じ意味でスポーンと使われています。
では、このスポーンポイント用のオブジェクトですが、あくまでタンクが動いたら同じように動いてもらわないといけないので、Tankオブジェクトの子オブジェクトとして作ります。
【
Tank
】オブジェクトを右クリックし、空のオブジェクトを作ってください。名前は【
ShellSpawnPoint
】にでもしておきます。
この
【
ShellSpawnPoint
】のTransformを以下のようにしてください。
弾をうつ
以前にも少し触れましたが「【子オブジェクトの
Transform
の数値】は【親オブジェクトからの相対値】」です。
【
ShellSpawnPoint
】は【
Tank
】オブジェクトの子オブジェクトなので、
Transform
の数値は、「
Tank
オブジェクトからの相対値」となります。
相対値ということは「
Tank
オブジェクトの
Transform
から
Y座標+1.7、Z座標+1.35、x方向に-10°
」という意味になります。
このように同じ
Transformの値
でも、その数字が意味することは変わってきます。
実はUnity上では
【
ローカル空間
】と【
ワールド空間
】というものがあり、【どちらの値なのか?】によって意味するものが変わってきます。
【
ワールド空間
】とは、Scene全体の空間のことです。
親オブジェクトの
Transform
は、この
【
ワールド空間
】の値です。
【
ローカル空間
】は上記の通り、親オブジェクトからの相対座標で、子オブジェクトの
Transform
はコレです。
※Unityおいて、空間の種類は他にも色々あります。
ワールド空間とローカル空間
弾を飛ばす用のスクリプトを新しく作ります。名前は【
TankShoot
】にして、タンクにアタッチしておきましょう。
まずは、下の変数を用意します。
弾をうつ
【
shell
】変数は、弾のPrefabを代入する用の変数です。今までは
GameObject
型にPrefabを代入していましたが、今回は
Rigidbody
型になっています。
これは、以前は【弾を作り出す】だけで、その後【弾の動き】は弾側のスクリプトに作っていたからです。
今回は、【弾を作り出して、それを飛ばす】までこのスクリプト内で作りますので、
Rigidbody
型にしておくと、簡単に飛ばすことが出来ます。
【
shellTransform
】変数は、先ほど作ったスポーンポイントを代入する変数です。あくまで弾の初期位置(スポーン位置)や、方向だけを使うので、【
Transform
】型で作っています。
これも簡単に必要な情報だけ使うための方法です。
次に飛ばすメソッドを作りましょう。
弾をうつ
Fireという名前で新しいメソッドを定義しています。
【
Rigidbody shellInstance
】の行は、【
Instantiate()
】(インスタンシェート)で、PrefabのShellをオブジェクトにして、それを
Rigidbody
型の 【
shellInstance
】という変数に代入しています。
【
Instantiate()
】の第2引数、第3引数は、それぞれスポーンポイントの座標と方向のことですね。
この時点で【
shellInstance
】は、弾(shell)自体の
Rigidbody
が代入されています。
次の行で【
shellInstance.
velocty
】(弾の速度)に、【
shellTransform
.
forward
*
10
】を代入することで、【
shellTransform
.
forward
】(スポーンポイントの向いている方向)に速度が与えられ、弾が飛んでいく動きなります。
10という数字は、飛んでいく力です。増やせばより飛ぶということです。
後は、この【
Fire()
】メソッドを適切なタイミングで呼び出せば良いですね。
試してみよう
以下のコードの足りない部分を追加して、【スペースキーを押した後、押すのをやめた時に】弾を飛ばせるようにしてください。
※押した時ではなく、押すのをやめた時(指を離した時)であることに注意してください。
ヒント:押すのをやめた時に
True
を返すメソッドは【
Input.GetButtonUp()
】です。
【
InputManager
】はUnity上部のメニューの【
edit
】→【
ProjectSettings
】→【
Input
】で確認出来ましたね。
※【
InputManager
】の設定は変更しないでください。
Inspectorビューから【
shell
】と【
shellTransform
】に適切なものを代入することも忘れないでください。
ため撃ち
これで弾が飛ばせるようになったと思います。
今度はスペースキーを押している時間によって弾の飛距離が変わるようにしたいと思います。いわゆる【ため撃ち】です。
飛距離の力の部分は、下記の赤枠でしたね。ここの数値をボタンの押す時間によって変えていけば良いということです。
数値を変えていくということは、必ず変数が必要ですね。この弾の飛んでいく力用の変数を用意します。名前は【
launchForce
】(ローンチフォース:打ち上げる力)にしておきます。
ため撃ち
他にも用意しておく変数があります。
まず、まったく溜めていない状態の飛距離が0だと流石にゲームになりませんので【力の最低値】用の変数
逆に最大値が無限だと、遥か彼方に飛んでいってしまうので、【力の最大値】用の変数
後は、どれくらいの速度で力がたまるのか?という【力が溜まるスピード】用の変数
を用意します。
それぞれ、【
m
inForce
】(力の最低値)【
maxForce
】(力の最大値)【
chargeSpeed
】(力の溜まるスピード)という変数にしておきます。
すべてInspectorビューからイジれるようにpublicにしています。
変数が出来たら、それぞれ以下の数字を代入しておきましょう。
ため撃ち
まずは現状を確認しておきましょう。
現在は、前に飛ばす力(
launchForce
)は0なので、弾はすぐに落ちていくはずです。
※下の例では弾は光っていませんが、気にしないでください。
そのため、【スタート時に力の最低値を代入する】必要があります。以下のようにしておきましょう。
ため撃ち
次に、【スペースキーが押されている間、力が溜まる】部分です。
【キーが押されている間】入力を受け取るメソッドは【
Input.GetButton()
】メソッドです。
【
Input.GetButton()
】は押されている間、常に
True
を返します。
※【
Input.
GetButtonUp
()
】は「押すのをやめた時(指を離した時)」、【
Input.
GetButtonDown
()
】は「押した時(1回だけ)」でしたね。
次へ。
試してみよう
以下のコードの足りない部分を追加して、押した時間によって飛距離が伸びるようにしてください。
※【
chargeSpeed
】が10の場合、1秒毎に10ずつ【
launchForce
】が増えるようにしてください。
ヒント:下記のif文を追加するのは、当然Update()メソッドの中です。
また、飛距離が伸びた後、次の弾では
launchForce
を最低値に戻しておかないといけません。そのコードも追加してください。
ヒント:弾を飛ばした後、つまりは
Fire()
メソッドに追加しましょう。
左の動画のようになればOKです。
尚、現時点では【力の最大値】の設定はしていませんので、無制限に伸びます。
※例では弾は光っていませんが、気にしないでください。
ため撃ち
では、次は力の最大値の制限を作りましょう。
サンプルゲームをプレイするとわかりますが、このゲームでは「最大値を超えると自動的に弾が発射される」処理になっていますね。
同じように作ってみましょう。次へ。
試してみよう
以下のコードの足りない部分を追加して、力の最大値になると、
自動で発射
されるようにしてください。
ヒント:下記のif文を追加するのは、当然Update()メソッドの中です。
現時点では、自動で発射された後、スペースキーから指を離すと、また弾が発射されてしまうかと思いますが、これは次のページ以降で直します。
最大値の設定は出来ましたが、問題が出てきましたね。
最大値になると自動で弾が出るため、その後に指を離すと、また弾が飛んでいってしまいます。
それ以外にもスペースをずっと押し続けると、弾が何度も出てきます。
これもちゃんと直しておきましょう。次へ。
ため撃ち
試してみよう
以下の発射の問題点2つを解決してください。
「力が最大になり自動で発射された後、スペースキーから指を離すとまた弾が発射される」
「力が最大になり自動で発射された後、スペースキーを押し続けるとまた弾が発射される
」
解決方法は色々考えられますが、ここでは以下の方法で解決してください。
ヒント&条件:
bool型の変数を用意する。※変数名は自由
この変数は「
撃てる状態
」「
撃てない状態
」の変化を
true
、
false
で切り分けるために使う。
スペースキーを押した時だけ(1回だけ)「
撃てる状態(true)
」になる。
※新たなif文をUpdateメソッドに追加してください。
弾を撃った時(【
Fire()
】メソッドが実行された時)に
「
撃てない状態(false)
」に切り替わる。
※【
Fire()
】メソッドにコードを追加してください。
【「スペースキーを離した時」に弾が発射される】という現在の条件を【
「スペースキーを離した時」かつ「
撃てる状態(true)
」なら弾が発射される
】に変更する。
※ここ
で
問題点1が解決します。
【「スペースキーを押している間」弾の飛距離が増える(
launchForce
が増える
)】の条件を【「スペースキーを押している間」かつ「
撃てる状態(true)
」なら弾の飛距離が増える(
launchForce
が増える
)】に変更する。
※ここで問題点2が解決します。
問題点が解決したら見せてください。
さて、ため撃ち自体はできるようになりましたが、サンプルゲームでは、スペースキーを押している間、矢印が伸びていく演出があります。これを作っていきましょう。
視覚効果をつける
これは【
Canvas
】で作っていきます。
Tankオブジェクトを選択し、右クリック【
UI
】→【
Canvas
】を選択しましょう。
次に、今作った
【
Canvas
】を右クリックし、今度は【
UI
】→【
Slider
】(スライダー)を選択してください。以下の状態になっていると思います。
視覚効果をつける
この内、【
Background
】と【
Handle Slide Area
】は使いませんので、削除しておいてください。
また、別の場所に【
EventSystem
】というオブジェクトも作成されていると思います。
この【
EventSystem
】の【
Standalone Input Mdele
】を以下のようにしてください。
※末尾に"UI"を追加する。
これは【
InputManager
】の設定が変わっているので、それに合わせているだけです。あまり気にしなくてもOKです。
次に【
Canvas
】を設定します。
【
Render Mode
】という項目がありますので、これを【
World Space
】に変更してください。
【
Render Mode
】とは、この【
Canvas
】がどこに作られるのか?の設定です。今まで使っていた【
Screen
Sp
ace
Overlay
】は、スクリーン(ゲーム画面)自体に【
Canvas
】が作られていました。
なので、実際の【
Canvas
】の座標は、オブジェクトの座標とは関係ない場所に表示されてましたよね?※スコアの表示などです。
こ
れは
【
Canvas
】が【
Screen
Sp
ace
】つまり【
スクリーン空間
】に存在していたからで、その場合の
【
Canvas
】の
Transform
の座標
は【
スクリーン座標
】として扱われてました。
【
World Space
】にすることで【
ワールド空間
】に【
Canvas
】は作られることになります。
ただし、Tankの子オブジェクトになっているため、
Transform
の座標は【
ローカル座標
】であり、Tankが動けば一緒に動くようになります。
尚、まだ使ったことはないですが
【
Screen
Sp
ace
Camera
】の場合は、特定のカメラだけに表示されます。表示のされ方は基本的に【
Screen
Sp
ace
Overlay
】と同じです。
次へ。
視覚効果をつける
【
World Space
】に変更すると【
Rect Transform
】が変更できるようになると思います。
これ以下のように変更してください。
視覚効果をつける
コレで【
Canvas
】がTankと同じ位置になり、上を向いたような状態になっています。
次に【
Camvas Scaler
】の【
Reference Pixels Per Unit
】という項目を1にしてください。
【
Camvas Scaler
】とは、ゲーム画面の大きさ(PC、スマホなど)ごとに、どのように【
Canvas
】を描画するかの設定です。
この【
Reference Pixels Per Unit
】という項目は、上の【
UI Scale Mode
】によって意味合いが変わるのですが、【
World
】の状態では、【
Canvas
】上の1unit(ユニット:
Unity上の単位、現実世界での1メートル相当)のピクセル密度を表します。
1にした場合は1ピクセルで1
unitをカバーします。
なんだかよくわからないですが、矢印の先頭部分(三角形の部分)の大きさは固定して、棒の部分だけ伸びていくようにするために使っています。
次に【
Slider
】です。
まず【
Slider
】コンポーネントを下の画像のように変更してください。
視覚効果をつける
【
Interactable
】は、ユーザーが
Slider
を動かせるかの設定です。今回は矢印として使いますのでもちろん動かせないようにチェックをはずしています。
【
Transition
】は、「通常時」「クリックされている時」など状態によって、
Slider
の見た目を変える設定です。これも必要ありませんので【
None
】にしています。
【
Direction
】は、方向です。伸びていく方向を指定します。【
Botton To Top
】にしています。
【
MinValue
】と【
MaxValue
】は、Sliderの伸びる長さの
最小値、と最大値です。
これは【
minForce
】と【
maxForce
】変数と同じにしておいたほうが良いでしょう。
次に【
Slider
】の【
Rect Transform
】コンポーネントを下の画像のように変更してください。
※
【
Rect Transform
】は、必ず
左上の【
Anchors
】(□のマーク)から先に変更しましょう。
視覚効果をつける
次は【
Fill Area
】です。これも以下のようにしてください。
視覚効果をつける
最後に【
Fill
】です。まず、【
Image
】コンポーネントの【
Source Image
】に【
Aim Arrow
】を代入します。
【
Aim Arrow
】は【
Sprites
】フォルダの中に用意されています。
その後
【
Rect Transform
】も合わせておいてください。
視覚効果をつける
これで、
Slider
の準備が出来ました。
次は、スプリクト側に追加していきます。
【
TankShoot
】ファイルを開いてください。
まず、以下のように、【
Slider
】型の変数を作ってください。
視覚効果をつける
【
Slider
】型とは、先ほど作った
Slider
を代入しておくための変数です。
この
Slider
はUIクラスの一部なので、【
using UnityEngine.UI;
】も追加しておく必要があります。※
using
の書く場所は上の方(【
TaskShoot
】クラスの外)にありましたね。
一旦ファイルを保存し、
Inspectorビューから、
先ほど作った【
Slider
】を【
arrow
】変数に代入します。※
Canvas
ではなく、
Slider
を入れます。
この時点で、スクリプトから
Slider
を動かすことができるようになりました。
動かすと言っても、やる事は非常に単純です。
「【
Slider
】のValueの値を、【
launchForce
】と同じにする」だけです。次へ。
【
Slider
】のValueの値を、【
launchForce
】と常に(1フレームごとに)同じになるようにコードを追加してください。
ヒント:
【
Slider
】のValueの値は、【
arrow
.value
】とすることで指定できます。例えば【
arrow
.value = 100;
】とすれば、【
arrow
.value
】を100にすることができます。
試してみよう
弾の視覚効果としては、ほかにも【撃った時に煙が出る】と【当たった時に爆発する】というのがありますね。
【撃った時に煙が出る
】に関しては、少し作り方が違うので、これは後で行います。
先に、【当たった時に爆発する】を
作っていきます。
エフェクトは【
Prefab
】の中に【
ShellExplosion
】という名前で用意されています。
これを
shell
プレハブに貼り付けて子オブジェクトにしたいのですが、必ず、一旦、
shell
プレハブをオブジェクトにしてから
、
オブジェクト状態の【
ShellExplosion
】
に
貼り付けてください。
※
Prefab
に
Prefab
を貼り付けようとすると、子オブジェクトにはならず、
元のPrefabが上書きされてしまいます。
視覚効果をつける
視覚効果をつける
この時点で弾のエフェクトを生み出すことが出来るようになっています。
以前は、スクリプトを作り
【
OnTriggerEnter()
】メソッド(別オブジェクトにぶつかった時に呼び出されるメソッド)の中に、【
Instantiate
(
)
】を用意して、エフェクトを生み出す、ということをしていました。下の感じですね(ここは例なので、書かない)
今回はエフェクトである
【
ShellExplosion
】は【
Shell
】オブジェクトの子オブジェクトになっています。
この場合は【
Shell
】オブジェクトが作られたと同時に【
ShellExplosion
】も作られますので、
【
Instantiate
(
)
】が必要なくなります。
一旦、この状態で試してみましょう。
画面上には
まだ何も表示されない
と思いますが、Hierarchyビューを見ると、以下のようにちゃんと【
ShellExplosion
】も作られていることがわかると思います。
視覚効果をつける
では、なぜ表示されないのかというと、
【
ShellExplosion
】の
【
Particle System
】の中の【
Play On Awake
】にチェックがついていないからです。
【
Play On Awake
】は、このエフェクトオブジェクトが生み出された時に、エフェクトを再生(Play)するか?という項目でしたね。
これのチェックがないと、スクリプトで再生しない限り、エフェクトは生み出されても表示されない状態になります。
では、これのチェックを入れて動かしてみましょう。次へ。
以下のようになったと思います。
視覚効果をつける
一見、正しく見えますが爆発のタイミングが早すぎです。実際は以下の感じにならないといけません。
つまり、エフェクトが再生されるタイミングが早いのです。次へ。
タイミングが早いのは、生み出されてすぐに再生してしまうからなので、やはり
【
Play On Awake
】のチェックは外しておくべき、ということがわかります。
※チェックを外しておきましょう。
では、いつ再生すれば良いのか?というと、当然「何かにぶつかった時」ですね。
これはスプリクトがないと作れない処理なので、新しくスクリプトを作りましょう。名前は【
ShellExplosion
】にします。
出来たら、先にアタッチしておきましょう。アタッチするのは【
shell
】の方です。
※後で弾のダメージなどの処理も同じスクリプトで作っていきますので、
【
shell
】にまとめておきます。
視覚効果をつける
では、【
ShellExplosion
】スクリプトに、【別オブジェクトにぶつかった時】に【エフェクトが再生される】処理を作り、以下のように表示させてください。
ヒント:まずは【
ParticleSystem
】型の変数を用意しましょう。そして、Inspectorビューからこの変数に【
ShellExplosion
】プレハブを代入しておきましょう。
【エフェクトが再生する】のは、【(上で作った
)変数名
.
Play
()
;
】というメソッドです。
【別オブジェクトにぶつかった時】に呼び出されるメソッドは今まで何度も登場しています。少し前を見直すか、検索してみましょう。
試してみよう
現時点では、エフェクトの消え方(地面に消えていく)が変ですが、これは後で直します。
これで、エフェクトを表示させるタイミングはバッチリですが、消える時がなんか変です。
下の2つの動画を見比べてみましょう。
視覚効果をつける
よく見ると、右側の方は【エフェクトが地面に沈んでいく】状態になっています。
実は、これは弾が地面に消えていっているのですが、子オブジェクトであるエフェクトも一緒に地面に沈んでしまっているのです。
(子オブジェクトは、親と同じ動きをするため)
これを防ぐためには【エフェクトを再生する】前に【親子関係を切る】のです。
内部的に、
自分の親オブジェクトは【
オブジェクト(変数).transform.parent
】というところ保存されています。
※今回の場合、先ほど作った【
ParticleSystem
】型の変数でOKです。
つまり【
オブジェクト.transform.parent
】に
null
(ヌル)を代入すると、親がいないオブジェクトに変わります。
※逆に【
オブジェクト.transform.parent = (親にしたいオブジェクト).transform
】とすると、親オブジェクトにさせることも出来ます。今は必要ないですが。
【
ShellExplosion
】スクリプトの適切な場所に【親子関係をなくす】処理を追加し、以下のような表示になるようにしてください。
試してみよう
尚、弾を撃ったあと、Hierarchyビューでは以下の表示になっていることも確認しておきましょう。
※親子関係が外れていますね。
最後に
【
Shell
】と
【
ShellExplosion
】オブジェクトが削除されずに残っているので、これの削除のコードを追加します。
削除と言えば【
Destroy
(
gameObject
)
;
】で、このスクリプトがアタッチされているオブジェクトは削除できましたね。
つまり、
【
Shell
】に関しては、
これだけでOK
ということです。
ただ【
ShellExplosion
】は残ってしまいますので、別の方法が必要です。
以前はエフェクトをdestroyするだけ用のスクリプトを作って、エフェクトにアタッチしていましたね。
この方法でも良いのですが、今回はスクリプトを増やさず【
ShellExplosion
】スクリプトの中で処理する方法を使いましょう。以下を【何かにぶつかったときに】メソッドの中に追加しましょう。
削除する
1行目の【
ParticleSystem型の変数名
.
main
】とは、Inspectorビューの【
Particle System
】コンポーネントの部分です。
それを【
ParticleSystem
.
MainModule
】という型の変数に代入しています。
【
ParticleSystem
.
MainModule
】型とは、上記のコンポーネント用の型です。特殊な型に見えますが
深い意味はなく、上記の部分を取り出すにはこの型に入れないといけないと思ってください。
2行目はDestroyメソッドですが、第一引数の【
ParticleSystem型の変数名
.
gameObject
】は
【
ShellExplosion
】オブジェクトのことです。
第二引数の【
particleMain
.
duration
】とは、以下の部分のことです。こうすることで【
Duration
】(期間)が終われば削除する、という処理になります。
削除する
では、
【
Shell
】と
【
ShellExplosion
】を削除できるようにコードを追加してください。
弾を撃った後のHierarchyビューが以下のようになればOKです。
試してみよう
お疲れ様でした
今回で
Tank
の弾の動き、エフェクト部分ができました。
カメラが自動で動くような処理を作っていきます。
「
Tank!③
」に続く。