using UnityEngine; using System.Collections; using UnityEngine.SceneManagement; public class EnemyAI : MonoBehaviour { public DecisionTree root; //root of the decision tree which is searched for the AI to function public GameObject bananaPrefab; private Transform target; private Rigidbody2D Player; private Rigidbody2D Enemy; private Animator myAnimator; //Variables for keeping track of the Enemies health public float enemyHealth; //current health public float original; //health he spawned with //Variables for keeping track of the Players health public float playerHealth; //current health public float playerHealthOriginal; //players health they entered the arena with public static bool LookRight = true; //check which way the enemy is facing private bool set; private float speed = 2; //movement speed of enemy private float attackSpeed; //attack speed private float randomSpeed; //random speed which the atttack speed takes float spaceBarCounter = 0; //check for how aggresive the player is being private float coolDown = 0; //coolDown for Enemy attack private bool actionDelay = false; //sets a delay for the search of the tree during an enemy action private float searchDelay = 0.2f; private float searchCoolDown = 0; public static bool isEnemyKicking = false; //check for the player public static bool isEnemyPushing = false; //check for the player public static bool isEnemyDead = false; //check for the player private float kickCoolDown = 0; //cooldown on enemy kicks private float kickTimer; //hold the max time between enemy kicks private float aggressiveTimer; //time which countdowns, if player spams spacebar before it end, they will be seen as "Aggressive" private bool aggressiveCheck = false; //checks if the player is aggressive private bool isAggressive = false; private bool isPlayerAttacking = false; //Check for AI private bool isPlayerBlocking = false; //Check for AI private bool isPlayerKicking = false; //Check for AI private bool isPlayerPushing = false; //Check for AI private float playerPushingTimer; //Timer which makes AI jump after being pushed 'x' times private float throwCoolDown = 0; //timer to slow amount the AI can throw private float throwTimer; private bool canJump = false; //check to see if the AI can jump, to avoid clipping private int playerPushingCounter = 0; //check for how many times the AI has been pushed by the player private float randomActionCoolDown = 0; //cooldown for random actions private float randomAction; //holds the randomActionSpeed private float randomAcioionSpeed; //random speed set for random actions private int healthPotion; public int enemyMax; public int enemyMin; public bool dash = true; public float dashCoolDown = 5; void Start() { healthPotion = 1; throwTimer = 2; throwCoolDown = 1; playerPushingTimer = 2; aggressiveTimer = 3; kickTimer = 5; randomSpeed = Random.Range(0, 1f); attackSpeed = randomSpeed; randomAcioionSpeed = Random.Range(0, 2f); randomAction = randomAcioionSpeed; setEnemyHp(); playerHealth = PlayerStats.getHealth(); playerHealthOriginal = playerHealth; isEnemyDead = false; root = new DecisionTree(); // Debug.Log("start"); target = GameObject.FindGameObjectWithTag("Player").transform; //look at the player Player = GameObject.FindGameObjectWithTag("Player").GetComponent<Rigidbody2D>(); myAnimator = GetComponent<Animator>(); //required for animation ******* Enemy = GetComponent<Rigidbody2D>(); BuildDecisionTree(); } void Update() { //calls the all functions which need to be checked every frame AggressiveCoolDown(); BlockCheck(); AttackCheck(); KickCheck(); PushCheck(); HpCheck(); getPushed(); //cool downs for various actions throwCoolDown -= Time.deltaTime; coolDown -= Time.deltaTime; //for attacking kickCoolDown -= Time.deltaTime; randomActionCoolDown -= Time.deltaTime; //If the player can jump this will allow him to do so without getting stuck in the player if (canJump == true) { playerPushingTimer -= Time.deltaTime; if (playerPushingTimer <= 0) { JumpPlayer(); playerPushingTimer = 1.5f; canJump = false; } } if (dash == true) { dashCoolDown -= Time.deltaTime; if (dashCoolDown <= 0) { dashCoolDown = 5; dash = false; } } //sets a delay to the search of the tree so actions can not be spammed out by the AI if (actionDelay == true) { searchCoolDown -= Time.deltaTime; if (searchCoolDown <= 0) { searchCoolDown = searchDelay; root.search(); //search the decision tree } } else { root.search(); //search the decision tree actionDelay = false; } } public void setEnemyHp() { if (ArenaCombatControl.winCount <= 2) { enemyHealth = enemyHealth = Random.Range(20, 40); original = enemyHealth; } else { enemyHealth = enemyHealth = Random.Range(15 * (int)(ArenaCombatControl.winCount / 1.1f + 1), 20 * (int)(ArenaCombatControl.winCount / 1.1f + 1)); original = enemyHealth; } } /* * getPushed() * Takes Input from the user and checks whether or not the enemy is being pushed * Checks which direction the enemy is facing and applies the relative force * If the enemy has been pushed too many times he will then jump over the player and switch up the combat */ public void getPushed() { if (Vector3.Distance(transform.position, target.position) < 2.5f && isPlayerPushing == true) { myAnimator.SetBool("knockBack", true); myAnimator.SetBool("kick", false); myAnimator.SetBool("attack", false); myAnimator.SetBool("block", false); playerPushingCounter++; Invoke("StopKnockAnimation", 0.5f); if (LookRight == true) { Enemy.AddForce(new Vector2(-500, 0)); } else { Enemy.AddForce(new Vector2(500, 0)); } if (playerPushingCounter >= 2) { playerPushingCounter = 0; canJump = true; } } } //fixes infinate loop of knockBack animation public void StopKnockAnimation() { myAnimator.SetBool("knockBack", false); } //forces to the Enemy to jump over the player without getting stuck //relative forces are applied by checking the direction the enemy is facing public void JumpPlayer() { if (Vector3.Distance(transform.position, target.position) < 6f) { if (LookRight == true) { Enemy.AddForce(new Vector2(200, 1000)); } else { Enemy.AddForce(new Vector2(-200, 1000)); } } } /* * AggreiveCoolDown() * Takes input from the player and checks how much the spacebar is being pressed * if the spacebar is spammed, the enemy will push the player away */ public void AggressiveCoolDown() { if (Input.GetKeyDown(KeyCode.Space)) { spaceBarCounter++; // Debug.Log(spaceBarCounter); aggressiveCheck = true; } if (aggressiveCheck == true) { aggressiveTimer -= Time.deltaTime; // Debug.Log(agressiveTimer); } if (aggressiveTimer <= 0) { aggressiveCheck = false; spaceBarCounter = 0; aggressiveTimer = 5; } } //Check from user imput for AI, if the player is blocking or not public void BlockCheck() { isPlayerBlocking = ArenaCombatControl.block; //Debug.Log(isPlayerBlocking + "Enemy"); if (isPlayerBlocking == false) { myAnimator.SetBool("kick", false); } } //Check from user imput for AI, if the player is atacking or not public void AttackCheck() { isPlayerAttacking = ArenaCombatControl.attack; } //Check from user imput for AI, if the player is kicking or not public void KickCheck() { isPlayerKicking = ArenaCombatControl.kick; } //Check from player stats for AI, keeps track of the players HP public void HpCheck() { playerHealth = PlayerStats.curHealth; } //Check from user imput for AI, if the player is pushing or not public void PushCheck() { isPlayerPushing = ArenaCombatControl.push; } /* * Damage dealt against the enemy from the player */ public void Damage(int amount) { enemyHealth -= amount; if (enemyHealth <= 0) { enemyHealth = 0; ArenaCombatControl.winCount++; isEnemyDead = true; myAnimator.SetBool("death", true); Enemy.velocity = Vector2.zero; Invoke("EnemyDeath", 2.5f); Invoke("ExitArena", 2.4f); } } //destory the enemy when hes dead public void EnemyDeath() { Destroy(gameObject); } //exit the arena after the enemy had died public void ExitArena() { isEnemyDead = false; } /* * Damage dealt to the player from the enemy */ public int getDamageOutput() { enemyMax = 8 + (int)(ArenaCombatControl.winCount * 1.25f); //BALANCE THIS enemyMin = 1 + (int)(ArenaCombatControl.winCount * 1.1f); int final = Random.Range(enemyMin, enemyMax); Debug.Log(final); // calculate here! remember player defense is factored in later return final; } //Decision for the Decision Tree //is the player attacking? public bool d_isPlayerAttacking() { if (isPlayerAttacking == true) { return true; } // Debug.Log("Player Not Attacking"); return false; } //is the player kicking? public bool d_isPlayerKicking() { if (isPlayerKicking == true) { return true; } return false; } //is the enemy able to attack? //if yes he will attack //if no he will move towards the player public bool d_inAttackRange() { isEnemyKicking = false; isEnemyPushing = false; myAnimator.SetBool("drink", false); if (Vector3.Distance(transform.position, target.position) < 1.5f && Vector3.Distance(transform.position, target.position) > 1f) { myAnimator.SetFloat("speed", 0); return true; } else { myAnimator.SetBool("kick", false); myAnimator.SetBool("attack", false); myAnimator.SetBool("block", false); // myAnimator.SetBool("knockBack", false); myAnimator.SetBool("push", false); // Debug.Log("In Zone- not"); return false; } } //is the player too close? //if no the enemy moves towards //if yes the enemy moves backwards public bool d_isPlayerTooClose() { if (Vector3.Distance(transform.position, target.position) < 1f) { myAnimator.SetFloat("speed", 1f); return false; } else { return true; } } //if the player too far //if yes the enemy throws object to taunt you public bool d_isPlayerTooFar() { if (Vector3.Distance(transform.position, target.position) > 7.5f && Vector3.Distance(transform.position, target.position) < 12f) { return true; } else { return false; } } //is the player aggressive, checks to see if the user is spamming attack public bool d_isPlayerAggresive() { if (spaceBarCounter > 7 && aggressiveTimer > 0) { isAggressive = true; // Debug.Log("Aggressive"); return true; } else { isAggressive = false; // Debug.Log("Not Aggresive"); return false; } } //is the player blocking public bool d_isPlayerBlocking() { if (isPlayerBlocking == true) { return true; } return false; } //checks the Players HP //if players HP reaches below a certain threshold AI descions will be altered public bool d_isPlayerHpLow() { if ((playerHealthOriginal * 0.2f) > playerHealth) { return true; } return false; } //checks the Enemies HP //if Enemis HP reaches below a certain threshold AI descions will be altered public bool d_isHpLow() { myAnimator.SetBool("drink", false); if ((original / 2) > enemyHealth) { if (healthPotion >= 1) { myAnimator.SetBool("drink", true); enemyHealth += (int)(original * 0.5); if (enemyHealth > original) { enemyHealth = original; } healthPotion--; } return true; } return false; } //makes a random decision with a 75% true return and a 25% false return public bool d_randomDecision75() { int x = Random.Range(1, 4); if (x == 1) { // Debug.Log("Random"); return false; } else return true; } //Actions for the end of the Decision Tree //Enemies attack, with cooldown so he can spam and kill you too fast public void a_attack() { actionDelay = true; myAnimator.SetFloat("speed", 0f); if (coolDown <= 0) { coolDown = attackSpeed; // Debug.Log("attacking"); myAnimator.SetBool("attack", true); Enemy.velocity = Vector2.zero; } else { myAnimator.SetBool("attack", false); } } //Jump over the Player public void a_jumpOverPlayer() { actionDelay = true; if (LookRight == true) { // Debug.Log("Over Yo HEAD"); Enemy.AddForce(new Vector2(100, 1000)); } else { // Debug.Log("Over Yo HEAD"); Enemy.AddForce(new Vector2(-100, 1000)); } } //Push the player away public void a_push() { actionDelay = true; aggressiveTimer = 5; spaceBarCounter = 0; myAnimator.SetBool("push", true); // Debug.Log("Pushing"); Invoke("enemyPushing", 0.1f); } //Check for the Player, if the enemy is pushing then the player gets knocked back public void enemyPushing() { isEnemyPushing = true; } //Rouge attack, if the players HP gets really low the enemy goes insane and gets super aggressive public void a_superAttack() { myAnimator.SetFloat("speed", 0f); Debug.Log("SUPER!!!!"); myAnimator.SetBool("attack", true); } //Jump back away from combat, dodging attacks public void a_jumpBack() { actionDelay = true; if (LookRight == true) { Enemy.AddForce(new Vector2(-250, 500)); } else { Enemy.AddForce(new Vector2(250, 500)); } } //Casual jump public void a_jump() { actionDelay = true; Enemy.AddForce(new Vector2(0, 500)); } //Block, will defend off the player reducing hits public void a_block() { // Debug.Log("Block"); actionDelay = true; myAnimator.SetBool("attack", false); myAnimator.SetBool("block", true); Enemy.velocity = Vector2.zero; } //Kick, kick will disarm the player if they are blocking public void a_kick() { actionDelay = true; if (kickCoolDown <= 0) { isEnemyKicking = true; kickCoolDown = kickTimer; // Debug.Log("kicking"); myAnimator.SetBool("kick", true); Enemy.velocity = Vector2.zero; } else { myAnimator.SetBool("kick", false); myAnimator.SetBool("attack", true); } } //Throw - throws objects at the player public void a_throw() { actionDelay = true; myAnimator.SetFloat("speed", 0f); if (throwCoolDown <= 0) { throwCoolDown = throwTimer; // Debug.Log("throwing"); myAnimator.SetBool("throw", true); Invoke("bananaToss", 0.2f); } else { myAnimator.SetBool("throw", false); } } //Spawns the object which is thrown at the player public void bananaToss() { Vector3 offset = transform.rotation * new Vector3(0.5f, 0.5f, 0); //fire from the front of the player Instantiate(bananaPrefab, transform.position + offset, transform.rotation); myAnimator.SetBool("throw", false); } //change up the movement so its not so predictable public void a_walkOrDash() { if (dash == false) { a_dashToPlayer(); dash = true; } else { a_moveToPlayer(); } } //Will allow the enemy it either attack the player or preform a random action //50% chance of either happening public void a_AttackOrRandom() { // Debug.Log("Action"); float x = Random.Range(0, 2); actionDelay = true; if (x == 1) { a_attack(); } if (x == 2) { a_randomAction(); } } //Random Actions too keep the Enemy always moving //Each action is given a differnt activation % //Push 5% //Jump Back 15% //Jump Over Player 20% //Attack 40% //Kick 20% public void a_randomAction() { // Debug.Log("Action"); float x = Random.Range(0, 500); actionDelay = true; if (randomActionCoolDown <= 0) { //Debug.Log(x); randomActionCoolDown = randomAction; if (x < 25) { a_push(); } if (x > 25 && x < 125) { a_jumpOverPlayer(); } if (x > 225 && x <= 300) { a_jumpBack(); } if (x >= 125 && x <= 225) { a_attack(); } if (x > 300 && x <= 400) { a_kick(); } if (x > 400) { a_attack(); } } } //Random Block so the enemy doesnt just hold his shield every time //each block is given a certain % activation public void a_randomBlock() { float x = Random.Range(0, 350); actionDelay = true; if (randomActionCoolDown <= 0) { //Debug.Log(x); randomActionCoolDown = randomAction; if (x < 125) { a_jumpOverPlayer(); } if (x >= 125 && x <= 200) { a_jumpBack(); } if (x > 200 && x < 250) { a_push(); } if (x > 250) { a_block(); } } } //Random Attack //Enemy will still use basic attack more often then any action //this random action gives variety public void a_randomAttack() { float x = Random.Range(0, 250); actionDelay = true; if (randomActionCoolDown <= 0) { //Debug.Log(x); randomActionCoolDown = randomAction; if (x < 125) { a_attack(); } if (x >= 125 && x <= 200) { a_kick(); } if (x > 200) { a_throw(); } } } //Chance to Kick the shield down off the player if they are blocking public void a_disarmSheild() { actionDelay = true; float x = Random.Range(0, 3); if (x == 1) { a_kick(); } else { a_randomAttack(); } } public void a_moveToPlayer() { // Debug.Log("moving"); //rotate to look at the player //transform.LookAt(target.position); myAnimator.SetFloat("speed", 1); // This should probbaly reflect the actual speed transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime); if (target.transform.position.x <= transform.position.x) //players spot in world space as opposed to enemy "self" spot { LookRight = false; transform.rotation = new Quaternion(0, 180, 0, 0); // flips enemy around to face the player on x axis only } else if (target.transform.position.x >= transform.position.x) //players spot in world space as opposed to enemy "self" spot { LookRight = true; transform.rotation = new Quaternion(0, 0, 0, 0); // flips enemy around to face the player on x axis only } } } public void a_dashToPlayer() { // Debug.Log("moving"); //rotate to look at the player //transform.LookAt(target.position); myAnimator.SetFloat("speed", 1); // This should probbaly reflect the actual speed if (target.transform.position.x <= transform.position.x) //players spot in world space as opposed to enemy "self" spot { LookRight = false; transform.rotation = new Quaternion(0, 180, 0, 0); // flips enemy around to face the player on x axis only Enemy.AddForce(new Vector2(-350, Player.velocity.y * 5)); } else if (target.transform.position.x >= transform.position.x) //players spot in world space as opposed to enemy "self" spot { LookRight = true; transform.rotation = new Quaternion(0, 0, 0, 0); // flips enemy around to face the player on x axis only } Enemy.AddForce(new Vector2(350, Player.velocity.y * 5)); } } public void a_moveFromPlayer() { // Debug.Log("movingAWAY"); //rotate to look at the player //transform.LookAt(target.position); myAnimator.SetFloat("speed", 1); // This should probbaly reflect the actual speed transform.position = Vector2.MoveTowards(transform.position, target.position, (-speed * 2) * Time.deltaTime); if (target.transform.position.x <= transform.position.x) //players spot in world space as opposed to enemy "self" spot { transform.rotation = new Quaternion(0, 180, 0, 0); // flips enemy around to face the player on x axis only } else if (target.transform.position.x >= transform.position.x) //players spot in world space as opposed to enemy "self" spot { transform.rotation = new Quaternion(0, 0, 0, 0); // flips enemy around to face the player on x axis only } } } /* * BuildDecisionTree() * each action and decision above are used in this function to create the DecisionTree */ public void BuildDecisionTree() { //Actions DecisionTree Dash = new DecisionTree(); Dash.setAction(a_dashToPlayer); DecisionTree RandomWalk = new DecisionTree(); RandomWalk.setAction(a_walkOrDash); DecisionTree RandomAction = new DecisionTree(); RandomAction.setAction(a_randomAction); DecisionTree RandomBlock = new DecisionTree(); RandomBlock.setAction(a_randomBlock); DecisionTree RandomAttack = new DecisionTree(); RandomAttack.setAction(a_randomAction); DecisionTree AttackOrRandom = new DecisionTree(); AttackOrRandom.setAction(a_AttackOrRandom); DecisionTree Push = new DecisionTree(); Push.setAction(a_push); DecisionTree Rouge = new DecisionTree(); Rouge.setAction(a_superAttack); DecisionTree Kick = new DecisionTree(); Kick.setAction(a_kick); DecisionTree DisarmShield = new DecisionTree(); DisarmShield.setAction(a_disarmSheild); DecisionTree JumpBack = new DecisionTree(); JumpBack.setAction(a_jumpBack); DecisionTree Block = new DecisionTree(); Block.setAction(a_block); DecisionTree MoveToPlayer = new DecisionTree(); MoveToPlayer.setAction(a_moveToPlayer); DecisionTree Attack = new DecisionTree(); Attack.setAction(a_attack); DecisionTree MoveAway = new DecisionTree(); MoveAway.setAction(a_moveFromPlayer); DecisionTree JumpOverPlayer = new DecisionTree(); JumpOverPlayer.setAction(a_jumpOverPlayer); DecisionTree Throw = new DecisionTree(); Throw.setAction(a_throw); // Decisions DecisionTree isPlayerBlocking = new DecisionTree(); isPlayerBlocking.setDecision(d_isPlayerBlocking); isPlayerBlocking.setLeft(DisarmShield); isPlayerBlocking.setRight(Push); DecisionTree isPlayerBlocking2 = new DecisionTree(); isPlayerBlocking2.setDecision(d_isPlayerBlocking); isPlayerBlocking2.setLeft(DisarmShield); isPlayerBlocking2.setRight(AttackOrRandom); /* DecisionTree JumpPlayer = new DecisionTree(); JumpPlayer.setDecision(d_jumpOverPlayer); JumpPlayer.setLeft(JumpOverPlayer); JumpPlayer.setRight(RandomAction); */ DecisionTree PlayerHP2 = new DecisionTree(); PlayerHP2.setDecision(d_isPlayerHpLow); PlayerHP2.setLeft(AttackOrRandom); PlayerHP2.setRight(isPlayerBlocking2); DecisionTree PlayerHP3 = new DecisionTree(); PlayerHP3.setDecision(d_isPlayerHpLow); PlayerHP3.setLeft(Rouge); PlayerHP3.setRight(isPlayerBlocking2); DecisionTree EnemyHP = new DecisionTree(); EnemyHP.setDecision(d_isHpLow); EnemyHP.setLeft(PlayerHP2); EnemyHP.setRight(PlayerHP3); DecisionTree GettingAttacked = new DecisionTree(); GettingAttacked.setDecision(d_isPlayerAttacking); GettingAttacked.setLeft(RandomBlock); GettingAttacked.setRight(EnemyHP); DecisionTree PlayerHP = new DecisionTree(); PlayerHP.setDecision(d_isPlayerHpLow); PlayerHP.setLeft(Attack); PlayerHP.setRight(isPlayerBlocking); /* DecisionTree JumpPlayer2 = new DecisionTree(); JumpPlayer2.setDecision(d_jumpOverPlayer); JumpPlayer2.setLeft(JumpOverPlayer); JumpPlayer2.setRight(EnemyHP); */ DecisionTree GettingAttacked2 = new DecisionTree(); GettingAttacked2.setDecision(d_isPlayerAttacking); GettingAttacked2.setLeft(RandomBlock); GettingAttacked2.setRight(EnemyHP); //Random Action Trees DecisionTree Random01 = new DecisionTree(); Random01.setDecision(d_randomDecision75); Random01.setLeft(PlayerHP); Random01.setRight(Attack); //Random Action Trees DecisionTree Random02 = new DecisionTree(); Random02.setDecision(d_randomDecision75); Random02.setLeft(GettingAttacked2); Random02.setRight(AttackOrRandom); DecisionTree Aggressiveness = new DecisionTree(); Aggressiveness.setDecision(d_isPlayerAggresive); Aggressiveness.setLeft(Random01); Aggressiveness.setRight(Random02); DecisionTree IsPlayerTooFar = new DecisionTree(); IsPlayerTooFar.setDecision(d_isPlayerTooFar); IsPlayerTooFar.setLeft(Throw); IsPlayerTooFar.setRight(RandomWalk); DecisionTree IsPlayerTooClose = new DecisionTree(); IsPlayerTooClose.setDecision(d_isPlayerTooClose); IsPlayerTooClose.setLeft(IsPlayerTooFar); IsPlayerTooClose.setRight(MoveAway); root.setDecision(d_inAttackRange); root.setLeft(Aggressiveness); root.setRight(IsPlayerTooClose); } }