本講座ではUnityで3Dレースゲームの作り方について説明しています。今回は第6回となります。
前回はレーシングゲームにおけるタイマー計測・ラップのカウント処理・スタート処理・ゴール処理などのUI周りの必須機能を作成しました。
前回の記事 :
今回はさらにUI機能を拡張していきます。レースゲームに必要な真上から見たような俯瞰ミニマップを作成し、ゴール後にリセットできる処理を追加していきます。
特に俯瞰ミニマップの作成手順はレースゲームだけでなく、ローグライクやアクションゲームやシミュレーションゲームなど幅広いジャンルで応用可能なスキルになります。ぜひここでマスターしていってください!
では始めていきましょう!
Unityで俯瞰ミニマップを作成しよう
では早速、俯瞰ミニマップの作成をしていきます。
RawImageへカメラ画像の投影
まずはカメラ画像をRawImageに映す方法を解説していきます。
まずはHierarchyでCanvasで右クリック「UI→Raw Image」でCanvasの子にRawImageを作成します。このRawImageの名前を「Map」としておきましょう。
そして「Map」を選択しInspectorのRectTransformを下記のように位置、大きさ、Anchor、Pivotを設定します。
1 2 3 4 |
Anchor : 左上 PosX = 0, PosY = 0, PosZ = 0 Width = 400, Height = 400 Pivot x = 0, y = 1 |
これで左上にピッタリくっついたかと思います。(GameViewのサイズ設定によって見た目が少し違うと思います。下記画像は画面を「2048*1536 Landscape」に設定しています)
次にカメラを作成します。
まずは、Hierarchyで右クリック「Create Empty」で空オブジェクトを作成し、「MapCamRoot」という名前にします。そしてこの「MapCamRoot」で右クリックをして「Camera」を子に作成します。
リトライ
では次にリトライ処理を作成しましょう。ゴールしたらUボタンを表示して押したら再スタートという形にしていきます。
UIの作成
あまりかっこよさは考えずサクッと作成していきます。
Hierarchyの「Canvas」の子に空オブジェクトを作成し「Retry」という名前にします。そしてその子にUIから「Image」「Text」「Button」を作成します。「Image」を「Bg」、「Text」を「Title」、「Button」をそのまま「Button」という名前にします。
この時上から「Bg」が一番上に来るようにだけ注意してください。これは上にあるほうがカメラに映る際後方に表示されます。試しに「Bg」を「Text」や「Button」より下(Retryの子のまま)に移動してみると「Text」「Button」より前に「Bg」が来て暗くなっているのがわかるかと思います。(戻しておきましょう)
親である「Retry」も含めて、「RectTransform」で位置、大きさを以下の画像を参考にして設定してください(個々人でカスタマイズしてもOKです)。RectTransformをStretchにして全ての値を0にすると画面全体に引き伸ばされます。また、Bgの色を設定する際にalpha値を100程度にして半透明化しておきましょう。
また、Imageの色、Textの大きさや文字なども同じように設定してみてください。だいたい見た目がよければ問題ありません。(Button内の文字はButtonの子にあるTextで設定できます)
これらを設定すると下記のようになります。できたら親の「Retry」を選択しInspectorの名前の横にあるチェックマークを外して非アクティブにしておきましょう。
リトライUIの起動処理
ではまずUIを起動する処理を作成します。ゴールしたときに表示して、再スタートしたら消せばOKです。
まずは「PlayerContoller.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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
public class PlayerController : MonoBehaviour { ・・・ // 開始時位置. Vector3 startPosition = Vector3.zero; // 開始時角度. Quaternion startRotation = Quaternion.identity; ・・・ // ------------------------------------------------------------ /// <summary> /// カメラの車追跡. /// </summary> // ------------------------------------------------------------ void TrackingCameraUpdate() { // オフセット値を現在の角度で回転. var rotOffset = this.transform.rotation * tpCameraOffset; // 現在の位置の値に算出したオフセット値をプラスしてカメラの位置を算出. var anchor = this.transform.position + rotOffset; // カメラの位置を現在位置から徐々に変更. tpCamera.gameObject.transform.position = Vector3.Lerp( tpCamera.gameObject.transform.position, anchor, Time.fixedDeltaTime * cameraTrackingSpeed ); // カメラを車の方向に向ける. var look = this.transform.position; look.y += cameraLookHeightOffset; tpCamera.gameObject.transform.LookAt( look ); } ・・・ // ------------------------------------------------------------ /// <summary> /// カウントダウンスタート時コール. /// </summary> // ------------------------------------------------------------ public void OnStart() { startPosition = this.transform.position; startRotation = this.transform.rotation; } // ------------------------------------------------------------ /// <summary> /// リトライ時コール. /// </summary> // ------------------------------------------------------------ public void OnRetry() { this.transform.position = startPosition; this.transform.rotation = startRotation; var rotOffset = this.transform.rotation * tpCameraOffset; var anchor = this.transform.position + rotOffset; tpCamera.gameObject.transform.position = anchor; } } |
まず変数は、「Vector3」の「startPosition」、「Quaternion」の「startRotation」を用意します。これは開始位置、角度を保管しておくためです。
(TrackingCameraUpdate関数は追記はありませんが、参考のために記載しています。)
新しく「OnStart」関数を作成します。これはカウントダウンがスタートした時に呼び出される処理です。処理は簡単で「startPosition」に現在の位置「this.transform.position」を、「startRotation」に現在の角度「this.transform.rotation」を代入しています。
もう一つ作成した関数は「OnRetry」で、これはリトライ時に実行されます。処理はまず「OnStart」とは逆に、現在の位置「this.transform.position」に「startPosition」を、現在の角度「this.transform.rotation」に「startRotation」を代入して初期化します。
その下の処理は「TrackingCameraUpdate」関数でカメラの位置を算出している処理と同じで、開始時に初期化された車の位置にカメラを合わせています。
続いて、「GameContorller.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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
public class GameController : MonoBehaviour { ・・・ // リトライUI. [SerializeField] GameObject retryUI = null; ・・・ void Start() { ・・・ retryUI.SetActive( false ); } ・・・ // ------------------------------------------------------- /// <summary> /// カウントダウンスタート. /// </summary> // ------------------------------------------------------- void CountDownStart() { currentCountDown = (float)countStartTime; SetPlayState( PlayState.Ready ); countdownText.gameObject.SetActive( true ); player.OnStart(); } ・・・ // ------------------------------------------------------- /// <summary> /// ゴール時処理. /// </summary> // ------------------------------------------------------- void OnGoal() { CurrentState = PlayState.Finish; countdownText.text = "Goal"; countdownText.gameObject.SetActive( true ); retryUI.SetActive( true ); } // ------------------------------------------------------- /// <summary> /// リトライボタンクリックコールバック. /// </summary> // ------------------------------------------------------- public void OnRetryButtonClicked() { retryUI.SetActive( false ); timerText.text = "Time : 000.0 s"; lapText.text = "Lap : 1/" + player.GoalLap; player.OnRetry(); CountDownStart(); } } |
変数は「SerializeField」で「GameObject」型の「retryUI」を用意します。Hierarchyの「Retry」をドラック&ドロップしておきましょう。
次に「Start」関数で「retryUI.SetActive( false )」つまりリトライUIを非アクティブにしておきます。
続いて「CountDownStart」関数に「player.OnStart()」を追加しプレイヤーの「OnStart」を実行します。
次にゴール時処理「OnGoal」関数に「retryUI.SetActive( true )」を追加し、ゴールしたらUIを表示します。
最後に「OnRetryButtonClicked」という関数を追加します。これはリトライボタンを押した時の処理になりますので後ほどUnityから設定しましょう。
処理はまず「retryUI.SetActive( false )」でUIを消して、「timerText」「lapText」をスタート時の状態に戻し、「player.OnRetry()」でプレイヤーのリトライ処理を実行します。
そして、「CountDownStart()」を実行することで再びカウントダウンから始まります。
ではUnityに戻って、まずRetryのInspectorへの設定します。
そして、リトライボタンのクリック処理にGameContollerをドラック&ドロップして「OnRetryButtonClicked」を設定しましょう。
では再生して、必要な周回数を走ってゴールしてみましょう。ゴール時にRetryのUIが出てきて、ボタンを押すと再びスタート地点からカウントダウンが始まればOKです。
今回はこれで以上となります。次回はCPUの他の車を作成していきましょう。
次回の記事 :
コメント