top of page

2Dランゲーム編

復習チャレンジ

​このページについて

 2Dランゲーム編を通して、Unityでのマウス操作や、少し高度なテクニックを身に着けました。

 ここでは2Dランゲーム編の内容を応用して、おはじきを飛ばして場外へ落とす対戦ゲームを作ってみましょう。対戦相手に衝突することでダメージを与えることができ、体力が減ると吹っ飛びやすくすることで対戦に緊張感を持たせます通信対戦ではなく、ローカルで1つのマウスを使って戦います

 このページは2Dランゲーム編の総まとめや、Unityを久しぶりに触る方の復習用に作られています。わからない場合は2Dランゲーム編を見ながら進めてみてください。答えは1つではありませんので、実装できれば手段は自由です。

準備

 まずは2Dコア(2D URPでも可)を選択して、適当なプロジェクトを作成してください。

​ バージョンやプロジェクト名は自由です。

3Dアクションゲーム編1-12Dランゲーム編1-1参照)

 次に素材配布所(https://drive.google.com/file/d/1ZdN4RiIrloow7i4fd1zH9QPta3VzLCad/view?usp=sharing)からパッケージをダウンロードして、Unityにインポートしてください。

​ Mainシーンを開くと、ステージとUIが配置されたシーンが開きます。

 このパッケージには使用する画像と一部のスクリプト、TextMeshProが同梱されています。

Q1 プレイヤーを飛ばす

 まずはマウスを引いた方向と逆方向にプレイヤーを飛ばしてみましょう。

​ このゲームには1Pと2Pが存在していますが、まずは1Pだけを完成させます

​ 「2D Object」→「Sprites」→「Circle」を追加してください。これがプレイヤー(おはじき)になります。

チャレンジ!

 作成したプレイヤーに対して以下の設定を行ってください。

① オブジェクト名をPlayer1にする

② X座標を-8にする

③ Playerタグを設定する

​④ Circle Collider2DとRigidbody2Dをアタッチする

​⑤ 色を青にする

​・3Dアクションゲーム編1-4を参考にしてください

※ ただし ⑤ については画像を差し替えて自分だけのおはじきを作成してもOKです

 このままでは重力でプレイヤーが落下してしまうため、Rigidbody2DのGravity Scaleを0にしてください。

 空気抵抗であるLinear Dragを1に設定しましょう。空気抵抗が0だと、プレイヤーをはじいた際に移動が止まらなくなってしまいます(宇宙空間で物を押すと、空気抵抗がないためどこまでも進んでいくのと同じです)

 また、Collision Detectionを「Continuous」に変更して、プレイヤーが高速で移動しても壁を貫通しないようにしましょう。

※ Collision Detectionについては2Dランゲーム編1-2を参照してください

 次にヒエラルキー内にあるGameを選択してください。

​ GameオブジェクトにはGameManagerコンポーネントがアタッチされています。Player1を指定するパラメータがあるため、先ほど作成したPlayer1をドラッグアンドドロップして指定しましょう。

 それでは「プレイヤーをはじいて飛ばす」処理を実装します。

​ Scriptフォルダ内のGameManagerスクリプトを開いてください。

 GameManagerスクリプトには最初からゲームの状態を管理する処理と、プレイヤーの情報を格納する場所が用意されています。

 プレイヤーをはじく処理を実装しましょう。

 一見難しそうに感じるかもしれませんが、必要なものを1つずつ分解して考えていけば単純です。

① マウスが左クリックされた瞬間にマウスの座標(startMousePos)を記憶する

② 左クリックが離された瞬間のマウス座標からstartMousePosへ伸びるベクトルを計算する

​③ 計算したベクトル分の力をプレイヤーに瞬間的に加える

 引っ張った方向と逆方向に力を加える点に注意しましょう。

​ まずは ① マウスが左クリックされた瞬間にマウスの座標(startMousePos)を記憶する を実装しましょう。case GameState.enGameState_Pull: から break; の間にコードを書いていってください。

チャレンジ!

 GameManagerスクリプトに以下の処理を実装してください。

① 引っ張り中かそうでないかを格納するためのbool型の変数を追加

② クリック開始地点を格納するためのVector3型の変数を追加

もし①で実装した変数がfalseかつ、左クリックされた瞬間なら、①で実装した変数をtrueにして、②で実装した変数にマウスの座標を格納する

​・左クリックの検知については2Dランゲーム編1-6を参考にしてください

​・マウスのクリック位置は以下のコードで取得できます

 Input.mousePositionで現在のマウスのスクリーン座標を取得することができます。

​ ここで取得できる座標は「スクリーン座標系」であり、左下を(0,0)、右上を(画面の横幅,画面の縦幅) として計算しています。

 スクリーン座標系のまま計算を行ってしまうと画面サイズによって結果(はじく力)が変わってしまうことになりますそのため Camera.main.ScreenToWorldPoint( 変換したいスクリーン座標 ) を実行することで、ワールド座標系へ変換しているのです。

 よくわからない人は無理に理解しなくても構いません。ウィンドウサイズが変わってもゲームの結果を変えないおまじないのようなものだと思っておいてください。

Unity Tips!

 次に ② 左クリックが離された瞬間のマウス座標からstartMousePosへ伸びるベクトルを計算する と、​ ③ 計算したベクトル分の力をプレイヤーに瞬間的に加える を一気に実装します。

チャレンジ!

 GameManagerスクリプトに以下の処理を実装してください。

もし引っ張り中の変数がtrueかつ、左クリックが離された瞬間なら、現在のマウス座標からクリック開始地点へ伸びるベクトルを計算する

② プレイヤーに対して ① で計算したベクトル分の力を加える

③ 力を加える時に引っ張り中の変数をfalseに戻す

​・開始地点から終了地点へ伸びるベクトルの計算は2Dランゲーム編2-8を参考にしてください

・プレイヤーに対して瞬間的に力を加える方法は2Dランゲーム編1-5を参考にしてください

 ここまでのコードがうまくいっていれば、プレイヤーを引っ張って飛ばす処理が完成しています。

​ しかし、このままで壁にぶつかった際に跳ね返りません。物理マテリアルを実装して跳ね返るようにしてみましょう。

チャレンジ!

 LessonEX「物理マテリアル」を参考にして、壁に反射する物理マテリアルを作成し、プレイヤーに設定してください。

​・LessonEXで扱っているのは3Dの物理マテリアルですが、今回は2Dの物理マテリアルを作る点に注意しましょう

・Bouncinessの値は1にしてください

 現在の状態では、移動中にもはじくことができてしまいます。​移動がある程度終わるまで追加の入力ができないようにしましょう。

 移動中状態の終了判定は case GameState.enGameState_Moveing: から break; の間にコードを書いてください。

チャレンジ!

 GameManagerスクリプトに以下の処理を実装してください。

① プレイヤーに力を加える時に、m_nowStateをenGameState_Moveingへ切り替える

② プレイヤーへかかっている力が一定以下になった場合、m_nowStateをenGameState_Pullへ切り替える

 移動中に追加の入力ができなくなり、移動が​ある程度完了すると再度入力を受け付けるようになればOKです。

Q2 2人プレイヤーで交互に動かす

 1人で動かせるようになったため、2Pを追加しましょう。

​ 1Pをコピーして座標と色を変更してください。

チャレンジ!

 GameManagerスクリプトを改造して、2人プレイに対応してください。

① ターンの状態や、2Pを管理する変数を追加する

② 1Pのターン→2Pのターン→1Pのターン… と交互に操作できるようにする

​・移動待機から操作可能状態への遷移条件は「1Pと2P両方の移動速度が一定以下になったら」切り替わるように変更しましょう

Q3 ステージを作る

 ゲームを盛り上げるため、地形をもう少し複雑にしてみましょう。

チャレンジ!

 Tile Palletを使用して、壁を追加してください。場所は自由なので、ゲームが盛り上がるような配置を考えてみてください。

​・TilePalletは既に用意してあります

​ TilePalletの使い方は2Dランゲーム編2-1を参考にしてください

​・対象のTileMapは「Wall」に設定するようにしてください

​・対象のTileMapを「Ground」にして、地面の形を改造してもOKです

​ ぜひ面白いステージを作ってみてください!

Q4 矢印を表示する

 はじく方向がわかりやすいように矢印を表示してみましょう。

​ Spriteフォルダ内にあるArrowをシーン上にドラッグ&ドロップしてください。

 今回配置したArrowはPivotがLeftに設定されています。

​ Pivotは移動や回転の基準点で、今回の場合は矢印の左端を基点に回転するようになります。

Unity Tips!

 矢印を配置できたら、矢印を表示してみましょう。

​ 発射する方向へ矢印を回転させて、ベクトルの大きさを使って拡大率を調整します

チャレンジ!

 引っ張っている間、矢印を表示する処理を実装してください。

① 矢印のオブジェクトを指定するための変数を用意する

② ゲームの開始時に矢印を非表示にする

③ 引っ張っている間、矢印を表示して回転と拡大率を変更する

  矢印の座標を操作中のプレイヤーの座標に移動させる

④ 引っ張り終了(クリックが離された瞬間)に矢印を非表示にする

・発射用ベクトルの方向へZ軸周りに回転する処理のサンプルです

​ 発射用ベクトルは現在のマウス座標から引っ張り処理開始地点へ伸びるベクトルです

         // ベクトルの方向を角度に変換
         float angle = Mathf.Atan2(発射用ベクトル.y, 発射用ベクトル.x) * Mathf.Rad2Deg;
         // Z軸周りに回転
         Arrow.transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));

