Created
March 30, 2020 14:12
-
-
Save CodingDino/ef3d8295a68ecca5bfd7dd2f6778f42d to your computer and use it in GitHub Desktop.
Updates to Unity Playground UI script (and inspector) to allow hearts for health display and to allow separate win / loss scenes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine.UI; | |
using UnityEngine.SceneManagement; | |
[AddComponentMenu("")] | |
public class UIScript : MonoBehaviour | |
{ | |
public enum HealthDisplayType | |
{ | |
TEXT, | |
HEART, | |
//BAR | |
} | |
public enum EndGameAction | |
{ | |
POPUP_TEXT, | |
CHANGE_SCENE, | |
//BAR | |
} | |
[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 HealthDisplayType displayType = HealthDisplayType.TEXT; | |
// Heart Icon assets | |
public Sprite heartIcon; | |
public Sprite heartContainerIcon; | |
// Health bar UI object reference | |
public Sprite healthBarFullSprite; | |
public Sprite healthBarContainerSprite; | |
// End game actions | |
public EndGameAction endGameAction = EndGameAction.POPUP_TEXT; | |
public const string SAME_SCENE = "0"; | |
public string winScene = SAME_SCENE; | |
public string loseScene = SAME_SCENE; | |
[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; | |
public Image[] healthBarFull = new Image[2]; | |
public Image[] healthBarContainer = new Image[2]; | |
public GameObject[] heartRoots = new GameObject[2]; | |
public GameObject heartPrefab; | |
public GameObject heartContainerPrefab; | |
// 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 int[] playersHealthMax = new int[2]; | |
private List<Image>[] playerHearts = new List<Image>[2]; | |
private List<Image>[] playerHeartContainers = new List<Image>[2]; | |
private void Start() | |
{ | |
if(numberOfPlayers == Players.OnePlayer) | |
{ | |
if (displayType != HealthDisplayType.TEXT) | |
{ | |
leftLabel.text = ""; | |
numberLabels[0].text = ""; | |
if (displayType == HealthDisplayType.HEART) | |
{ | |
heartRoots[0].SetActive(true); | |
} | |
} | |
} | |
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 = "0"; | |
scores[0] = scores[1] = 0; | |
} | |
else | |
{ | |
// Show the 2-player life interface | |
if (displayType == HealthDisplayType.TEXT) | |
{ | |
rightLabel.text = leftLabel.text = "Life"; | |
} | |
else | |
{ | |
rightLabel.text = leftLabel.text = ""; | |
numberLabels[0].text = numberLabels[1].text = ""; | |
if (displayType == HealthDisplayType.HEART) | |
{ | |
heartRoots[0].SetActive(true); | |
heartRoots[1].SetActive(true); | |
} | |
} | |
// Life will be provided by the PlayerHealth components | |
} | |
} | |
} | |
//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; | |
switch (endGameAction) | |
{ | |
case EndGameAction.POPUP_TEXT: | |
winLabel.text = "Player " + ++playerNumber + " wins!"; | |
statsPanel.SetActive(false); | |
winPanel.SetActive(true); | |
break; | |
case EndGameAction.CHANGE_SCENE: | |
if (winScene == SAME_SCENE) | |
{ | |
//just restart the level | |
SceneManager.LoadScene(SceneManager.GetActiveScene().name, LoadSceneMode.Single); | |
} | |
else | |
{ | |
//load another scene | |
SceneManager.LoadScene(winScene, LoadSceneMode.Single); | |
} | |
break; | |
} | |
} | |
} | |
public void GameOver(int playerNumber) | |
{ | |
// only set game over UI if game is not over | |
if (!gameOver) | |
{ | |
gameOver = true; | |
switch (endGameAction) | |
{ | |
case EndGameAction.POPUP_TEXT: | |
statsPanel.SetActive(false); | |
gameOverPanel.SetActive(true); | |
break; | |
case EndGameAction.CHANGE_SCENE: | |
if (loseScene == SAME_SCENE) | |
{ | |
//just restart the level | |
SceneManager.LoadScene(SceneManager.GetActiveScene().name, LoadSceneMode.Single); | |
} | |
else | |
{ | |
//load another scene | |
SceneManager.LoadScene(loseScene, LoadSceneMode.Single); | |
} | |
break; | |
} | |
} | |
} | |
public void SetInitialHealth(int amount, int playerNumber) | |
{ | |
playersHealthMax[playerNumber] = amount; | |
playersHealth[playerNumber] = amount; | |
switch (displayType) | |
{ | |
case HealthDisplayType.TEXT: | |
break; | |
case HealthDisplayType.HEART: | |
playerHearts[playerNumber] = new List<Image>(); | |
playerHeartContainers[playerNumber] = new List<Image>(); | |
for (int i = 0; i < amount; ++i) | |
{ | |
GameObject newContainer = Instantiate(heartContainerPrefab, heartRoots[playerNumber].transform); | |
newContainer.GetComponent<Image>().sprite = heartContainerIcon; | |
playerHeartContainers[playerNumber].Add(newContainer.GetComponent<Image>()); | |
GameObject newHeart = Instantiate(heartPrefab, newContainer.transform); | |
newHeart.GetComponent<Image>().sprite = heartIcon; | |
playerHearts[playerNumber].Add(newHeart.GetComponent<Image>()); | |
} | |
break; | |
//case HealthDisplayType.BAR:``````````````````````````````````````` | |
// break; | |
} | |
SetHealth(amount, playerNumber); | |
} | |
public void SetHealth(int amount, int playerNumber) | |
{ | |
//Debug.Log("Setting health for player " + playerNumber + " to " + amount + " from "+ playersHealth[playerNumber]); | |
playersHealth[playerNumber] = amount; | |
switch (displayType) | |
{ | |
case HealthDisplayType.TEXT: | |
numberLabels[playerNumber].text = playersHealth[playerNumber].ToString(); | |
break; | |
case HealthDisplayType.HEART: | |
for (int i = 0; i < playersHealthMax[playerNumber]; ++i) | |
{ | |
playerHearts[playerNumber][i].enabled = i < amount; | |
} | |
break; | |
//case HealthDisplayType.BAR: | |
// healthBarFull[playerNumber].transform.localScale = new Vector3(((float)amount) / ((float)playersHealthMax[playerNumber]), 0, 0); | |
// break; | |
} | |
} | |
public void ChangeHealth(int change, int playerNumber) | |
{ | |
//Debug.Log("Changing health for player " + playerNumber + " by " + change); | |
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 | |
} | |
} | |
//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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"}; | |
private string sceneWarning = "WARNING: Make sure the scene is enabled in the Build Settings scenes list."; | |
private string sceneInfo = "WARNING; To add a new level, save a Unity scene and then go to File > Build Settings... and add the scene to the list."; | |
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); | |
if(gameType == 0) //score game | |
{ | |
EditorGUILayout.PropertyField(serializedObject.FindProperty("scoreToWin")); | |
} | |
if(gameType == 1) //life | |
{ | |
EditorGUILayout.HelpBox(lifeReminder, MessageType.Info); | |
} | |
EditorGUILayout.PropertyField(serializedObject.FindProperty("displayType")); | |
UIScript.HealthDisplayType displayType = (UIScript.HealthDisplayType)serializedObject.FindProperty("displayType").intValue; | |
switch (displayType) | |
{ | |
case UIScript.HealthDisplayType.TEXT: | |
break; | |
case UIScript.HealthDisplayType.HEART: | |
EditorGUILayout.PropertyField(serializedObject.FindProperty("heartIcon")); | |
EditorGUILayout.PropertyField(serializedObject.FindProperty("heartContainerIcon")); | |
break; | |
/*case UIScript.HealthDisplayType.BAR: | |
EditorGUILayout.PropertyField(serializedObject.FindProperty("healthBarFull"), true); | |
EditorGUILayout.PropertyField(serializedObject.FindProperty("healthBarContainer"), true); | |
break;*/ | |
} | |
// Scenes | |
EditorGUILayout.PropertyField(serializedObject.FindProperty("endGameAction")); | |
UIScript.EndGameAction endGameAction = (UIScript.EndGameAction)serializedObject.FindProperty("endGameAction").intValue; | |
if (endGameAction == UIScript.EndGameAction.CHANGE_SCENE) | |
{ | |
bool displayWarning = false; | |
if (EditorBuildSettings.scenes.Length > 0) | |
{ | |
int sceneIdWin = 0; | |
int sceneIdLose = 0; | |
string sceneNamePropertyWin = serializedObject.FindProperty("winScene").stringValue; | |
string sceneNamePropertyLose = serializedObject.FindProperty("loseScene").stringValue; | |
//get available scene names and clean the names | |
string[] sceneNames = new string[EditorBuildSettings.scenes.Length + 1]; | |
sceneNames[0] = "RELOAD LEVEL"; | |
int i = 1; | |
foreach (EditorBuildSettingsScene s in EditorBuildSettings.scenes) | |
{ | |
int lastSlash = s.path.LastIndexOf("/"); | |
string shortPath = s.path.Substring(lastSlash + 1, s.path.Length - 7 - lastSlash); | |
sceneNames[i] = shortPath; | |
if (shortPath == sceneNamePropertyWin) | |
{ | |
sceneIdWin = i; | |
if (!s.enabled) | |
{ | |
displayWarning = true; | |
} | |
} | |
if (shortPath == sceneNamePropertyLose) | |
{ | |
sceneIdLose = i; | |
if (!s.enabled) | |
{ | |
displayWarning = true; | |
} | |
} | |
i++; | |
} | |
//Display the selector | |
sceneIdWin = EditorGUILayout.Popup("Winning scene", sceneIdWin, sceneNames); | |
sceneIdLose = EditorGUILayout.Popup("Losing scene", sceneIdLose, sceneNames); | |
if (displayWarning) | |
{ | |
EditorGUILayout.HelpBox(sceneWarning, MessageType.Warning); | |
} | |
if (sceneIdWin == 0) | |
{ | |
serializedObject.FindProperty("winScene").stringValue = UIScript.SAME_SCENE; //this means same scene | |
} | |
else | |
{ | |
serializedObject.FindProperty("winScene").stringValue = sceneNames[sceneIdWin]; | |
} | |
if (sceneIdLose == 0) | |
{ | |
serializedObject.FindProperty("loseScene").stringValue = UIScript.SAME_SCENE; //this means same scene | |
} | |
else | |
{ | |
serializedObject.FindProperty("loseScene").stringValue = sceneNames[sceneIdLose]; | |
} | |
} | |
else | |
{ | |
EditorGUILayout.Popup("Winning scene", 0, new string[] { "No scenes available!" }); | |
EditorGUILayout.Popup("Losing scene", 0, new string[] { "No scenes available!" }); | |
EditorGUILayout.HelpBox(sceneInfo, MessageType.Warning); | |
} | |
} | |
//write all the properties back | |
serializedObject.FindProperty("gameType").intValue = gameType; | |
serializedObject.FindProperty("numberOfPlayers").intValue = nOfPlayers; | |
if(GUI.changed) | |
{ | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment