-
-
Save Rohyn/fc273f2605539c52ad083525cdc8bc1d to your computer and use it in GitHub Desktop.
Looking for feedback on best practices and optimization for my first combat handler.
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 System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.UI; | |
using UnityEngine.EventSystems; | |
using PixelCrushers.DialogueSystem; | |
public class combat : MonoBehaviour | |
{ | |
public int startingDraw; // how many elements to draw first turn? | |
public int turnDraw; // how many new elements to draw each turn? | |
public string enemyName; // pulled from dialogue manager | |
public GameObject enemyObject; // fetched using enemyName | |
private enemy Enemy; // the script attached to enemyObject | |
public GameObject enemyPortrait; // the raw image object that holds the enemy's portrait | |
public GameObject enemyHPBar; // the slider bar that tracks enemy's hp | |
public GameObject enemyHPText; // the text on said slider bar | |
public GameObject enemyNamePlate; // the text object displaying the enemy's name | |
public int enemyMaxHP; // derived from the Enemy script | |
public int enemyHP; // starts at the Enemy script's value | |
private GameObject playerObject; // the player object | |
private Player player; // and the player's data | |
// associate player hp/mp bubble objects for ease of refence | |
public GameObject playerHPBar; | |
public GameObject playerHPText; | |
public GameObject playerMPBar; | |
public GameObject playerMPText; | |
// declare some player stats | |
public int playerMaxHP; | |
public int playerHP; | |
public int playerMaxMP; | |
public int playerMP; | |
public int playerMPRegen; | |
private string currentScene; | |
private string victoryScene; | |
private string defeatScene; | |
// store GUI game objects for later reference | |
public GameObject elements; | |
public GameObject elementPanel; | |
public GameObject handSlotPrefab; | |
public GameObject spellPanel; | |
public GameObject spellSlotPrefab; | |
public GameObject actionPanel; | |
public GameObject actionSlotPrefab; | |
public GameObject fadePanel; // clear panel that sits over the player's hand to prevent clicking when not their turn | |
// prepare to define some components for easier reference later | |
private Slider enemyHPSlider; | |
private Text enemyHPInt; | |
private Slider playerHPSlider; | |
private Text playerHPInt; | |
private Slider playerMPSlider; | |
private Text playerMPInt; | |
// now for other stuff | |
private List<GameObject> playerHand = new List<GameObject>(); | |
private List<GameObject> spellElements = new List<GameObject>(); | |
private List<GameObject> possibleElements = new List<GameObject>(); | |
private List<GameObject> enemyHand = new List<GameObject>(); | |
private string newTurn; | |
private int turnNumber; | |
private int index; | |
// a list of x coordinates for hand slots {5,57,109,161,213,266,318,370,422,474} 10 | |
public List<int> handSpacing = new List<int> (); | |
// and spell slots {3,80,157,235,312} 5 | |
public List<int> spellSpacing = new List<int> (); | |
// spacing of action slots {5,64,123,181,240,299} 6 | |
public List<int> actionSpacing = new List<int> (); | |
// mana costs, per element in the spell {1,4,9,16,25} 5 | |
public List<int> manaCost = new List<int> (); | |
// finally, grab the alert manager for later use | |
private alerts alertPanel; | |
void OnEnable() | |
// this runs before anything else, let's populate our opponent and store some critical references for later | |
{ | |
// the dialogue manager will enable combat when necessary, so let's use it to set some initial stuff | |
currentScene = DialogueLua.GetVariable("CurrentScene").AsString; | |
victoryScene = DialogueLua.GetVariable("VictoryScene").AsString; | |
defeatScene = DialogueLua.GetVariable("DefeatScene").AsString; | |
// swap to the combat music next | |
GameObject music = GameObject.Find(currentScene); | |
music.GetComponent<AudioSource>().Stop(); | |
// we should have the opponent stored for recall... | |
enemyName = DialogueLua.GetVariable("enemy").AsString; | |
// next, associate the enemy with its game object for easy storage of stats, etc | |
enemyObject = GameObject.Find("/combat/enemies/" + enemyName); | |
// and store the enemy script for later reference | |
Enemy = enemyObject.GetComponent<enemy>(); | |
// set the portrait to the enemy's image | |
enemyPortrait.GetComponent<RawImage>().texture = Enemy.portrait; | |
// and set the name displayed as well | |
enemyNamePlate.GetComponent<Text>().text = Enemy.displayName; | |
// now grab the enemy's starting hp value | |
enemyMaxHP = Enemy.hp; | |
enemyHP = enemyMaxHP; | |
// fetch the player's hp/mp from the player object | |
playerObject = GameObject.Find("Dialogue Manager/Manager"); | |
player = playerObject.GetComponent<Player>(); | |
playerMaxHP = player.hp; | |
playerMaxMP = player.mp; | |
playerHP = playerMaxHP; | |
playerMP = playerMaxMP; | |
playerMPRegen = player.regen; | |
// and finally do some one-time component fetching to move hp/mp sliders | |
enemyHPSlider = enemyHPBar.GetComponent<Slider>(); | |
enemyHPInt = enemyHPText.GetComponent<Text>(); | |
playerHPSlider = playerHPBar.GetComponent<Slider>(); | |
playerHPInt = playerHPText.GetComponent<Text>(); | |
playerMPSlider = playerMPBar.GetComponent<Slider>(); | |
playerMPInt = playerMPText.GetComponent<Text>(); | |
// don't forget to grab the alert script panel for later use | |
alertPanel = GetComponent<alerts>(); | |
// now let's set up for the first round of combat | |
turnNumber = 0; | |
ClearHands(); // in case this isn't the first fight since we changed scenes | |
// determine which elements we can draw | |
foreach (Transform child in elements.transform) | |
{ | |
if (child.gameObject.activeSelf) | |
{ | |
possibleElements.Add(child.gameObject); | |
} | |
} | |
// draw initial elements/actions | |
for(int i = 0; i < startingDraw; i++){ | |
PlayerDraw(); | |
} | |
for(int i = 0; i < 6; i++){ | |
EnemyDraw(); | |
} | |
UpdateEnemyHand(); | |
UpdatePlayerHand(); | |
// we're going into the first turn, let's see whose turn we start on and then launch that party's round | |
newTurn = DialogueLua.GetVariable("FirstTurn").AsString; | |
if (newTurn == "player") { | |
StartPlayerTurn(); | |
} | |
else { | |
StartEnemyTurn(); | |
} | |
} | |
void ClearHands() | |
{ | |
foreach (GameObject rune in playerHand) { | |
Destroy(rune); | |
} | |
playerHand.Clear(); | |
foreach (GameObject rune in enemyHand) { | |
Destroy(rune); | |
} | |
enemyHand.Clear(); | |
} | |
void StartPlayerTurn() | |
// begin the player's turn | |
{ | |
// advance the turn counter | |
turnNumber++; | |
// make sure we can click on our hand | |
fadePanel.SetActive(false); | |
// draw new runes as needed | |
for (int i = 0; i < turnDraw; i++){ | |
PlayerDraw(); | |
} | |
UpdatePlayerHand(); | |
// regen MP | |
playerMP = playerMP+playerMPRegen; | |
if (playerMP > playerMaxMP) { | |
playerMP = playerMaxMP; | |
} | |
alertPanel.Alert("Your Turn"); | |
} | |
void PlayerDraw() | |
{ | |
// we're drawing a rune, start by making sure our hand isn't full | |
if (playerHand.Count < 10) { | |
// now choose which element to draw | |
index = Random.Range(0,possibleElements.Count); | |
GameObject ele = possibleElements[index]; | |
// now create the rune | |
GameObject newRune = Instantiate(handSlotPrefab, elementPanel.transform); | |
playerHand.Add(newRune); | |
// now attach the right element to it | |
newRune.GetComponent<runes>().element = ele; | |
newRune.GetComponent<runes>().combatHandler = gameObject; | |
newRune.GetComponent<Image>().sprite = ele.GetComponent<action>().icon; | |
newRune.GetComponent<Button>().onClick.AddListener(delegate() {HandButton();} ); | |
//UpdatePlayerHand(); | |
} | |
} | |
void HandButton() | |
// for the buttons that comprise the player's hand | |
{ | |
GameObject rune = EventSystem.current.currentSelectedGameObject; | |
// we need the 'runes' script attached to the button... | |
runes clickedRune = rune.GetComponent<runes>(); | |
// the UseRune method will move it from the hand to the player's current spell | |
clickedRune.UseRune(); | |
} | |
void UpdatePlayerHand() | |
{ | |
// updating the player's hand, iterate over the runes we have | |
foreach (GameObject rune in playerHand) { | |
// find x-coordinate for this rune from the list of x-coordinates for the hand | |
int xcoord = handSpacing[playerHand.IndexOf(rune)]; | |
// now move it to the right place | |
Vector3 temp = new Vector3(xcoord,0,0); | |
RectTransform trans = rune.GetComponent<RectTransform>(); | |
trans.anchoredPosition = temp; | |
} | |
} | |
public void AddElement(GameObject pressed) | |
// for adding a new element to the current spell | |
{ | |
// start by checking the length of our spell | |
if (spellElements.Count < 5) { | |
// and don't forget to check if we have enough mana | |
if (playerMP >= manaCost[spellElements.Count]) { | |
// create a new spellrune | |
GameObject newSpell = Instantiate(spellSlotPrefab, spellPanel.transform); | |
// make sure to add it to the list for later use | |
spellElements.Add(newSpell); | |
// now set the new rune's attributes to the rune we copied it from | |
newSpell.GetComponent<runes>().element = pressed.GetComponent<runes>().element; | |
newSpell.GetComponent<runes>().combatHandler = gameObject; | |
newSpell.GetComponent<runes>().handButton = pressed; | |
newSpell.GetComponent<Image>().sprite = pressed.GetComponent<Image>().sprite; | |
// make sure we can't reuse the rune in our hand | |
pressed.GetComponent<Button>().interactable = false; | |
// and add onClick functionality to the new spellrune | |
newSpell.GetComponent<Button>().onClick.AddListener(delegate() {SpellButton();} ); | |
// finally, position the spellrunes on the spell bar | |
UpdateSpell(); | |
} else { | |
alertPanel.Alert("Not enough mana!"); | |
} | |
} else { | |
alertPanel.Alert("Too many elements!"); | |
} | |
} | |
void SpellButton() | |
{ | |
// for clicking on a rune in the current spell | |
GameObject rune = EventSystem.current.currentSelectedGameObject; | |
runes clickedRune = rune.GetComponent<runes>(); | |
// remove it from the spell | |
clickedRune.RemoveRune(); | |
} | |
public void RemoveElement(GameObject pressed) | |
{ | |
// for removing an existing element from the current spell | |
GameObject rune = pressed.GetComponent<runes>().handButton; | |
// return use of the associated rune to the player | |
rune.GetComponent<Button>().interactable = true; | |
// remove the element from the spell | |
spellElements.Remove(pressed); | |
// delete the actual button | |
Destroy(pressed); | |
// and re-sort the spell bar | |
UpdateSpell(); | |
} | |
void UpdateSpell() | |
{ | |
// sort the spell bar | |
foreach (GameObject rune in spellElements) { | |
int xcoord = spellSpacing[spellElements.IndexOf(rune)]; | |
Vector3 temp = new Vector3(xcoord,0,0); | |
RectTransform trans = rune.GetComponent<RectTransform>(); | |
trans.anchoredPosition = temp; | |
} | |
} | |
public void Cast() | |
// we clicked the cast button | |
{ | |
// first make sure we have something to cast | |
if (spellElements.Count >= 1) { | |
// we do, deduct the mana cost | |
playerMP = playerMP-manaCost[spellElements.Count-1]; | |
// set up a temporary store for total damage | |
int damageDone = 0; | |
// then iterate over the elements in the spell | |
foreach (GameObject rune in spellElements) { | |
// implement the element's effects | |
GameObject effect = rune.GetComponent<runes>().element; | |
damageDone = damageDone+effect.GetComponent<action>().damage; | |
// then remove the rune from the player's hand | |
GameObject handRune = rune.GetComponent<runes>().handButton; | |
playerHand.Remove(handRune); | |
Destroy(handRune); | |
// and from the spell bar, too | |
Destroy(rune); | |
} | |
DamageEnemy(damageDone); | |
// clear what we think is in the spell bar | |
spellElements.Clear(); | |
// sort what's left of the player's hand | |
UpdatePlayerHand(); | |
// and pass the turn | |
StartEnemyTurn(); | |
} else { | |
// we tried to cast with no spells | |
alertPanel.Alert("Add elements first!"); | |
} | |
} | |
void StartEnemyTurn() | |
// begin the enemy's turn | |
{ | |
// advance the turn counter | |
turnNumber++; | |
// make it so the player can't click anything | |
fadePanel.SetActive(true); | |
// refill the enemy's action bar | |
while (enemyHand.Count < 6) { | |
EnemyDraw(); | |
} | |
UpdateEnemyHand(); | |
// pause for a moment | |
Invoke("ContinueEnemyTurn", 1); | |
} | |
void ContinueEnemyTurn() | |
{ | |
// grab the first action in the queue | |
GameObject rune = enemyHand[0]; | |
GameObject effect = rune.GetComponent<runes>().element; | |
// and execute its effect | |
DamagePlayer(effect.GetComponent<action>().damage); | |
// then destroy that action | |
enemyHand.Remove(rune); | |
Destroy(rune); | |
// and update the enemy's hand | |
UpdateEnemyHand(); | |
// pause... | |
Invoke("FinishEnemeyTurn", 1); | |
} | |
void FinishEnemeyTurn() | |
{ | |
// just here for the delay | |
StartPlayerTurn(); | |
} | |
void EnemyDraw() | |
{ | |
// we're drawing an action, start by making sure the hand isn't full | |
if (enemyHand.Count < 6) { | |
// now choose which action to draw | |
index = Random.Range(0,Enemy.actions.Count); | |
GameObject ele = Enemy.actions[index]; | |
// now create the slot | |
GameObject newAction = Instantiate(actionSlotPrefab, actionPanel.transform); | |
enemyHand.Add(newAction); | |
// now attach the right action to it | |
newAction.GetComponent<runes>().element = ele; | |
newAction.GetComponent<runes>().combatHandler = gameObject; | |
newAction.GetComponent<Image>().sprite = ele.GetComponent<action>().icon; | |
} | |
} | |
void UpdateEnemyHand() | |
{ | |
// updating the enemy's hand, iterate over the runes we have | |
foreach (GameObject rune in enemyHand) { | |
// find x-coordinate for this rune | |
int xcoord = actionSpacing[enemyHand.IndexOf(rune)]; | |
// now move it to the right place | |
Vector3 temp = new Vector3(xcoord,0,0); | |
RectTransform trans = rune.GetComponent<RectTransform>(); | |
trans.anchoredPosition = temp; | |
} | |
} | |
void DamageEnemy(int amt) | |
{ | |
enemyHP = enemyHP-amt; | |
alertPanel.Alert("You deal " + amt.ToString() + " damage!"); | |
} | |
void DamagePlayer(int amt) | |
{ | |
playerHP = playerHP-amt; | |
alertPanel.Alert("You take " + amt.ToString() + " damage!"); | |
} | |
// Update is called once per frame | |
void Update() | |
{ | |
// update enemy hp bubble | |
enemyHPSlider.value = (float)enemyHP/enemyMaxHP; | |
enemyHPInt.text = enemyHP.ToString(); | |
// and player hp/mp bubbles | |
playerHPSlider.value = (float)playerHP/playerMaxHP; | |
playerHPInt.text = playerHP.ToString(); | |
playerMPSlider.value = (float)playerMP/playerMaxHP; | |
playerMPInt.text = playerMP.ToString(); | |
// check for victory/defeat conditions | |
if (enemyHP <= 0) { | |
Victory(); | |
} else if (playerHP <= 0) { | |
Defeat(); | |
} | |
} | |
void Victory() | |
{ | |
alertPanel.Alert("You've won!"); | |
Invoke("MovingOn", 2); | |
} | |
void MovingOn() | |
{ | |
GameObject scene = GameObject.Find(currentScene); | |
scene.SetActive(false); | |
GameObject newScene = GameObject.Find(victoryScene); | |
newScene.SetActive(true); | |
gameObject.SetActive(false); | |
} | |
void Defeat() | |
{ | |
// welp you suck | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment