You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

232 lines
5.6 KiB

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAI : EnemyActions, IDamagable<DamageObject>{
[Space(10)]
public bool enableAI;
public float chargeTime = 0f;
public bool ranged = false;
public DamageObject rangedDamage;
float _timeToShoot = 4f;
//a list of states where the AI is executed
private List<UNITSTATE> ActiveAIStates = new List<UNITSTATE> {
UNITSTATE.IDLE,
UNITSTATE.WALK,
UNITSTATE.CHARGE
};
void Start(){
//add this enemy to the enemylist
EnemyManager.enemyList.Add(gameObject);
//set z spread (zspread is used to keep space between the enemies)
ZSpread = (EnemyManager.enemyList.Count-1);
Invoke ("SetZSpread", .1f);
//randomize values to avoid synchronous movement
if(randomizeValues) SetRandomValues();
OnStart();
}
void FixedUpdate(){
OnFixedUpdate();
}
void LateUpdate(){
OnLateUpdate();
}
void Shoot()
{
_timeToShoot -= Time.deltaTime;
if (ranged && _timeToShoot < 0 && enemyState != UNITSTATE.KNOCKDOWNGROUNDED)
{
//spawn projectile at spawn position
GameObject projectilePrefab = GameObject.Instantiate(Resources.Load("ProjectileEnemyKnife"), this.transform.position + new Vector3(0f, 1f, 0f), Quaternion.identity) as GameObject;
if (!projectilePrefab) return;
//set projectile to current direction
Projectile projectileComponent = projectilePrefab.GetComponent<Projectile>();
if (projectileComponent)
{
projectileComponent.firedByEnemy = true;
projectileComponent.direction = this.currentDirection;
rangedDamage.inflictor = this.gameObject;
projectileComponent.SetDamage(rangedDamage);
}
_timeToShoot = 3f;
}
}
void Update(){
Shoot();
chargeTime -= Time.deltaTime;
//do nothing when there is no target or when AI is disabled
if (target == null || !enableAI) {
Ready ();
return;
} else {
//get range to target
range = GetDistanceToTarget ();
}
if(!isDead && enableAI){
if(ActiveAIStates.Contains(enemyState) && targetSpotted) {
//AI active
AI();
} else {
//try to spot the player
if(distanceToTarget.magnitude < sightDistance) targetSpotted = true;
}
}
}
void AI(){
LookAtTarget(target.transform);
if (enemyTactic == ENEMYTACTIC.CHARGE)
{
if (chargeTime < 0)
{
WalkTo(closeRangeDistance, 0f);
chargeTime = 2f;
}
else
{
Charge();
}
}
if (range == RANGE.ATTACKRANGE){
//attack the target
if (!cliffSpotted){
if (Time.time - lastAttackTime > attackInterval) {
ATTACK();
} else {
Ready();
}
return;
}
//actions for ATTACKRANGE distance
if (enemyTactic == ENEMYTACTIC.KEEPCLOSEDISTANCE) WalkTo(closeRangeDistance, 0f);
if (enemyTactic == ENEMYTACTIC.KEEPMEDIUMDISTANCE) WalkTo(midRangeDistance, RangeMarging);
if (enemyTactic == ENEMYTACTIC.KEEPFARDISTANCE) WalkTo(farRangeDistance, RangeMarging);
if (enemyTactic == ENEMYTACTIC.STANDSTILL) Ready ();
} else {
//actions for CLOSERANGE, MIDRANGE & FARRANGE distances
if (enemyTactic == ENEMYTACTIC.ENGAGE) WalkTo (attackRangeDistance, 0f);
if (enemyTactic == ENEMYTACTIC.KEEPCLOSEDISTANCE) WalkTo(closeRangeDistance, RangeMarging);
if (enemyTactic == ENEMYTACTIC.KEEPMEDIUMDISTANCE) WalkTo(midRangeDistance, RangeMarging);
if (enemyTactic == ENEMYTACTIC.KEEPFARDISTANCE) WalkTo(farRangeDistance, RangeMarging);
if (enemyTactic == ENEMYTACTIC.STANDSTILL) Ready();
}
}
//update the current range
private RANGE GetDistanceToTarget(){
if (target != null) {
//get distance from the target
distanceToTarget = target.transform.position - transform.position;
distance = Vector3.Distance (target.transform.position, transform.position);
float distX = Mathf.Abs(distanceToTarget.x);
float distZ = Mathf.Abs(distanceToTarget.z);
//AttackRange
if(distX <= attackRangeDistance){
if(distZ < (hitZRange/2f))
return RANGE.ATTACKRANGE;
else
return RANGE.CLOSERANGE;
}
//Close Range
if (distX > attackRangeDistance && distX < midRangeDistance) return RANGE.CLOSERANGE;
//Mid range
if(distX > closeRangeDistance && distance < farRangeDistance) return RANGE.MIDRANGE;
//Far range
if(distX > farRangeDistance) return RANGE.FARRANGE;
}
return RANGE.FARRANGE;
}
//set an enemy tactic
public void SetEnemyTactic(ENEMYTACTIC tactic){
if (enemyTactic != ENEMYTACTIC.CHARGE)
enemyTactic = tactic;
}
//spread enemies out in z distance
void SetZSpread(){
ZSpread = (ZSpread - (float)(EnemyManager.enemyList.Count - 1) / 2f) * (capsule.radius*2) * zSpreadMultiplier;
if (ZSpread > attackRangeDistance) ZSpread = attackRangeDistance - 0.1f;
}
//Unit has died
void Death(){
StopAllCoroutines();
CancelInvoke();
enableAI = false;
isDead = true;
animator.SetAnimatorBool("isDead", true);
Move(Vector3.zero, 0);
EnemyManager.RemoveEnemyFromList(gameObject);
gameObject.layer = LayerMask.NameToLayer ("Default");
//ground death
if(enemyState == UNITSTATE.KNOCKDOWNGROUNDED) {
StartCoroutine(GroundHit());
} else {
//normal death
animator.SetAnimatorTrigger("Death");
}
GlobalAudioPlayer.PlaySFXAtPosition("EnemyDeath", transform.position);
StartCoroutine (animator.FlickerCoroutine(2));
enemyState = UNITSTATE.DEATH;
DestroyUnit();
}
}
public enum ENEMYTACTIC {
ENGAGE = 0,
KEEPCLOSEDISTANCE = 1,
KEEPMEDIUMDISTANCE = 2,
KEEPFARDISTANCE = 3,
STANDSTILL = 4,
CHARGE = 5
}
public enum RANGE {
ATTACKRANGE,
CLOSERANGE,
MIDRANGE,
FARRANGE,
}