Skip to content

Instantly share code, notes, and snippets.

@Rohyn

Rohyn/combat.cs Secret

Created October 3, 2019 01:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Rohyn/fc273f2605539c52ad083525cdc8bc1d to your computer and use it in GitHub Desktop.
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.
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