前回はPaddleがCylinderをキャッチするとScoreが加算されるようにしました.今回はPaddleが3回Cylinderをキャッチし損ねるとGAME OVERの表示が出るようにしたいと思います.
まずGAME OVERの表示をするPanelを作成します.HierarchyビューのCanvasを右クリックして[UI]→[Panel]を選択します.Canvasの下にもう一つのPanelであるPanel (1)ができますのでそれをGameOverPanelにリネームしましょう: 次に"GAME OVER"のテキストを表示するText Mesh Proを用意しましょう.HierarchyビューでGameOverPanelを選択した状態で右クリックし,[UI]→[Text - TextMeshPro]を選択します.GameOverPanelの下にText (TMP)ができますのでGameOverTextにリネームします: この状態でSceneビューを見ると次のようになってます(画面はMove Tool選択時です): ゲームをプレイ中はこのGameOverPanelを非表示にしておき,ゲームオーバーになったら表示するようにします.そこでこの画面中央に表示されている"New Text"の文字を"Game Over"に変え,位置や色やフォントなどを変えておきましょう.
HierarchyビューでGameOverTextが選択された状態でInspectorからRect TransformのWidthとHeightをそれぞれ800,200に変えます.続いてText Mesh Pro UGUI (Script)の中のTextの項目の中の"New Text"と表示されたところを"Game Over"に書き換え,Font Styleを太字(Bold),Font Sizeを130,Alignmentを上下左右ともに中央寄せにします: 今回はScoreTextと同じfont Assetを使用しますが,もちろん変えても構いません.注意してほしいのは同じfont Assetを使用している場合,fontの見た目(FaceやOutlineなど)を片方で変えるともう片方も共通なので同じように変わってしまうという点です.同じfont Assetを使用しているのだから当然ですね.さて,今回,Game Overの表示の下にReplayボタンを配置したいのでSceneビューで"Game Over"のテキストを少し上にずらしておきましょう.大体この辺にします: 次にReplayボタンをこのパネルに取り付けます.HierarcyビューでGameOverPanelが選択された状態で右クリックし,[UI]→[Button - TextMeshPro]を選択します.ButtonがGameOverPanelの下にできるので左側の三角のマークをクリックしてButtonの下のText (TMP)を表示し出てきたText (TMP)をReplayTextにリネームします: この状態で再びHierarchyビューでButtonを選択しRect TransformのWidthとHeightをそれぞれ300と80にします.それからMove Toolで”Game Over”の表示の下に持っていきます.次にHierarchyビューでReplayTextを選択し,Text Mesh Pro UGUI (Script)のTextをReplay?にし,Font Sizeを60,Font Styleを太字(Bold),Alignmentを上下左右全て中央寄せにします: Sceneビューはこんな感じです: 本当はフォントをもっとカッコよくしたいところですが,フォントのインストールやfont Assetの作成など色々大変ですのでまた別の機会にご紹介したいと思います.今回はボタンの背景色とPanelの色を変えてGame Over画面のデザインは終了とします.
HierarchyビューでButtonをクリックし,InspectorビューのButton (Script)のNormal Colorを変えます.ここでは緑色に変えてみます.またHierarchyビューでGameOverPanelをクリックしてInspectorビューのImage (Script)のColorをやはり緑色にして,Alpha値を100にします.出来上がったGame Over画面はこんな感じです: ここまで来たらスクリプトの作成に入りますが,その前にGameOverPanelを非表示にしておきましょう. ゲームオーバーになった時に表示させます.HierarchyビューでGameOverPanelを選択しInspectorの一番上のGameOverPanelの左のチェックを外します: これで初期状態ではGameOverPanelが非表示になりましたので,画面にはReplayボタンもなくなりました.次はスクリプトです.今回はPaddleが3回Cylinderをキャッチし損ねるとGameOverPanelが表示されるようにしたいので1回キャッチし損ねるたびにカウントされる変数loseを用意しましょう.この変数はゲーム開始時から存在してDestroyされないオブジェクトに付けたいのでTextControllerに記述することにします.次のように入力しましょう:
using UnityEngine; using TMPro; public class TextController : MonoBehaviour { int score = 0; public TextMeshProUGUI scoreText; GameObject panel; int lose = 0; public void AddScore() { this.score++; } public int AddLose() { this.lose++; return lose; } // Start is called before the first frame update void Start() { panel = GameObject.Find("Panel"); scoreText = panel.GetComponentInChildren<TextMeshProUGUI>(); } // Update is called once per frame void Update() { scoreText.text = "Score:" + score.ToString(); } }
このスクリプトではメソッドAddLoseだけが定義されてます.また,AddLoseはほかのスクリプトで利用できるよう戻り値としてloseを返しています.次に画面外にCylinderが出てしまったときにAddLoseを実行するためにCylinderControllerに次のように記述します:
using UnityEngine; public class CylinderController : MonoBehaviour { float speed; float rotx; float roty; float rotz; float rndx; float rndy; float rndz; public GameObject canvas; public GameObject paddle; public Transform gameoverPanel; // Start is called before the first frame update void Start() { speed = Random.Range(20f, 50f) * Time.deltaTime; rotx = 0; roty = 0; rotz = 0; rndx = Random.Range(-500f, 500f) * Time.deltaTime; rndy = Random.Range(-500f, 500f) * Time.deltaTime; rndz = Random.Range(-500f, 500f) * Time.deltaTime; } // Update is called once per frame void Update() { rotx += rndx; roty += rndy; rotz += rndz; transform.rotation = Quaternion.Euler(rotx, roty, rotz); transform.Translate(0f, 0f, -speed, Space.World); if (transform.position.z < -25) { canvas = GameObject.Find("Canvas"); int lose = canvas.GetComponent<TextController>().AddLose(); if (lose == 3) { gameoverPanel = canvas.transform.Find("GameOverPanel"); gameoverPanel.gameObject.SetActive(true); paddle = GameObject.Find("Paddle"); Destroy(paddle); } Destroy(gameObject); } } }
このコードはCylinderが画面外に出たら(z < -25),TextControllerのAddLoseを実行してloseを1増やし,loseが3になったらGameOverPanelを表示してpaddleを消滅させるというものです.一点注意すべきなのが,gameoverPanelをGameObjectのクラスではなくTransformのクラスにしている点です.というのもデフォルトではGameOverPanelは非表示つまりSetActiveがfalseになっているのですが,SetActiveがfalseのGameObjectはGameObject.Findメソッドで見つけることができないのでtransform.Findを使用しなければならないからです.またtransform.Findは親オブジェクトを指定したときに子オブジェクトを見つけるものなので親オブジェクトも先に見つけておかなくてはなりません.このため,上記コードのようにスクリプトを記述します.
これでReplayボタン以外ができました.次にReplayボタンのスクリプトを作成します. ProjectビューのAssetsフォルダ内で右クリックして[Create]→[C# Script]を選択し,できたファイルの名前をReplayScriptとして保存し,ダブルクリックして次のコードを入力します:
using UnityEngine; using UnityEngine.SceneManagement; public class ReplayScript : MonoBehaviour { public void OnClick() { SceneManager.LoadScene(0); } }
このスクリプトはReplayボタンが押されたときに最初(Scene番号0)のSceneを読み込みするというものです.今回のゲームでは一つしかSceneがありませんが,こうすることで,再度Sceneを読み込んで初期化することができます.なお,Scene番号の代わりに"MainScene"などとSceneの名前を入れても大丈夫です.このスクリプトをCtrl + sで保存したら,Unityに戻ります.ProjectビューのAssetsフォルダ内のReplayScriptをHierarcvhyビューのButtonまでドラッグしてドロップします.次にButtonのInspectorビューでButton (Script)のOn Click ()のList is Emptyの下の+マークをクリックします: 上の図で赤い線を引いたNone (Object)のところの右の丸をクリックして出てきたSelect ObjectのウィンドウのSceneタブの中からButtonを選択します: Select Objectウィンドウを閉じてOn Click()の中のNo Functionと表示されているところの右側の上下の矢印をクリックして,その中から[ReplayScript]→[OnClick()]を選択します: 最後にButtonのInspectorビューでButton (Script)のInteractableにチェックを入れます.このチェックを見落としていたせいで僕は15分ぐらい考え込んでしまいました^^; これでゲームは完成しました.上手くいっていれば,3回Cylinderをキャッチし損ねると,Game Overと表示され,Replayボタンを押すと再度ゲームが始まるはずです: www.youtube.com 今回まででゲームが完成しましたので遊べるようにUnity RoomにUPしてみました: unityroom.com 僕自身まだまだ未熟すぎですが,初めてUnityに触ったよ!という方でも作れたのではないでしょうか? 次回はアプリケーションとして遊べるようにするためのBuild Settingについて話します.これでUnityでのゲーム作りの基礎の基礎は終了です.次回の連載ではAssetの使い方などの基本をご紹介したいと思います.