プレイグランドを改造する

Improvement Playground

今回はUNITYの練習用アセットPlaygroundの改良をしてみましょう。今回は時間制限機能をつけてみましょう。

LEVEL

開発環境

UNITY (2D)

対応デバイス:PC
方向変更:WADS
レーザー発射:スペース

 プレイグランドに時間制限機能をつける

プレイグランドは、色々なアセットで簡単な操作でゲームを作れるようになっていますが、通常のUnityプロジェクトと同じように色々なオリジナル機能を追加することができます。今回は、時間制限の機能をつけてみましょう。

 編集しよう

変更箇所

【プレファブ】Prefabs
・Userinterface

【スクリプト】Scripts
・UIScript
・UIScriptInspector

プレファブの変更

Userinterfaceプレファブを編集していきます。「Time Up」を表示するためのPanel(パネル)をつくります。

ゲームオブジェクト「TimeUp」の設定

UI TEXT「TimeUpText」の設定

スクリプトの変更

UIScript.cs

時間を計測するための各種変数を定義して、Update()メソッドを追加して、そのなかで時間を計測させています。
変更箇所は「改良のための追加..」を書かれています。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
[AddComponentMenu("")]
public class UIScript : MonoBehaviour
{
[Header("Configuration")]
public Players numberOfPlayers = Players.OnePlayer;
public GameType gameType = GameType.Score;
// If the scoreToWin is -1, the game becomes endless (no win conditions, but you could do game over)
public int scoreToWin = 5;
public int gameTime = 30;
//改良のための追加1 START
public Text timeText;//時間表示Textエリア
public GameObject timeUpPanel;//タイムアップ用Window
public Text timeUpText;//タイムアップ用Windowの表示Text
private bool onetime = true;
//改良のための追加1 END
[Header("References (don't touch)")]
//Right is used for the score in P1 games
public Text[] numberLabels = new Text[2];
public Text rightLabel, leftLabel;
public Text winLabel;
public GameObject statsPanel, gameOverPanel, winPanel;
public Transform inventory;
public GameObject resourceItemPrefab;
// Internal variables to keep track of score, health, and resources, win state
private int[] scores = new int[2];
private int[] playersHealth = new int[2];
private Dictionary<int, ResourceStruct> resourcesDict = new Dictionary<int, ResourceStruct>(); //holds a reference to all the resources collected, and to their UI
private bool gameOver = false; //this gets changed when the game is won OR lost
private void Start()
{
if(numberOfPlayers == Players.OnePlayer)
{
// No setup needed
}
else
{
if(gameType == GameType.Score)
{
// Show the 2-player score interface
rightLabel.text = leftLabel.text = "Score";
// Show the score as 0 for both players
numberLabels[0].text = numberLabels[1].text = numberLabels[2].text = "0";
scores[0] = scores[1] = 0;
}
else
{
// Show the 2-player life interface
rightLabel.text = leftLabel.text = "Life";
// Life will be provided by the PlayerHealth components
}
}
}
/*
* 改良のための追加2 START
* Add Time Rule
*/
private void Update()
{
if (gameTime > 0)
{
//Debug.Log("経過時間" + Time.time);
int timeInt = gameTime - (int)Time.time;
timeText.text = timeInt.ToString();
if (0 == timeInt)
{
TimeUp();
}
}
else if (gameTime == 0)
{
int timeInt = (int)Time.time;
timeText.text = timeInt.ToString();
}
}
//改良のための追加2 END
//version of the one below with one parameter to be able to connect UnityEvents
public void AddOnePoint(int playerNumber)
{
AddPoints(playerNumber, 1);
}
public void AddPoints(int playerNumber, int amount = 1)
{
scores[playerNumber] += amount;
if(numberOfPlayers == Players.OnePlayer)
{
numberLabels[1].text = scores[playerNumber].ToString(); //with one player, the score is on the right
}
else
{
numberLabels[playerNumber].text = scores[playerNumber].ToString();
}
if(gameType == GameType.Score
&& scores[playerNumber] >= scoreToWin)
{
GameWon(playerNumber);
}
}
//currently unused by other Playground scripts
public void RemoveOnePoint(int playerNumber)
{
scores[playerNumber]--;
if(numberOfPlayers == Players.OnePlayer)
{
numberLabels[1].text = scores[playerNumber].ToString(); //with one player, the score is on the right
}
else
{
numberLabels[playerNumber].text = scores[playerNumber].ToString();
}
}
public void GameWon(int playerNumber)
{
// only set game over UI if game is not over
if (!gameOver)
{
gameOver = true;
winLabel.text = "Player " + ++playerNumber + " wins!";
statsPanel.SetActive(false);
winPanel.SetActive(true);
}
}
public void GameOver(int playerNumber)
{
// only set game over UI if game is not over
if (!gameOver)
{
gameOver = true;
statsPanel.SetActive(false);
gameOverPanel.SetActive(true);
}
}
//改良のための追加3 START
// タイムズ・アップ
public void TimeUp()
{
if (onetime)
{
timeUpText.text = "Time UP! Score=" + scores[0].ToString();
onetime = false;
}
statsPanel.SetActive(false);
timeUpPanel.SetActive(true);
}
//改良のための追加3 END
public void SetHealth(int amount, int playerNumber)
{
playersHealth[playerNumber] = amount;
numberLabels[playerNumber].text = playersHealth[playerNumber].ToString();
}
public void ChangeHealth(int change, int playerNumber)
{
SetHealth(playersHealth[playerNumber] + change, playerNumber);
if(gameType != GameType.Endless
&& playersHealth[playerNumber] <= 0)
{
GameOver(playerNumber);
}
}
//Adds a resource to the dictionary, and to the UI
public void AddResource(int resourceType, int pickedUpAmount, Sprite graphics)
{
if(resourcesDict.ContainsKey(resourceType))
{
//update the dictionary key
int newAmount = resourcesDict[resourceType].amount + pickedUpAmount;
resourcesDict[resourceType].UIItem.ShowNumber(newAmount);
resourcesDict[resourceType].amount = newAmount;
}
else
{
//create the UIItemScript and display the icon
UIItemScript newUIItem = Instantiate<GameObject>(resourceItemPrefab).GetComponent<UIItemScript>();
newUIItem.transform.SetParent(inventory, false);
resourcesDict.Add(resourceType, new ResourceStruct(pickedUpAmount, newUIItem));
resourcesDict[resourceType].UIItem.ShowNumber(pickedUpAmount);
resourcesDict[resourceType].UIItem.DisplayIcon(graphics);
}
}
//checks if a certain resource is in the inventory, in the needed quantity
public bool CheckIfHasResources(int resourceType, int amountNeeded = 1)
{
if(resourcesDict.ContainsKey(resourceType))
{
if(resourcesDict[resourceType].amount >= amountNeeded)
{
return true;
}
else
{
//not enough
return false;
}
}
else
{
//resource not present
return false;
}
}
//to use only before checking that the resource is in the dictionary
public void ConsumeResource(int resourceType, int amountNeeded = 1)
{
resourcesDict[resourceType].amount -= amountNeeded;
resourcesDict[resourceType].UIItem.ShowNumber(resourcesDict[resourceType].amount);
}
public enum Players
{
OnePlayer = 0,
TwoPlayers
}
public enum GameType
{
Score = 0,
Life,
Endless,
Time
}
}
//just a virtual representation of the resources for the private dictionary
public class ResourceStruct
{
public int amount;
public UIItemScript UIItem;
public ResourceStruct(int a, UIItemScript uiRef)
{
amount = a;
UIItem = uiRef;
}
}
view raw UIScript.cs hosted with ❤ by GitHub

