Game UI
確認済のバージョン: 5.4
-
難易度: 初級
In this live training session we will look at creating a multiple choice quiz game. We will create the core game loop - timer, score, win and lose states. We will also show code architecture best practices - keeping data and logic separate, and how to structure a game in a way that makes it easy to maintain and extend. We will look at some of the ways we can extend this in session two.


Game UI
初級 Scripting
AnswerData
Code snippet
using UnityEngine;
using System.Collections;
[System.Serializable]
public class AnswerData
{
public string answerText;
public bool isCorrect;
}
QuestionData
Code snippet
using UnityEngine;
using System.Collections;
[System.Serializable]
public class QuestionData
{
public string questionText;
public AnswerData[] answers;
}
RoundData
Code snippet
using UnityEngine;
using System.Collections;
[System.Serializable]
public class RoundData
{
public string name;
public int timeLimitInSeconds;
public int pointsAddedForCorrectAnswer;
public QuestionData[] questions;
}
DataController
Code snippet
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class DataController : MonoBehaviour
{
public RoundData[] allRoundData;
// Use this for initialization
void Start ()
{
DontDestroyOnLoad (gameObject);
SceneManager.LoadScene ("MenuScreen");
}
public RoundData GetCurrentRoundData()
{
return allRoundData [0];
}
// Update is called once per frame
void Update () {
}
}
MenuScreenController
Code snippet
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class MenuScreenController : MonoBehaviour {
public void StartGame()
{
SceneManager.LoadScene("Game");
}
}
SimpleObjectPool
Code snippet
using UnityEngine;
using System.Collections.Generic;
// A very simple object pooling class
public class SimpleObjectPool : MonoBehaviour
{
// the prefab that this object pool returns instances of
public GameObject prefab;
// collection of currently inactive instances of the prefab
private Stack<GameObject> inactiveInstances = new Stack<GameObject>();
// Returns an instance of the prefab
public GameObject GetObject()
{
GameObject spawnedGameObject;
// if there is an inactive instance of the prefab ready to return, return that
if (inactiveInstances.Count > 0)
{
// remove the instance from teh collection of inactive instances
spawnedGameObject = inactiveInstances.Pop();
}
// otherwise, create a new instance
else
{
spawnedGameObject = (GameObject)GameObject.Instantiate(prefab);
// add the PooledObject component to the prefab so we know it came from this pool
PooledObject pooledObject = spawnedGameObject.AddComponent<PooledObject>();
pooledObject.pool = this;
}
// enable the instance
spawnedGameObject.SetActive(true);
// return a reference to the instance
return spawnedGameObject;
}
// Return an instance of the prefab to the pool
public void ReturnObject(GameObject toReturn)
{
PooledObject pooledObject = toReturn.GetComponent<PooledObject>();
// if the instance came from this pool, return it to the pool
if(pooledObject != null && pooledObject.pool == this)
{
// disable the instance
toReturn.SetActive(false);
// add the instance to the collection of inactive instances
inactiveInstances.Push(toReturn);
}
// otherwise, just destroy it
else
{
Debug.LogWarning(toReturn.name + " was returned to a pool it wasn't spawned from! Destroying.");
Destroy(toReturn);
}
}
}
// a component that simply identifies the pool that a GameObject came from
public class PooledObject : MonoBehaviour
{
public SimpleObjectPool pool;
}
AnswerButton
Code snippet
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class AnswerButton : MonoBehaviour {
public Text answerText;
private AnswerData answerData;
private GameController gameController;
// Use this for initialization
void Start ()
{
gameController = FindObjectOfType<GameController> ();
}
public void Setup(AnswerData data)
{
answerData = data;
answerText.text = answerData.answerText;
}
public void HandleClick()
{
gameController.AnswerButtonClicked (answerData.isCorrect);
}
}
GameController
Code snippet
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
public class GameController : MonoBehaviour {
public Text questionDisplayText;
public Text scoreDisplayText;
public Text timeRemainingDisplayText;
public SimpleObjectPool answerButtonObjectPool;
public Transform answerButtonParent;
public GameObject questionDisplay;
public GameObject roundEndDisplay;
private DataController dataController;
private RoundData currentRoundData;
private QuestionData[] questionPool;
private bool isRoundActive;
private float timeRemaining;
private int questionIndex;
private int playerScore;
private List<GameObject> answerButtonGameObjects = new List<GameObject>();
// Use this for initialization
void Start ()
{
dataController = FindObjectOfType<DataController> ();
currentRoundData = dataController.GetCurrentRoundData ();
questionPool = currentRoundData.questions;
timeRemaining = currentRoundData.timeLimitInSeconds;
UpdateTimeRemainingDisplay();
playerScore = 0;
questionIndex = 0;
ShowQuestion ();
isRoundActive = true;
}
private void ShowQuestion()
{
RemoveAnswerButtons ();
QuestionData questionData = questionPool [questionIndex];
questionDisplayText.text = questionData.questionText;
for (int i = 0; i < questionData.answers.Length; i++)
{
GameObject answerButtonGameObject = answerButtonObjectPool.GetObject();
answerButtonGameObjects.Add(answerButtonGameObject);
answerButtonGameObject.transform.SetParent(answerButtonParent);
AnswerButton answerButton = answerButtonGameObject.GetComponent<AnswerButton>();
answerButton.Setup(questionData.answers[i]);
}
}
private void RemoveAnswerButtons()
{
while (answerButtonGameObjects.Count > 0)
{
answerButtonObjectPool.ReturnObject(answerButtonGameObjects[0]);
answerButtonGameObjects.RemoveAt(0);
}
}
public void AnswerButtonClicked(bool isCorrect)
{
if (isCorrect)
{
playerScore += currentRoundData.pointsAddedForCorrectAnswer;
scoreDisplayText.text = "Score: " + playerScore.ToString();
}
if (questionPool.Length > questionIndex + 1) {
questionIndex++;
ShowQuestion ();
} else
{
EndRound();
}
}
public void EndRound()
{
isRoundActive = false;
questionDisplay.SetActive (false);
roundEndDisplay.SetActive (true);
}
public void ReturnToMenu()
{
SceneManager.LoadScene ("MenuScreen");
}
private void UpdateTimeRemainingDisplay()
{
timeRemainingDisplayText.text = "Time: " + Mathf.Round (timeRemaining).ToString ();
}
// Update is called once per frame
void Update ()
{
if (isRoundActive)
{
timeRemaining -= Time.deltaTime;
UpdateTimeRemainingDisplay();
if (timeRemaining <= 0f)
{
EndRound();
}
}
}
}
関連するチュートリアル
- Intro and Setup (レッスン)
- Data Classes (レッスン)
- Menu Screen (レッスン)
- Game UI (レッスン)
- Answer Button (レッスン)
- Displaying Questions (レッスン)
- Click To Answer (レッスン)
- Ending The Game and Q&A (レッスン)