【Unity/2D】Flappy Bird風ゲームを作ってみる話 #2 プレイヤーを動かす準備~プレイヤーを動かす
記事をご覧いただき、誠にありがとうございます。
出てきたコンポーネントの一覧からPhysics 2D > Rigidbode 2Dと選択してアタッチしてもいいですが、検索窓で入力する方が早いので、本記事ではコンポーネントは検索してアタッチしていきます。
Rigidbody2Dを選択するとPlayerにアタッチされました。
では準備が出来たので、早速プレイヤーを動かしていきます。
そこで、Unity側の文字エンコードであるUnicodeに変更してやる必要があります。
これでOKボタンを押してUnityで確認すると、文字化けが解消されました。
ここで特定のキー入力があった場合に、プレイヤーは上方向に移動するようなスクリプトを書けばいいわけです。
このplayerRBのvelocityにベクトルを与えて、プレイヤーを移動させます。
次は内部処理用の変数で、Rigidbody2DのplayerRBです。
Start関数内では、playerRBがアタッチしたオブジェクトのRigidbody2Dを取得します。
これでプレイヤーがスペースキーを押される毎に上方向へ移動する処理が出来ました。
投稿主の無能です。
前回は、プロジェクトを新規作成してプレイヤーを登場させました。
今回はプレイヤーを動かす処理を作っていきたいと思います。
プレイヤーを動かす準備
まずはプレイヤーを動かす準備を整えます。
オブジェクトが移動するには、座標のTransformのPositionを動かしてやれば、動くには動きます。
ですが、オブジェクトと言っても現状では一枚の絵を貼り付けただけのものなので、このオブジェクトをプレイヤーとして機能させるために色々と準備が必要になります。
ということでやっていきましょう。
Rigidbody2Dをアタッチする
最初にRigidbody2Dをプレイヤーのオブジェクトへアタッチします。
アタッチというのはRoll a Ballでもやった通り装着を意味します。
つまり、日本語で言うとオブジェクトへコンポーネントという部品を装着する、という意味になります。
ここで移動に必要なコンポーネントがRigidbody2Dになるわけです。
3Dの場合は名前の末尾の2Dを除いてRigidbodyになり、2Dでは名前の末尾に2Dが付きます。
3Dだと必要なコンポーネントが変わってくるので間違えないようにしてくださいね。
では、Playerを選択した状態で、Inspectorビューの最下段の「Add Component」ボタンを押します。
Playerを選択した状態でInspectorビューのAdd Componentを押す
検索窓でコンポーネントの名前を入力して検索
Rigidbody2DがPlayerにアタッチされた
スクリプトを書く
スクリプトの準備
ではスクリプトを書いて、プレイヤーを動かしていきます。
スクリプトはこの後幾つか書くことになるので、スクリプトを格納しておくフォルダを作成します。
ProjectビューのAssetsフォルダを選択し、フォルダを新規作成して名前を「Scripts」フォルダにします。
ProjectビューでScriptsフォルダを作成
そしてScriptsフォルダ内にC#スクリプトを作成し、名前を「PlayerController」にします。
Scriptsフォルダ内に「PlayerController」スクリプトを作成
ではスクリプトをダブルクリックかEnterキーで決定して、Visual Studio(以下VS)を起動します。
スクリプトを開くとVisual Studioが起動する
文字化けを解消する
VSのデフォルトの文字エンコードはShift-JISになっているので、UnityのInspectorビューでスクリプトを確認すると、文字エンコードが合致していないためもじばけが発生します。
VSで日本語のコメントを書くと…
Unityでは文字エンコードが不一致なため文字化けが発生する
VSでファイル > 名前を付けて○○(現在アクティブなスクリプト名).csを保存を選択します。
ファイル > 名前を付けて○○(現在アクティブなスクリプト名).csを保存を選択
別ウィンドウで保存画面が出てくるので、下部の上書き保存ボタンの横の三角形のボタンを押し、「エンコード付きで保存」を選択します。
下部の上書き保存ボタンの横の三角形のボタンを押し「エンコード付きで保存」を選択
上書き保存の確認ダイアログが表示されるので、はいを選択します。
その後更に別ウィンドウが出てくるので、上のエンコードの選択項目から「Unicode(UTF-8 シグネチャ付き)- コードページ 65001」を選択します。
デフォルトのShift-JISの直下ですね。
上のエンコードの選択項目から「Unicode(UTF-8 シグネチャ付き)- コードページ 65001」を選択
Unityで確認すると文字化けが解消された
これは別にやらなくても支障は無いことですが、Unity側でもスクリプトのコメントが確認出来るようになるので、やっておいて損はないかと思います。
ではスクリプトを書いていきましょう。
プレイヤーを動かすスクリプトを書く
では実際にプレイヤーを動かすスクリプトを書いていきましょう。
今回のゲームは、右から左へ動く上下の土管の間を抜けてスコアを獲得していく、所謂Flappy Bird風のゲームを作ります。
という事は、プレイヤーは特定のキー入力があった場合にジャンプするように、上方向へ移動すればいいわけですね。
スクリプトに実装させる処理が思い浮かばないときは、このように
「何が(何のオブジェクトが)」
「どうなるか(どんな処理を行うのか)」
を、目的のオブジェクトに対して「最小限」の処理になるように考えてみるといいです。
例えば、今回のゲームで言えば
「プレイヤーを(目的のオブジェクトを)」
「ジャンプさせたい(上方向に動かしたい)」
と言った感じで、とにかく最小限の処理を考えます。
その最小限の処理が実装出来たら、今度はその処理に肉付けして、理想の処理にしていくような感じです。
現状のPlayerの状態をUnityでゲームを実行して見てみると、Rigidbody2Dの重力の影響を受け、下方向へ移動していきます。
ヒューンと落ちているように見えますね。
ゲーム実行画面
やりたい事が明確になったので、実際にスクリプトを書いてみましょう。
PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
#region Var-Jump
[Header("ジャンプ力")]
[SerializeField] float jumpPower = 1f;
#endregion
#region Var-Internal
Rigidbody2D playerRB; // プレイヤーのRigidbody2D
#endregion
#region Start
void Start()
{
// プレイヤーのRigidbodyを取得
playerRB = GetComponent<Rigidbody2D>();
}
#endregion
#region Update
void Update()
{
// スペースキーが押された場合
if (Input.GetKey(KeyCode.Space))
{
// ジャンプする
Jump();
}
}
#endregion
#region Jump
// ジャンプする
void Jump()
{
// プレイヤーに上方向のベクトルを持たせる
playerRB.velocity = Vector2.up * jumpPower;
}
#endregion
}ではコードを見ていきましょう。メンバ変数
最初に角カッコで括られたHeaderがありますが、これはUnityのInspectorビューに後ろの文字列、ここでは「ジャンプ力」という文字列を出せるようになるものです。
このplayerRBのvelocityにベクトルを与えて、プレイヤーを移動させます。
次は内部処理用の変数で、Rigidbody2DのplayerRBです。
変数に使用用途が書いてあれば分かりやすいですね。
次のSerializeFieldは、同じくUnityのInspectorビューに変数を表示できるようになります。
これでpublicな変数じゃなくても、Inspectorビューから変数の値、ここではjumpPowerがInspectorビューから値の変更が可能になります。
Start関数
次はStart関数です。Start関数内では、playerRBがアタッチしたオブジェクトのRigidbody2Dを取得します。
Update関数
次にUpdate関数です。
Update関数では、スペースキーが押された場合にJump関数を呼んでいます。
Update関数は毎フレームごとに処理されるので、Unityでゲームを実行している間中にスペースキーが押されるとJump関数が呼ばれる、という処理になります。
GetKeyとGetKeyDownの違いについて
ここで一つ説明ですが、GetKeyとGetKeyDownには違いがあります。
GetKeyは「キーが押された」という判定に対し処理が行われます。
対してGetKeyDownは「キーが押された状態からキーが離された」という一連の流れに対して処理が行われます。
実際にメモ帳やエディタでキーボード入力をしてみてください。
何らかのキーをずっと押している間は文字が入力され続けますよね?
この状態がGetKeyです。
GetKeyのイメージ
GetKeyDownの場合はどうかと言うと、「キーが押された状態からキーが離された」という一連の流れに対して処理が行われるので、キーを押しっぱなしでは動きません。
「キーが離された」状態になって、エディタで言えば初めて一文字入力できるようになります。
GetKeyDownのイメージ
これは結構な違いなので、ゲームを作る場合は注意が必要です。
この違いを理解しないままだと、理想の処理が作れない場合が出てきます。
Jump関数
最後はJump関数です。
Jump関数では、playerRBのvelocityを上方向とjumpPowerを掛けた値をベクトルとして持たせています。
これでスペースキーが押されたらジャンプするようになります。
velocity(ベクトル)での移動とTransformでの移動の違い
ここでまた説明です。
今度はvelocity(ベクトル)での移動と、Transformでの移動についてです。
移動する、という点においては、どちらも結果に違いは無いように見えます。
ところが、移動する過程に於いては、決定的な違いがあります。
ベクトルを与えると言うのは、運動量を与えることと同義です。
Unityで言えば、昔小学校の授業で教わった自動車の等速直線運動と同じ動きの仕方を与える、という事になります。
だからUnityで非現実的な非推奨の動かし方だ、って言われたんですね。
そんなvelocityに対してTransformでの移動というのは、現在のオブジェクトの位置から次のオブジェクトの位置まで、簡単に表すと「瞬間移動している」という事になります。
何のこっちゃ?と思われるかも知れませんが、
「velocity(ベクトル)で動かす場合はdeltaTimeの掛け算は不要」
「Transformで直接動かす場合はdeltaTimeの掛け算が必要になる」
という事になります。
よく考えてみると、ベクトル(矢印)を表す場合は、「何が」「どれくらい」「どの方向へ移動」したかを表す必要があります。
そうなると、矢印の縦棒の大きさは「ゲーム内時間を含んで」作成されないと、矢印は作れないことが分かります。
移動するための矢印(ベクトル)を表すには、小学校で習った
距離=速さ×時間
になるので、時間という要素が含まれるわけです。
ベクトルでの移動のイメージ
対してTransformでの移動の場合は、瞬間移動になるので「瞬間移動する先の座標」さえ分かっていれば、後は瞬間移動するだけになります。
ですので、PCのスペック差を埋めるためにdeltaTimeを掛けて、そのギャップを無くしているわけです。
Transformでの移動のイメージ
全く同じルートを通る、二つの異なるスペックのPCで、deltaTimeでの調整が無いとします。
そのスペック差がゲームを実行するとAのPCは1秒で、BのPCは0.5秒だとします。
この差は同じゲームでも歴然になりますね。
その位の差が出るようなPCでも、出来る限り同じ動作になるようにしているのがdeltaTimeになります。
そしてdeltaTimeを含んでいるのがベクトル(矢印)になるわけです。
説明されている記事をあまりみかけなかったので、改めて説明しました。
ここら辺もゲームを作る際に覚えておかないと、予想の動きと全然違うものになったりするので注意してください。
プレイヤーへスクリプトをアタッチする
これでオブジェクトが上方向へ移動できる処理を作れたので、上方向へ移動するという処理を持ったスクリプトを、プレイヤーにアタッチしてあげます。
PlayerControllerスクリプトをドラッグしてPlayerにドロップします。
PlayerControllerスクリプトをPlayerにアタッチする
アタッチできたら、InspectorビューのJumpPowerを調整します。
このゲームでは4にします。
InspectorビューのJumpPowerを4にする
それではゲームを実行して確認します。
スペースキーの入力毎にプレイヤーが上方向へ移動する
無能が説明した内容を確認するために、GetKeyDownでの動きの違いや、二台の違うPCをお持ちでしたらTransformでの移動などもお試しください。
理解がより深まると思います。
まとめ
今回は
- プレイヤーにコンポーネントをアタッチした
- スクリプトを作成し、プレイヤーが上方向へ移動する処理を書いた
- プレイヤーに作成したスクリプトをアタッチしてジャンプできるようになった
という事をやりました。
次回は、土管の画像を入手して、それをゲーム内に登場させたいと思います。
では、また次回!




















コメント
コメントを投稿