Ending The Game and Q&A
확인 완료한 버전: 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.


Ending The Game and Q&A
초급 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 (강좌)