Q5 体力システムを実装する

 プレイヤーに衝突された時にダメージを受け、体力の残量に応じて摩擦係数を調整することで滑りやすくしましょう。

​ Playerスクリプトを作成して、以下のパラメータを作成してください。

チャレンジ!

 自分にプレイヤータグが設定されたオブジェクトが衝突した時、自分の現在体力(m_nowHP)を一定量減らすようにしてください。減らす量はお好みで構いません。

① 開始時に必要なコンポーネントを取得し、現在体力の値を最大体力の値にする

② 自分にプレイヤータグが設定されたオブジェクトが衝突した時、体力を減らして摩擦係数を調整する

・衝突判定に使う関数は3Dアクションゲーム編3-6を参考にしてください

・自分のターンの時に自分がダメージを受けないようにしてください

​ (この措置を行わないと、自分から体当たりした時に自分もダメージを受けてしまいます)

​・摩擦係数(drag)は以下の計算式で調整してください

         float fill = (float)m_nowHP / (float)MaxHP;
         m_rigidBody2D.drag = 0.4f + (2.0f * fill);

 見た目では分かりにくいかもしれませんが、衝突する度にRigidbody2DのLinear Dragの値が減少していればOKです。

Q6 UIを更新する

 現在のプレイヤー名や体力バーの表示を更新しましょう。

チャレンジ!

 HPバーの画像と現在のプレイヤー名を表示しているTextMeshProを、適切な表示になるように更新してください。HPバー本体は「BarHP」、プレイヤー名は「TimeText」が表示しています。

・HPバーの更新は2Dランゲーム編4-3を参考にしてください

 ゲームの状況に応じてUIが更新されるようになったらOKです。

​ 自信のあるひとはHPゲージに減少演出を加えるなど、よりUIを華やかにしてみてください。

Q7 勝敗判定をする

 あと少しです!

​ 次はプレイヤーが地面からはみ出た時に、はみ出なかった方のプレイヤーを勝利として、UIを表示してみましょう。

(執筆中)

河原電子ビジネス専門学校
​ゲームクリエイター科

bottom of page