Learn Unity 4 for iOS Game Development 9
ゲーム GUI
作ったもの
・ボウリング・ゲームへのスコアボード/メニュー画面/ポーズ機能の実装(エスケープキーで、一時停止できます)。
クリックすると、別ウィンドウが開きます。(音が出ます。)
http://shakeweb.sakura.ne.jp/demo/LU4_chap9/
————————————————————————————————
スコアボードの実装
・シーンにスコアボード用の空の GameObject を用意して、スクリプトを適用する。
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 |
#pragma strict var style:GUIStyle; // customize the appearance. function OnGUI () { //GUI.Label(Rect(5,100,200,20), "This is a label"); for(var f:int = 0; f < 10; f++) { var score:String = ""; var roll1:int = FuguBowl.player.scores[f].ball1; var roll2:int = FuguBowl.player.scores[f].ball2; var roll3:int = FuguBowl.player.scores[f].ball3; switch(roll1) { case -1: score += " "; break; case 10: score += "X"; break; default: score += roll1; } score += " | "; if(FuguBowl.player.IsSpare(f)) { score += "/"; } else { switch(roll2) { case -1: score += " "; break; case 10: score += "X"; break; default: score += roll2; } } if(f == 9) { score += " | "; if(10 == roll2 + roll3) { score += "/"; } else { switch(roll3) { case -1: score += " "; break; case 10: score += "X"; break; default: score += roll3; } } } GUI.Label(Rect(f * 30 + 5, 5, 50, 20), score, style); // フレームごとにラベルを用意する. var total:int = FuguBowl.player.GetScore(f); if(total != -1) { GUI.Label(Rect(f * 30 + 5, 20, 50, 20), " " + total, style); // フレームごとにラベルを用意する. } } } |
・GUI クラスのラベルにテキストで表示。
————————————————————————————————
メニュー画面/一時停止機能の実装
・一時停止機能が付いていないと、アップルの審査に落とされることがある。
・メニュー画面/一時停止機能用の空の GameObject を用意して、スクリプトを適用する。
1 2 3 4 5 |
enum Page { None, Main, Options, Credits } private var currentPage:Page; |
・FSM と同じように、それぞれのページのステートを用意する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
private var savedTimeScale:float; // Time.timeScale before we pause function PauseGame() { savedTimeScale = Time.timeScale; // save normal time scale Time.timeScale = 0; // suspend time AudioListener.pause = true; // suspend music currentPage = Page.Main; // start with the main menu page } function UnPauseGame() { Time.timeScale = savedTimeScale; AudioListener.pause = false; currentPage = Page.None; } static function IsGamePaused() { return Time.timeScale == 0; } |
・Time.timeScale をゼロにすると、ゲーム中の動きが止まる。反対に、保存しておいた元の timeScale に戻すと、動き出す。同様に、timeScale の値を見れば、停止しているかどうか判定できる。
・ゲーム開始時に、ゲームを一時停止させ、メニュー画面を表示させる。
1 2 3 4 5 6 7 |
var startPaused:boolean = true; // bring up the menu at game start function Start() { if(startPaused) { PauseGame(); } } |
・escape キーで、’一時停止’/’停止解除’/’サブメニュー画面からのメインメニュー画面への遷移’を制御できるように、Update() 関数でキーボード入力を監視する。
・一時停止中は Time.deltaTime の値がゼロになり、ゼロで割るエラーを引き起こしてしまうので、ボールの動きを制御するスクリプトを修正する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function Update() { forcex = 0; forcey = 0; if(Time.deltaTime > 0) { // if it's not paused CalcForce(); } } function CalcForce() { var deltaTime:float = Time.deltaTime; forcex = mousepowerx * Input.GetAxis("Mouse X") / deltaTime; forcey = mousepowery * Input.GetAxis("Mouse Y") / deltaTime; } |
・メニュー画面の表示を OnGUI() 関数で制御。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var hudColor:Color = Color.white; var skin:GUISkin; function OnGUI() { if(IsGamePaused()) { if(skin != null) { GUI.skin = skin; } else { GUI.color = hudColor; } switch (currentPage) { case Page.Main: ShowPauseMenu(); break; case Page.Options: ShowOptions(); break; case Page.Credits: ShowCredits(); break; } } } |
・OnGUI() コールバックは、1フレーム中に複数回呼び出されるので、一時停止中かどうか、常に監視される。
・GUILayout クラスの BeginArea() 関数で GUI の表示領域の指定を開始し、EndArea() 関数で終了する。
1 2 3 4 5 6 7 8 9 10 11 12 |
var menutop:int = 25; function BeginPage(width:int, height:int) { GUILayout.BeginArea(Rect((Screen.width - width) / 2, menutop, width, height)); } function EndPage() { if(currentPage != Page.Main && GUILayout.Button("Back")) { currentPage = Page.Main; } GUILayout.EndArea(); } |
・GUILayout.Button(“Back”) は、これ自体でボタンを表示させ、ボタンが押されたら、戻り値が true になる。尚、この関数は、一時停止中は OnGUI() 関数経由で常に監視され続ける。
・メインメニュー表示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function ShowPauseMenu() { BeginPage(150,300); if(GUILayout.Button("Play")) { UnPauseGame(); } if(GUILayout.Button("Options")) { currentPage = Page.Options; } if(GUILayout.Button("Credits")) { currentPage = Page.Credits; } #if !UNITY_WEBPLAYER && !UNITY_EDITOR if(GUILayout.Button("")) { Application.Quit(); } #endif EndPage(); } |
・一時停止中は、OnGUI() 関数経由で常に監視され続ける。ボタンが押されると、OnGUI() の switch 文で別ページに遷移する。
・クレジット・ページ。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
var credits:String[] = [ "A Fugu Games Production", "Copyright (c) 2012 Technicat, LLC. All Rights Reserved.", "More information at http://fugugames.com/" ]; function ShowCredits() { BeginPage(300,200); for(var credit in credits) { GUILayout.Label(credit); } EndPage(); } |
・オプション・ページ。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
private var toolbarIndex:int = 0; // current toolbar selection private var toolbarStrings: String[] = ["Audio", "Graphics", "System"]; // tabs function ShowOptions() { BeginPage(300,300); toolbarIndex = GUILayout.Toolbar (toolbarIndex, toolbarStrings); switch(toolbarIndex) { case 0: ShowAudio(); break; case 1: ShowGraphics(); break; case 2: ShowSystem(); break; } EndPage(); } |
・GUILayout.Toolbar に渡す toolbarStrings で、ボタンに表示する名前を指定。toolbarIndex で選択されているボタンを指定。また、この関数は選択されているボタンのインデックスを int 型で返す。ShowOptions() 関数は、OnGUI() 経由で常に監視されているので、ボタンが選択されると、すぐさま、インデックスの値が変数 toobaIndex に代入され、Toolbar() に渡される値に反映されて、表示が切り替わる。
・オーディオ・パネル。
1 2 3 4 |
function ShowAudio() { GUILayout.Label("Volume"); AudioListener.volume = GUILayout.HorizontalSlider(AudioListener.volume, 0.0, 1.0); } |
・グラフィクス・パネル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function ShowGraphics() { GUILayout.Label(QualitySettings.names[QualitySettings.GetQualityLevel()]); GUILayout.Label("Pixel Light Count: " + QualitySettings.pixelLightCount); GUILayout.Label("Shadow Cascades: " + QualitySettings.shadowCascades); GUILayout.Label("Shadow Distance: " + QualitySettings.shadowDistance); GUILayout.Label("Soft Vegetation: " + QualitySettings.softVegetation); GUILayout.BeginHorizontal(); if(GUILayout.Button("Decrease")) { QualitySettings.DecreaseLevel(); } if(GUILayout.Button("Increase")) { QualitySettings.IncreaseLevel(); } GUILayout.EndHorizontal(); } |
・QualitySettings.GetQualityLevel() が int 型で値を返すので、それをインデックスとして配列 name から表示する名前を引っ張ってくる。
・システム・パネル。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function ShowSystem() { GUILayout.Label("Graphics: " + SystemInfo.graphicsDeviceName + " " + SystemInfo.graphicsMemorySize + "MB\n" + SystemInfo.graphicsDeviceVersion + "\n" + SystemInfo.graphicsDeviceVendor); // GUILayout.Label("Shadows: " + Available(SystemInfo.supportsShadows)); // GUILayout.Label("Image Effects: " + Available(SystemInfo.supportsImageEffects)); // GUILayout.Label("Render Textures: " + Available(SystemInfo.supportsRenderTextures)); GUILayout.Label("Shadows: " + SystemInfo.supportsShadows); GUILayout.Label("Image Effects: " + SystemInfo.supportsImageEffects); GUILayout.Label("Render Textures: " + SystemInfo.supportsRenderTextures); } |
・Available() がエラーになるため、使用を断念。Unity Pro なら使えるのだろうか。
————————————————————————————————
アセットストア(GUI 関連)
EZGUI (Above and Beyond Software)
NGUI (Tasharen Entertainment)