UIScriptInspector.cs

このスクリプトは、UIScriptのインスペクターの表示を編集するためのスクリプトです。ですから、このスクリプトにUIScriptインスペクタで今回追加した変数をインスペクタに表示するコードを追加します。変更箇所は「改良のための追加..」を書かれています。

using UnityEngine;
using UnityEditor;
using System.Collections;
[CustomEditor(typeof(UIScript))]
public class UIScriptInspector : InspectorBase
{
private string explanation = "Use the UI to visualise points and health for the players.";
private string lifeReminder = "Don't forget to use the script HealthSystemAttribute on the player(s)!";
private int nOfPlayers = 0, gameType = 0;
private string[] readablePlayerEnum = new string[]{"One player", "Two players"};
private string[] readableGameTypesEnum = new string[]{"Score", "Life", "Endless"};
// Inspector GUI OnInspcetorGUIをオーバライドしてカスタマイズ
public override void OnInspectorGUI()
{
GUILayout.Space(10);
EditorGUILayout.HelpBox(explanation, MessageType.Info);
nOfPlayers = serializedObject.FindProperty("numberOfPlayers").intValue;
gameType = serializedObject.FindProperty("gameType").intValue;
nOfPlayers = EditorGUILayout.Popup("Number of players", nOfPlayers, readablePlayerEnum);
gameType = EditorGUILayout.Popup("Game type", gameType, readableGameTypesEnum);
// GameTypeにより表示をScoreToWinを表示・非表示を切り替える
if (gameType == 0) //score game
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("scoreToWin"));
}
if(gameType == 1) //life
{
EditorGUILayout.HelpBox(lifeReminder, MessageType.Info);
}
// 改良のための追加 START
EditorGUILayout.PropertyField(serializedObject.FindProperty("gameTime"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("timeText"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("timeUpPanel"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("timeUpText"));
// 改良のための追加 END
//write all the properties back
serializedObject.FindProperty("gameType").intValue = gameType;
serializedObject.FindProperty("numberOfPlayers").intValue = nOfPlayers;
//serializedObject.FindProperty("gameTime").intValue = gameTime;
if (GUI.changed)
{
serializedObject.ApplyModifiedProperties();
}
}
}

コードを書くとUserInterfaceのインスペクタに以下のように変数が追加されますので、該当のGameObjectをアタッチしてください。Game Time変数に0を入力するとカウントアップしていきます。また、0より大きな数字をいれるとカウントダウンして、0になると「タイムアップ」と表示されうます。

これで改良のおわりです。下のように時間表示は追加されるとおもいます。