【Unity7】uGUIでUIの表示とレベル機能を実装したい!【2Dローグライク12】
Unity5.0.0f4 Personal(2015年6月)
前回の続きです〜
今回は、ゲーム画面にUIを表示させます〜ゲームが始まった時に表示されるレベル(「Day 1」とか)と、プレイヤーの体力を表すFoodを画面に表示させます〜
また、それらUIに表示されている数値を、スクリプトから操作して変更します〜
【目標】UIを表示させ、UIの数値を変更する
2D Roguelike 12 of 14 : UI & Levels - YouTube
①UIを作成する
まずはDay1やDay2などと表示してレベルを示すUIを作成します〜始めに黒い画像を背景として表示し、その上に白いテキストを載せる形で進めていきます〜
HierarchyからCreate>UI>Imageを選択して下さい〜Imageの名前はLevelImageにして下さい〜
Imageを作成 名前はLevelImage
LevelImageのInspectorビューに移って下さい〜次に画像の赤枠部分を選択し、altボタンを押しながら右下のパネルを選択して下さい〜
altを押しながら右下を選択
この状態でSceneビューを見てみると、画面全体をLevelImageが覆った状態となっていることが分かります〜
画面全体が白く覆われる
ImageコンポーネントのColorを黒にして、背景は完成です〜
Colorを黒にする
続いてレベルを表示するテキストを作成していきます〜HierarchyからCreate>UI>Textを選択し、名前をLevelTextに変更して下さい〜
また、LevelTextはLevelImageの子オブジェクトにします〜
LevelTextをLevelImageの子オブジェクトにする
それではInspectorの設定を行います〜まずはテキストを画面の中央へ持っていきたいので、下画像の赤枠をクリックし、中央のパネルをaltを押しながらクリックして下さい〜
テキストを「Day 1」に、フォントをPressStart2P-Regularに、テキストサイズを32に、Alignment(文字位置)を中央に、テキストカラーを白に変更します〜
こんな感じ
これで画面中央に文字が表示されるはずなのですが、うまく表示されません〜これは、文字サイズが文字の枠をはみ出してしまっているからです〜
こういった場合、Overflowの設定を行うことで文字が文字枠からはみ出していても表示させることができます〜Horizontal OverflowとVertical OverflowをOverflowに変更して下さい〜
Overflow設定
文字が表示されるようになった
最後にプレイヤーの体力を表すFoodのUIを作成します〜HierarchyからCreate>UI>Textを選択し、名前をFoodTextに変更して下さい〜
続いて基点を画面下側に設定します〜赤枠クリック後、altを押しながら基点が下にくるパネルをクリックして下さい〜
AnchorをBottomに設定
続いてテキストを「Food: 100」、フォントをPressStart2P-Regular、文字サイズを24、Alignmentを中央、文字色を白に変更して下さい〜また、先ほどと同じくOverflowの設定も行います〜
このように設定すると
いい感じに表示される
ちょっと画面の下ギリギリすぎるので、Anchorの位置を少しだけ上にします〜Rect Transform内のAnchorsをクリックして下さい〜
MinとMaxという項目があり数値が書いてありますが、これらはAnchorの位置を表しています〜
X:0, Y:0が左下、X:1, Y:1が右上を表しています〜
X:0, Y:0が左下、X:1, Y:1が右上
それではMinのYとMaxのYを0.05に変更し、Anchorを少し上にあげましょう〜
また、Anchorを変更しただけではテキストの位置は変わりません〜今の状態でPosYを0に変更することで、テキスト位置がBottomより少し上に変更されます〜
Min YとMax Yを0.05に、PosYを0に変更
わかりにくいけど、ちょっと上に上がった
続いてこのFoodTextをLevelImageの下に表示して、プレイヤー操作画面でのみ表示されるようにします〜HierarchyビューのFoodTextをドラッグし、CanvasにドロップするとCanvas内の子オブジェクトの中で一番上の位置に変更されます〜
ドラッグ&ドロップ!
子オブジェクト内で一番上となる
UIはCanvas内で下にある程前面に表示されるため、これでFoodTextは隠れた状態となりました〜
隠れた
②GameManagerスクリプトの修正
それではGameManagerスクリプトを修正し、先ほど作成したUIを表示させたり値を変えたりしていきましょう〜以下ソースです〜
using UnityEngine; using System.Collections; using System.Collections.Generic; //********** 開始 **********// using UnityEngine.UI; //UI用に宣言 //********** 終了 **********// public class GameManager : MonoBehaviour { //********** 開始 **********// public float levelStartDelay = 2f; //レベル表示画面で2秒待つ //********** 終了 **********// public float turnDelay = .1f; public static GameManager instance = null; public BoardManager boardScript; public int playerFoodPoints = 100; [HideInInspector] public bool playersTurn = true; //********** 開始 **********// private Text levelText; //レベルテキスト private GameObject levelImage; //レベルイメージ private int level = 1; //レベルは1にしておく private bool doingSetup; //levelImageの表示等で活用 //********** 終了 **********// private List<Enemy> enemies; private bool enemiesMoving; void Awake () { if (instance == null) { instance = this; } else if (instance != this) { Destroy(gameObject); } DontDestroyOnLoad(gameObject); enemies = new List <Enemy>(); boardScript = GetComponent<BoardManager>(); InitGame(); } //********** 開始 **********// //UnityのAPIで、Sceneが呼ばれる度に実行されるメソッド private void OnLevelWasLoaded (int index) { level++; //レベルを1プラスする InitGame(); } //********** 終了 **********// void InitGame () { //********** 開始 **********// //trueの間、プレイヤーは身動きを取れない doingSetup = true; //LevelImageオブジェクト・LevelTextオブジェクトの取得 levelImage = GameObject.Find("LevelImage"); levelText = GameObject.Find("LevelText").GetComponent<Text>(); levelText.text = "Day " + level; //最新のレベルに更新 levelImage.SetActive(true); //LebelImageをアクティブにし表示 Invoke ("HideLevelImage", levelStartDelay); //2秒後にメソッド呼び出し //********** 終了 **********// enemies.Clear(); boardScript.SetupScene(level); } //********** 開始 **********// private void HideLevelImage () { levelImage.SetActive(false); //LevelImage非アクティブ化 doingSetup = false; //プレイヤーが動けるようになる } //********** 終了 **********// public void GameOver () { //********** 開始 **********// //ゲームオーバーメッセージを表示 levelText.text = "After " + level + " days, you starved."; levelImage.SetActive(true); //********** 終了 **********// enabled = false; } void Update () { //********** 開始 **********// //doingSetup=trueの時はEnemyを動かさない if (playersTurn || enemiesMoving || doingSetup) { //********** 終了 **********// return; } StartCoroutine(MoveEnemies()); } public void AddEnemyToList (Enemy script) { enemies.Add (script); } IEnumerator MoveEnemies () { enemiesMoving = true; yield return new WaitForSeconds (turnDelay); if (enemies.Count == 0) { yield return new WaitForSeconds (turnDelay); } for (int i = 0; i < enemies.Count; i++) { enemies[i].MoveEnemy(); yield return new WaitForSeconds(enemies[i].moveTime); } playersTurn = true; enemiesMoving = false; } }
GameManager.cs
OnLevelWasLoadedメソッド
まずはOnLevelWasLoadedメソッドです〜このメソッドは、Unityに標準で備わっているメソッドで、Sceneが呼ばれる度に実行されるメソッドです〜引数のindexはSceneのindex番号で、Build SettingにてSceneをAdd Currentした時に与えられる番号です〜今回は使いません〜
Build Settingsのこの赤枠の数字が渡される
続いてレベルをプラス1して、InitGameメソッドを読んでいます〜
InitGameメソッド
InitGameメソッドではまず、doingSetupをtrueにし、Enemyが動けないようにしています〜(後述)
続いてLevelImageオブジェクトとLevelTextオブジェクトを取得し、LevelTextに関しては最新のレベルに更新しています〜
また、LevelImageをSetActiveによってアクティブ化し、画面に表示しています〜
最後にInvokeでHideLevelImageを呼び出しています〜Invokeは第2引数の分だけ遅れてメソッドを呼び出します〜デフォルトだと2秒遅れになっています〜
HideLevelImageメソッド
2秒経過後、まずはLevelImageを非アクティブ化し、LevelImageを非表示にします〜
続いてdoingSetupをfalseにし、Enemyが動けるようにしています〜
Updateメソッド
Updateメソッドでは、return(メソッド終了)を実行する条件にdoingSetupを追加しています〜こうすることにより、doingSetupがtrueの間はEnemyが動かなくなります〜
GameOverメソッド
最後にGameOverメソッドです〜LevelTextのテキスト部分にゲームオーバーメッセージを代入し、LevelImageをアクティブ化しゲームオーバーメッセージを表示しています〜
③Playerメソッド修正
最後にプレイヤーの体力を表すFoodTextを機能させるため、Playerスクリプトに修正を加えていきます〜以下ソースです〜
using UnityEngine; using System.Collections; //********** 開始 **********// using UnityEngine.UI; //********** 終了 **********// public class Player : MovingObject { public int wallDamage = 1; public int pointsPerFood = 10; public int pointsPerSoda = 20; public float restartlevelDelay = 1f; //********** 開始 **********// public Text foodText; //FoodText //********** 終了 **********// private Animator animator; private int food; protected override void Start () { animator = GetComponent<Animator>(); food = GameManager.instance.playerFoodPoints; //********** 開始 **********// foodText.text = "Food: " + food; //********** 終了 **********// base.Start(); } private void OnDisable () { GameManager.instance.playerFoodPoints = food; } void Update () { if (!GameManager.instance.playersTurn) return; int horizontal = 0; int vertical = 0; horizontal = (int)Input.GetAxisRaw ("Horizontal"); vertical = (int)Input.GetAxisRaw ("Vertical"); if (horizontal != 0) { vertical = 0; } if (horizontal != 0 || vertical != 0) { AttemptMove<Wall>(horizontal, vertical); } } protected override void AttemptMove <T> (int xDir, int yDir) { food--; //********** 開始 **********// foodText.text = "Food: " + food; //********** 終了 **********// base.AttemptMove <T> (xDir, yDir); RaycastHit2D hit; CheckIfGameOver(); GameManager.instance.playersTurn = false; } protected override void OnCantMove <T> (T component) { Wall hitWall = component as Wall; hitWall.DamageWall(wallDamage); animator.SetTrigger("PlayerChop"); } private void OnTriggerEnter2D (Collider2D other) { if (other.tag == "Exit") { Invoke ("Restart", restartlevelDelay); enabled = false; } else if (other.tag == "Food") { food += pointsPerFood; //********** 開始 **********// foodText.text = "+" + pointsPerFood + " Food: " + food; //********** 終了 **********// other.gameObject.SetActive(false); } else if (other.tag == "Soda") { food += pointsPerSoda; //********** 開始 **********// foodText.text = "+" + pointsPerSoda + " Food: " + food; //********** 終了 **********// other.gameObject.SetActive(false); } } private void Restart () { Application.LoadLevel(Application.loadedLevel); } public void LoseFood (int loss) { animator.SetTrigger("PlayerHit"); food -= loss; //********** 開始 **********// foodText.text = "-" + loss + " Food: " + food; //********** 終了 **********// CheckIfGameOver(); } private void CheckIfGameOver () { if (food <= 0) { GameManager.instance.GameOver(); } } }
Player.cs
まずはpublic変数であるfoodTextに、FoodTextオブジェクトを指定してあげましょう〜
ドラッグ&ドロップ!
Startメソッド
Startメソッドでは、新しいレベルのステージが開始された時の体力を表示しています〜
AttemptMoveメソッド
AttempMoveメソッドは移動を試みた時に実行されるメソッドで、開始直後に体力が1減るので、そのすぐ下で体力の表示を更新しています〜
OnTriggerEnter2Dメソッド
OnTriggerEnter2Dメソッドではアイテムをとった時の処理を記述しています〜
Foodを取り体力を10回復したあと、即座に「+10 Food: 体力値」と表示させています〜
同じくSodaを取り体力を20回復したあと、即座に「+20 Food: 体力値」と表示させています〜
LoseFoodメソッド
最後はEnemyから攻撃を受けた時に実行されるLoseFoodです〜
体力値が変数loss分マイナスされたあと、即座に「-loss Food: 体力値」と表示させています〜
テスト
以上でUIの実装は終了です〜テストをしてみましょう〜
ゲームスタート
画面下に体力表示
動くと体力が減る
アイテムを取得すると回復する
攻撃を受けると体力が減る
次のステージへ進むとレベルが上がる
体力が0になるとゲームオーバー
ゲームを進める上でのひと通りの機能は揃いました〜
今回はここまでです〜
ありがとうございました〜
【Unity開発7】Unity公式チュートリアル2Dローグライクの導入【2Dローグライク1】
【Unity開発7】アニメーションを作りたい!【2Dローグライク2】
【Unity開発7】Floorやアイテムを作成したい!【2Dローグライク3】
【Unity開発7】床や敵キャラ、アイテム等を自動生成させたい!【2Dローグライク4】
【Unity開発7】BoardManagerを呼び出すGameManagerを作成する【2Dローグライク5】
【Unity開発7】キャラクターを動かすための抽象クラス作成【2Dローグライク6】
【Unity開発7】破壊可能な壁(Wall)を作成したい!【ローグライク7】
【Unity開発7】プレイヤーのアニメーターを設定したい!【ローグライク8】
【Unity開発7】プレイヤー用のスクリプトを設定したい!【ローグライク9】
【Unity開発7】敵キャラクターのスクリプトを作成したい!【2Dローグライク10】
【Unity開発7】敵キャラクターのアニメーターを設定したい!【2Dローグライク11】
【Unity開発7】uGUIでUIの表示とレベル機能を実装したい!【2Dローグライク12】