この記事はロックマン風2D横スクロールアクションゲームの作り方講座の第2回です。
前回はプロジェクトの作成と画像素材、そしてDoTweenアセットのインポート等の開発準備を行いました。
前回の記事:
いよいよゲームの中心となる要素を作り始めていきましょう。
今回の記事では主人公キャラクターのオブジェクトを作成し、スクリプトを組み、物理演算を実装して基本的なアクション操作を実現するところまで作っていきましょう。
2Dアクションゲームのプレイヤーキャラクターオブジェクトを作成
一番最初に主人公となるプレイヤーキャラクターのオブジェクトから作成しましょう。
オブジェクトの作成は画面上部にある[GameObject]バーをクリックして行います。続いてどの種類のオブジェクトを作成するかを選択していきます。2Dゲームの場合、画面上を動くオブジェクトは基本的にスプライト(Sprite)オブジェクトとして作成するので以下のように選択しましょう。
[2D Object]→[Sprites]→[Square](※Sprites以下はオブジェクトの初期画像が変わるだけなのでどれを選んでも問題なし)と進めてみましょう。
SceneビューやGameビューを見れば白い四角形のオブジェクトが作成されているのが確認できます。
同時にエディター画面左側にあるHierarchyビュー内に作成したオブジェクトの名前が「Square」として追加されています。
このHierarchyビューはシーン内にあるオブジェクトの一覧を表示するエリアです。シーンとはざっくり説明するとゲームの1ステージ分のことであり、ステージ内にモノを追加・配置していると考えると理解しやすいです。
Hierarchyビュー内にあるオブジェクト名をクリックするとそのオブジェクトが選択状態になります。
選択されたオブジェクトは画面右側にあるInspectorビューにおいて詳細が表示されます。ここからオブジェクトの情報を確認したり、位置や大きさ等のパラメータを変更したり、機能の追加・消去等さまざまな設定を行えます。
オブジェクトの名前を変更する事も出来るので、まずはこのSquareオブジェクトの名前を「Actor」に変更しておきましょう(PlayerなどでもOKですが今回の講座では主人公キャラ名をActorとしました)。Inspectorビューの最上部に名前入力ボックスがあります。
※左右のチェックボックスをうっかり触らないように注意
プレイヤーキャラクターの画像を仮設定
続いてはこのキャラクターオブジェクトに主人公の画像を表示させるようにしましょう。
スプライトオブジェクトとして作成した物は全てSprite Rendererというコンポーネント(機能)を持っており、ここで表示画像の設定が行えます。
コンポーネントの編集になるのでまずはInspectorビューを操作しましょう。
Sprite Rendererタブ内にあるSpriteと書かれた項目が表示画像の設定欄になるので、現在Square画像が割り当てられているのを変更すれば良いです。
変更先の画像は既にインポートされているはずですので、Projectビューから探しましょう。目的の画像は[Textures]フォルダ以下[Actors]→[Walks]と進むとあります。
ゲームで正式に使用する画像は今後、キャラクターアニメーションを実装する段階で設定しますので現時点ではどの画像を選んでも問題ありません。
使用する画像を決めたら、Projectビュー内の該当画像からInspectorビューのSprite欄までドラッグ&ドロップして反映させます。
ここではNormal_0を選択しました。これでオブジェクトの見た目がヒツジの画像に変わったはずです。
オブジェクトの大きさを調整
Gameビューを開くと分かるのですが、現段階ではオブジェクトの大きさが画面の表示範囲に対してやや大きいようです。
この場合は画像自体を小さくする、画像のインポート設定を変更する、カメラの表示範囲を広げる等いろいろな方法がありますが、今回はオブジェクトの大きさを変更する方法を使ってみます。
Actorオブジェクトを選択し、InspectorビューにあるTransformコンポーネントを確認します。
このTransformは全てのオブジェクトが必ず持っているコンポーネントであり、オブジェクトの位置(Position)や角度(Rotation)、拡大率(Scale)を設定できます。今回はScale値を変更しましょう。
Scale値は各方向で1が基準値なので、1より小さくするとオブジェクトも小さくなります。今回はX方向とY方向をそれぞれ0.4くらいにしてみます。Z方向は奥行きを表しているので今回は変更しなくてOKです。
Gameビューを見るとオブジェクトの表示が小さくなったことがわかります。
プレイヤーキャラクターを動かすC#スクリプトを作成
ここまででキャラクターの見た目はある程度できてきましたが、動きを設定していないのでゲームをテストプレイしても何も変化が起こりません。
ここからはC#スクリプトを作成し、主人公キャラをキーボードの操作で動かせるように実装していきましょう。
スクリプトの新規作成はProjectビューから行いますが、まずはスクリプトの置き場所を用意しておきます。
Assets/Scriptsフォルダ以下にActorフォルダを作成しましょう。今後主人公キャラクター関連のスクリプトを複数作成する予定です。似た機能を持つスクリプトを同じ場所に置いておくためにフォルダを用意しています。
フォルダの作成はビュー内の何もない場所で右クリック→[Create]→[Folder]から可能です。
フォルダを作成し、名前をActorに変えたらそのフォルダ内でスクリプトを作成します。
スクリプト名(クラス名)はActorControllerとします。
先ほどと同様に右クリック→[Create]→[C# Script]からスクリプトを新規作成できます…がここでの注意点として、新規作成直後の名前入力のタイミングできちんと名前を入力しきってください。
一度作成が完了したスクリプトファイルは後からファイル名を変更することができません(変更するとエラーが出ます)。忘れがちなので今後もスクリプト作成の際は気を付けてください。
作成が無事に終わったらそのスクリプトをエディター上でダブルクリックしてみましょう。スクリプトエディタが立ち上がるはずです。ここでプログラミング作業を行っていきます。
主人公キャラクターを左右移動させるスクリプト(仮)
それではActorControllerクラスを拡張していきます。
(基本的にUnity C#は1スクリプト=1クラスです。クラスの持つ機能を増やすようなイメージでスクリプトを組んでいきます。)
まずは左キー・右キーを押している間、その方向に移動し続けるスクリプトを仮作成します。(後程解説します)
ActorController.csを作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// アクター操作・制御クラス /// </summary> public class ActorController : MonoBehaviour { // 変数宣言部 // Start(オブジェクト有効化時に1度実行) void Start() { } // Update(1フレームごとに1度ずつ実行) void Update() { // 仮の移動処理 if (Input.GetKey (KeyCode.RightArrow)) {// 右方向の移動入力 Vector2 pos = transform.position; pos.x += 0.05f; transform.position = pos; } else if (Input.GetKey (KeyCode.LeftArrow)) {// 左方向の移動入力 Vector2 pos = transform.position; pos.x -= 0.05f; transform.position = pos; } } } |
スクリプトは基本的に作成しただけではゲームに反映されません。シーン内のオブジェクトにコンポーネントとして取り付ける(アタッチする)ことによって初めてスクリプト内の処理が実行されるようになります。
アタッチ操作はProjectビューのスクリプトからInspectorビューの下端(空いている場所)にドラッグ&ドロップすれば完了です。
これでActorオブジェクトにActorControllerの機能が追加された形になります。
ActorControllerスクリプトの解説
先ほどのスクリプトを大まかに解説していきます。
①using部
using文によりUnity標準の機能等を呼び出して使用できるようにしています。
外部プラグインの機能などを使用する場合は別途using文をここに書き加えていく形になりますが、今回は変更不要です。
②クラス宣言部
新規クラスの作成を宣言しています。
クラスの名前もここで決定しています。ファイル名とクラス名が異なっているとエラーが出ます。
ここからの波カッコ内にクラスの処理などを書き込んでいきます。
③変数宣言部
このクラスが持つメンバ変数(フィールドともいいます)を宣言・定義する場所です。
場所自体はどこでもいいのですが、このように先頭の位置に書くのが慣例になっています。
変数は以下のような形で宣言でき、以降そのクラス内で自由に値の変更が可能になります。
1 |
public int hoge = 1; // hogeという名前のint(整数)型変数を、初期値1でpublicで宣言している |
現在はメンバ変数を使用していないのでこの場所は空欄になっています。
④Startメソッド
スクリプトにおいて具体的な処理の実行はメソッドと呼ばれる枠組みの中に書き込んでいきます。メソッドを呼び出すと波カッコ内の上に書いてある処理から順番に実行されます。
今回はStartメソッド内で「Debug.Log」という処理を呼び出しています。この呼び出しによってUnityエディターの画面上で任意の文字列や変数の状態を確認できます。
StartメソッドはUnityで定義されている特殊なメソッドの1つで、このスクリプトがアタッチされているオブジェクトが有効状態になった直後に1回だけ自動的に呼び出されます。(シーンに最初から配置されているオブジェクトだった場合、シーン開始直後に呼ばれます)
⑤Updateメソッド
Startと同様に特殊なメソッドであり、このUpdateメソッドはゲーム内において1フレームごとに1回呼び出されます。
1フレームごとの実行なのでゲームのフレームレートが変われば実行回数も変わることを覚えておきましょう。
今回はUpdateの中に、「左右の矢印キーを押したらその方向にオブジェクトが移動する」という処理を書いています。
1 2 3 |
if (Input.GetKey (KeyCode.RightArrow)) { } |
と書く事により、「右矢印キーを押しているなら波カッコ内の処理を実行」という条件判断が出来ます。その波カッコ内で
1 2 3 |
Vector2 pos = transform.position; pos.x += 0.05f; transform.position = pos; |
という処理を書く事で、結果的に「右矢印キーを押している間はTransformのposition.x値が増加する」動作になります。
そしてif-else文を使用して左矢印キーの場合の処理も同様に書いていきます。
以降、Unity C#の初歩となる要素に関しては解説を割愛させていただく事もあるので以下の記事から予習しておく事をおすすめします。
Unityで再生して動作確認
エディター画面上部中央にある▶ボタンを押すとテストプレイを開始できます。
左右矢印キーの押下で主人公キャラが横に移動する事を確認しましょう。
2Dアクションゲームに必要な物理演算を用意する
さて、これで一見主人公キャラの左右移動は完成したように見えますがこのままではアクションゲームを作成するのに適した状態ではありません。
現在プレイヤーキャラクターには物理演算の機能が盛り込まれていないので、後にジャンプを実装したり床や壁との接触を判定するために新たなコンポーネントをアタッチする必要があります。
2Dオブジェクトに物理演算を組み込む場合はRigidbody 2Dコンポーネントを使用します。
Actorオブジェクトを選択し、Inspectorビュー下端の[Add Component]ボタンを押下します。
- コンポーネントの詳細表示はコンポーネント名左側の三角ボタンで折りたたむ事が可能です。
このRigidbody 2Dをアタッチしたことで、このActorオブジェクトは物理的な動きを行うようになりました。例えば、今テストプレイを開始すれば重力に従って画面の下端まで落下して消えていきます。
このままではすぐ画面から消えて確認が難しいので、仮の地面オブジェクトを用意しておきましょう。
Actorオブジェクトを作成した時と同様に新規のSpriteオブジェクトをシーンに作成します。オブジェクト名は仮でGroundとしました。
GroundオブジェクトをActorオブジェクトの初期位置よりも下側に、かつ画面に収まる範囲に移動させます。Transform-Position座標を(X:0, Y:-3.5)くらいに変更します。
さらにオブジェクトを横長にするために、ScaleのX値を10くらいに大きくします。
そしてこのGroundオブジェクトにもRigidbody 2Dコンポーネントを付与します。
後でRigidbody 2Dに関しては大まかに解説しますが、ここではBody TypeパラメータをDynamicからKinematicに変更しておきます。この操作によってGroundオブジェクトは重力の影響を受けて落下しなくなります。
この状態でテストプレイすると、Actorオブジェクトのみが落下する事を確認できますがGroundオブジェクトをすり抜けてしまいます。これは2つのオブジェクトに当たり判定を設定していないためです。
地面の当たり判定をBoxCollider2Dで実装する
まずはGroundオブジェクトに対して当たり判定を設定していきます。
四角形の当たり判定はBox Collider 2Dコンポーネントをアタッチする事で設定可能です。
このコンポーネントはアタッチされた時に自動で当たり判定の大きさを(画像の大きさに合わせて)セットしてくれるので、今回はパラメータの変更なしでOKです。
プレイヤーキャラクターとの当たり判定をBoxCollider2Dで実装する
ActorオブジェクトにもBox Collider 2Dコンポーネントをアタッチします。
Sceneビューに表示される緑色の枠線が当たり判定を示しているのですが、今回は羊の画像に対してちょっと判定が大きいように見えます。
画像の大きさに合った当たり判定にするために自分でパラメータを変更してみましょう。
Box Collider 2Dコンポーネントの主要なパラメータは以下のようになっています。
パラメータ名 | 解説 |
Is Trigger | トリガーモード設定 オンにすると他のオブジェクトとぶつからなくなるが、スクリプトで接触を判定する事は可能。 |
Used By Effector Used By Composite |
他のEffector・Compositeコンポーネントを使用する場合はオンにする |
Offset | 当たり判定の中心をX・Y方向それぞれにずらす距離 |
Size | 当たり判定のX・Y方向それぞれの大きさ |
今回はOffsetとSizeを変更すればよい事が分かります。
今回はOffsetを(0.16, -0.24)、Sizeを(2.12, 3.2)に変更しておきます。
これでテストプレイを行えば、プレイヤーキャラクターが地面にしっかり着地することが確認できます。
Rigidbody 2Dのパラメータ解説
Rigidbody2Dは沢山のパラメータを持っています。よく変更する設定は以下です。
パラメータ名 | 解説 |
Body Type | 物理演算のモードを設定する。 Dynamicにすれば通常の動作し、Kinematicにすれば他のオブジェクトや重力に影響を受ける事がない。 以下のパラメータ解説はDynamic時のもの。 |
Material | 物理演算マテリアル設定(摩擦率などを変更可能) |
Mass | 物体の質量 |
Linear Drag | 移動時に受ける空気抵抗(減速率) |
Angular Drag | 回転時に受ける空気抵抗(減速率) |
Gravity Scale | 重力影響度。2にすると2倍の重力を受けるようになる |
Collision Detection | 物体との接触判定方法。移動する物体同士のすり抜けを防ぎたい時はここをContinuousに変更すると改善する。 |
ActorオブジェクトのRigidbody 2Dコンポーネントは特にパラメータの変更の必要はありません。強いて言えばCollision DetectionをContinuousに変更しておくと安心かもしれません。
重力の基準値を変更
先ほどGravity Scaleの説明でも触れましたが、Rigidbody 2Dを持つオブジェクトは常に下方向への力(重力)を受けています。
この基準値についてはProject Settings画面から確認・変更する事が可能です。画面はエディター左上の[Edit]タブから[Project Settings…]から開く事が可能です。
ウィンドウ左側に沢山のサブメニューが存在していますが、物理演算の設定は[Physics 2D]から行うのでこれを選択します。そして右側エリアの一番上にあるGravityパラメータが重力設定になっています。
初期の重力値はY方向に-9.81となっています。これは地球の重力加速度と同じでリアルな数値ではありますが、2Dアクションゲームとして見るとややフワフワした挙動になってしまいます。
ある程度上下方向にもキビキビ動いて欲しいのでこの値を-30に変更してみましょう。
この状態でテストプレイをすれば一瞬で接地するようになったことが確認できます。
プレイヤーキャラクター左右移動スクリプトの仕上げ
ここまででオブジェクトに物理演算を組み込む事が出来たので、スクリプトでもそれを使用するように変更します。
それと同時に新しいメソッドを使用する方法や、FixedUpdateの使用についても学んでいきましょう。
ActorControllerクラスを以下のように拡張します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// アクター操作・制御クラス /// </summary> public class ActorController : MonoBehaviour { // オブジェクト・コンポーネント参照 private Rigidbody2D rigidbody2D; // Rigidbody2Dコンポーネントへの参照 // 移動関連変数 private float xSpeed; // X方向移動速度 // Start(オブジェクト有効化時に1度実行) void Start() { // コンポーネント参照取得 rigidbody2D = GetComponent<Rigidbody2D> (); } // Update(1フレームごとに1度ずつ実行) void Update() { // 左右移動処理 MoveUpdate (); } /// <summary> /// Updateから呼び出される左右移動入力処理 /// </summary> private void MoveUpdate () { // X方向移動入力 if (Input.GetKey (KeyCode.RightArrow)) {// 右方向の移動入力 // X方向移動速度をプラスに設定 xSpeed = 6.0f; } else if (Input.GetKey (KeyCode.LeftArrow)) {// 左方向の移動入力 // X方向移動速度をマイナスに設定 xSpeed = -6.0f; } else {// 入力なし // X方向の移動を停止 xSpeed = 0.0f; } } // FixedUpdate(一定時間ごとに1度ずつ実行・物理演算用) private void FixedUpdate () { // 移動速度ベクトルを現在値から取得 Vector2 velocity = rigidbody2D.velocity; // X方向の速度を入力から決定 velocity.x = xSpeed; // 計算した移動速度ベクトルをRigidbody2Dに反映 rigidbody2D.velocity = velocity; } } |
- メンバ変数としてRigidbody2Dへの参照を持てるようにしています。そしてStartメソッド内のGetComponent呼び出しにより、このクラスがアタッチされているオブジェクト内にあるRigidbody2Dコンポーネントへの参照を取得しています。
- MoveUpdateメソッドを自作してUpdate内から呼び出しています。このようにクラスの機能としてメソッドを簡単に増やすことができます。
- 以降、エディター上にてrigidbody2Dという変数名に対して警告文が表示される場合がありますが無視してもOKです。気になる方は変数名の変更などで警告が消えます。
最後にFixedUpdateというメソッドが出てきました。このメソッドはUnity標準の機能の1つであり、Updateと似たように何度も自動で呼び出されるメソッドです。
Updateの場合は1フレームごとに1回呼び出されていました(つまりフレームレートの変動によって処理の頻度が変化する可能性があります)が、FixedUpdateは一定時間ごとに1回呼び出されます。つまり毎フレーム実行される訳ではありませんが、基本的に呼び出し間隔は同じです。
このメソッドは物理演算と相性が良いので、今後Rigidbody 2Dのパラメータを継続的に変更することがある場合はFixedUpdateを使用していきます。もしUpdateで書いた処理がうまく動かなかったらFixedUpdateを試してみる、というクセを付けると良いかもしれません。
現在の状態でテストプレイをしても、左右移動するという見た目は同じなのであまり変化はありません。
移動時に主人公キャラクターの向きを設定&変更する処理を追加
左右に移動できるようになったので、「プレイヤーキャラクターが左に移動したら画像(スプライト)も左を向く」という機能も追加してみます。
2Dオブジェクトの画像表示はSprite Rendererコンポーネントが担いますので、スクリプトでもこれにアクセスする形で使用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// アクター操作・制御クラス /// </summary> public class ActorController : MonoBehaviour { // オブジェクト・コンポーネント参照 private Rigidbody2D rigidbody2D; private SpriteRenderer spriteRenderer; // 移動関連変数 [HideInInspector] public float xSpeed; // X方向移動速度 [HideInInspector] public bool rightFacing; // 向いている方向(true.右向き false:左向き) // Start(オブジェクト有効化時に1度実行) void Start() { // コンポーネント参照取得 rigidbody2D = GetComponent<Rigidbody2D> (); spriteRenderer = GetComponent<SpriteRenderer> (); // 変数初期化 rightFacing = true; // 最初は右向き } // Update(1フレームごとに1度ずつ実行) void Update() { // 左右移動処理 MoveUpdate (); } /// <summary> /// Updateから呼び出される左右移動入力処理 /// </summary> private void MoveUpdate () { // X方向移動入力 if (Input.GetKey (KeyCode.RightArrow)) {// 右方向の移動入力 // X方向移動速度をプラスに設定 xSpeed = 6.0f; // 右向きフラグon rightFacing = true; // スプライトを通常の向きで表示 spriteRenderer.flipX = false; } else if (Input.GetKey (KeyCode.LeftArrow)) {// 左方向の移動入力 // X方向移動速度をマイナスに設定 xSpeed = -6.0f; // 右向きフラグoff rightFacing = false; // スプライトを左右反転した向きで表示 spriteRenderer.flipX = true; } else {// 入力なし // X方向の移動を停止 xSpeed = 0.0f; } } // FixedUpdate(一定時間ごとに1度ずつ実行・物理演算用) private void FixedUpdate () { // 移動速度ベクトルを現在値から取得 Vector2 velocity = rigidbody2D.velocity; // X方向の速度を入力から決定 velocity.x = xSpeed; // 計算した移動速度ベクトルをRigidbody2Dに反映 rigidbody2D.velocity = velocity; } } |
spriteRendererのflipXパラメータをオンにすると表示が左右反転されるのでこの機能を利用しています。
また、今後使用する可能性があるため現在の向きを記憶するrightFacing変数も宣言しています。
また、移動関連変数の宣言をpublicに変更しています。こうするとこの変数は他のクラスからも参照したり変更する事が可能になります。
現在はActorControllerクラス1つしか書いていないので関係ありませんが、今後ActorControllerクラスを参照する別のクラスを実装する時にこれらの変数を使用する想定であるためpublicにしています。
なお実際にはpublic変数の使用は非推奨です。今回は講座なのでスクリプトを簡略化させるために今後もpublicを多用していきますが、厳密には全てprivateで宣言をし、publicメソッドからこれらの値の参照・変更を行うようにした方が好ましいことは覚えておいてください。
ちなみにpublic変数はエディター画面のInspectorからでも値の参照・変更が可能になります。今回の変数2つに関してはその必要はないため、[HideInInspector]属性を付与してInspectorからの表示を隠しています。
この状態でテストプレイすれば、しっかりと主人公キャラが移動方向に応じて向きを変えていることが確認できます。
まとめ
ここまでで主人公キャラクター(Actorオブジェクト)の左右移動および物理演算に則した重力落下までを実装できました。
まだプレイヤーキャラクターの基本動作は完成からは程遠いですが引き続き開発を続けていきましょう。一歩ずつ開発を進めて立派なロックマン風2Dアクションゲームに昇華させていきます。
では、次回はジャンプ処理の実装からになります。
次の記事:
コメント