Fixed small visual bugs
This commit is contained in:
@@ -0,0 +1,925 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Pathfinding;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
// Designed by the goat Jacob Weedman
|
||||
// Use on any basic enemy
|
||||
//
|
||||
// Configure to your likeing
|
||||
// Not all options apply with every configuration
|
||||
//
|
||||
// PREREQUISITES
|
||||
// 1. The "Seeker" script from the A* pathfinding library must be attatched to the same game object
|
||||
// 2. A Rigidbody2D component must be attatched to the same game object
|
||||
// 3. A _Collider2D component must be attatched to the same game object
|
||||
// 4. Various game objects are required to be in the scene in order for this to function properly
|
||||
// 5. Various children game objects are required in order for this to funciton properly
|
||||
|
||||
public class MasterEnemyAI : MonoBehaviour
|
||||
{
|
||||
|
||||
#region MISC VARIABLES (DO NOT CHANGE VALUES)
|
||||
GameObject Target = null;
|
||||
GameObject Camera = null;
|
||||
GameObject Player = null;
|
||||
GameObject Barrel = null;
|
||||
Vector2 StartPosition;
|
||||
public GameObject LastKnownPlayerLocation = null;
|
||||
float DistanceFromPlayer;
|
||||
public List<GameObject> SuitablePositions;
|
||||
public List<GameObject> AllPositions;
|
||||
public List<GameObject> PatrolPositions;
|
||||
// start pathfinding
|
||||
float nextWaypointDistance = 5;
|
||||
Path path = null;
|
||||
int currentWaypoint = 0;
|
||||
bool reachedEndOfPath = false;
|
||||
// end pathfinding
|
||||
#endregion
|
||||
|
||||
#region CONDITIONS/GENERAL INFORMATION
|
||||
bool PositionRecomputeLock = false;
|
||||
public bool TargetingPlayer = false;
|
||||
public bool CurrentlyReloading = false;
|
||||
bool PatrolLock = false;
|
||||
bool Lock = false;
|
||||
bool MoveLock = false;
|
||||
bool FireLock = false;
|
||||
bool DashLock = false;
|
||||
bool TeleportLock = true;
|
||||
bool CurrentlyMovingToNextPatrolTarget = false;
|
||||
float DesiredDistance;
|
||||
public int WeaponCurrentMagazineAmmount;
|
||||
public int NumberOfHitsPerMag = 0;
|
||||
float BarrelAngle;
|
||||
bool Primed = false; // For self-explosion
|
||||
|
||||
#endregion
|
||||
|
||||
#region ENEMY STATS (Changeable in Unity)
|
||||
public float Speed = 1f; // In relation to player's walking speed
|
||||
public float JumpHeight = 1.5f; // In relation to player's regular jump height
|
||||
public float Health = 100;
|
||||
public float MinumumDistance = 5f;
|
||||
public float PatrolDistance = 10;
|
||||
public int PlayerDetectionRange = 50;
|
||||
float PatrolCooldown;
|
||||
public float PatrolCooldownReset = 20.0f;
|
||||
float JumpCooldown;
|
||||
public float JumpCooldownReset = 1.0f;
|
||||
float FireCooldown;
|
||||
public float FireCooldownReset = 0.1f;
|
||||
float ReloadCooldown;
|
||||
public float ReloadCooldownReset = 5.0f;
|
||||
public float DashSpeed = 40f; // Strength of the dash
|
||||
float DashCooldown;
|
||||
public float DashCooldownReset = 4.0f;
|
||||
float TeleportCooldown;
|
||||
public float TeleportCooldownReset = 0.5f;
|
||||
public float HiddenTransparencyAmmount = 0.05f; // Strength of the cloaked transparency
|
||||
public int MaxBatteryCapacity = 30; // Depletes one every second it is out of the bay
|
||||
public int RechargeTime = 6000; //ms
|
||||
|
||||
// Capabiltiies
|
||||
public bool AbilityDash = false;
|
||||
public bool AbilityInvisible = false;
|
||||
public bool AbilityJump = true;
|
||||
public bool AbilityTeleport = false;
|
||||
public bool AbilityReloadAndMove = false;
|
||||
public bool AbilityMove = true;
|
||||
public bool AbilityDynamicRelocation = true;
|
||||
public bool AbilityExplodeOnContact = false;
|
||||
public bool AbilityExplodeNearPlayer = false;
|
||||
public bool AbilityExplodeOnDeath = false;
|
||||
public bool AbilityPlayerESP = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region WEAPON STATS (CHANGEABLE in Unity)
|
||||
|
||||
public GameObject EnemyProjectile;
|
||||
public string EnemyType = "GROUND"; // Options: "GROUND", "AIR"
|
||||
public string WeaponType = "RANGED"; // Options: "RANGED", "ROCKET", "PARTICLE", "MELEE", "GRENADE", "NONE"
|
||||
public int WeaponDamage = 5; // Damage per hit
|
||||
public float WeaponRandomSpread = 7.5f; // Random direction of lanched projectiles
|
||||
public int WeaponRange = 15; // Maximum range of the projectile before it drops off
|
||||
public float WeaponProjectileSpeed = 40f; // Speed of launched projectiles
|
||||
public int WeaponMagazineSize = 20; // Number of shots the enemy will take before having to reloade
|
||||
|
||||
#endregion
|
||||
|
||||
#region COMPONENT REFERENCES
|
||||
Seeker seeker = null;
|
||||
Rigidbody2D rb = null;
|
||||
#endregion
|
||||
|
||||
#region ONCE THE ENEMY IS SPAWNED IN
|
||||
void Awake()
|
||||
{
|
||||
if (GetComponent<Seeker>())
|
||||
seeker = GetComponent<Seeker>();
|
||||
if (GetComponent<Rigidbody2D>())
|
||||
rb = GetComponent<Rigidbody2D>();
|
||||
|
||||
if (transform.Find("ReloadingIndicator"))
|
||||
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
if (transform.Find("PursuingIndicator"))
|
||||
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
|
||||
StartPosition = transform.position;
|
||||
|
||||
if (GameObject.FindGameObjectsWithTag("PossiblePositions").Count() > 0)
|
||||
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
|
||||
|
||||
if (EnemyType == "GROUND") // Configure settings for Ground enemies
|
||||
{
|
||||
foreach (GameObject pos in AllPositions)
|
||||
{
|
||||
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
|
||||
{
|
||||
PatrolPositions.Add(pos);
|
||||
}
|
||||
}
|
||||
|
||||
gameObject.layer = LayerMask.NameToLayer("Enemies");
|
||||
|
||||
foreach (Transform child in gameObject.transform)
|
||||
{
|
||||
child.gameObject.layer = LayerMask.NameToLayer("Enemies");
|
||||
}
|
||||
|
||||
if (PatrolPositions.Count() > 0)
|
||||
{
|
||||
Target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
|
||||
}
|
||||
else
|
||||
{
|
||||
Target = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (EnemyType == "AIR") // Configure settings for Air enemies
|
||||
{
|
||||
gameObject.layer = LayerMask.NameToLayer("FlyingEnemies");
|
||||
|
||||
foreach (Transform child in gameObject.transform)
|
||||
{
|
||||
child.gameObject.layer = LayerMask.NameToLayer("FlyingEnemies");
|
||||
}
|
||||
|
||||
rb.gravityScale = 0;
|
||||
if (GameObject.Find("FlyingTarget"))
|
||||
Target = Instantiate(GameObject.Find("FlyingTarget"), transform.position, Quaternion.identity);
|
||||
}
|
||||
|
||||
if (GameObject.FindGameObjectWithTag("MainCamera"))
|
||||
Camera = GameObject.FindGameObjectWithTag("MainCamera");
|
||||
if (GameObject.FindGameObjectWithTag("Player"))
|
||||
Player = GameObject.FindGameObjectWithTag("Player");
|
||||
|
||||
if (transform.Find("Barrel"))
|
||||
Barrel = transform.Find("Barrel").gameObject;
|
||||
|
||||
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
|
||||
DesiredDistance = WeaponRange - 5;
|
||||
|
||||
if (EnemyProjectile == null) // Automatically set enemy projectile if level designer did not
|
||||
{
|
||||
switch (WeaponType)
|
||||
{
|
||||
case "RANGED":
|
||||
EnemyProjectile = GameObject.Find("GameObjectFolder").transform.Find("EnemyProjectile").gameObject;
|
||||
break;
|
||||
|
||||
case "ROCKET":
|
||||
EnemyProjectile = GameObject.Find("GameObjectFolder").transform.Find("EnemyRocket").gameObject;
|
||||
break;
|
||||
|
||||
case "PARTICLE":
|
||||
EnemyProjectile = GameObject.Find("GameObjectFolder").transform.Find("EvilAura").gameObject;
|
||||
break;
|
||||
|
||||
case "GRENADE":
|
||||
EnemyProjectile = GameObject.Find("GameObjectFolder").transform.Find("Grenade").gameObject;
|
||||
break;
|
||||
|
||||
default:
|
||||
EnemyProjectile = GameObject.Find("GameObjectFolder").transform.Find("EnemyProjectile").gameObject;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
InvokeRepeating("UpdatePath", 0f, 0.1f);
|
||||
InvokeRepeating("PathfindingTimeout", 0f, 30);
|
||||
|
||||
// Initialize timers
|
||||
JumpCooldown = JumpCooldownReset;
|
||||
FireCooldown = FireCooldownReset;
|
||||
ReloadCooldown = ReloadCooldownReset;
|
||||
DashCooldown = DashCooldownReset;
|
||||
PatrolCooldown = 0;
|
||||
TeleportCooldown = TeleportCooldownReset;
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region INVOKE REPEATING METHODS
|
||||
// When enemy has reached the next node
|
||||
void OnPathComplete(Path p)
|
||||
{
|
||||
if (!p.error)
|
||||
{
|
||||
path = p;
|
||||
currentWaypoint = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Select next node
|
||||
void UpdatePath()
|
||||
{
|
||||
if (seeker.IsDone() && Target != null)
|
||||
{
|
||||
seeker.StartPath(rb.position, Target.transform.position, OnPathComplete);
|
||||
}
|
||||
}
|
||||
|
||||
// Pathfiniding Timeout
|
||||
void PathfindingTimeout()
|
||||
{
|
||||
if (Target != null && Vector2.Distance(transform.position, Target.transform.position) > 0.5 || LastKnownPlayerLocation == null)
|
||||
{
|
||||
LastKnownPlayerLocation = null;
|
||||
MoveNextPatrol();
|
||||
|
||||
if (AbilityTeleport && TeleportLock == false)
|
||||
{
|
||||
Teleport();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MAIN LOGIC
|
||||
void FixedUpdate()
|
||||
{
|
||||
#region DEATH
|
||||
if (Health <= 0)
|
||||
{
|
||||
if (AbilityExplodeNearPlayer == false && AbilityExplodeOnContact == false && AbilityExplodeOnDeath == false)
|
||||
{
|
||||
// Create carcas
|
||||
GameObject DeadBody;
|
||||
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
|
||||
DeadBody.GetComponent<Rigidbody2D>().gravityScale = 1.5f;
|
||||
Destroy(GameObject.Find(DeadBody.name).GetComponent<MasterEnemyAI>());
|
||||
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
|
||||
|
||||
foreach (Transform child in DeadBody.transform)
|
||||
{
|
||||
GameObject.Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
Destroy(gameObject);
|
||||
}
|
||||
else if (AbilityExplodeOnDeath == true)
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
}
|
||||
|
||||
// Explode when close to the player
|
||||
if (AbilityExplodeNearPlayer && Primed && Vector2.Distance(Player.transform.position, transform.position) <= 2)
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICONS
|
||||
|
||||
// See where the enemy wants to go (DEBUGGING ONLY)
|
||||
/*
|
||||
if (Target != null)
|
||||
{
|
||||
foreach (GameObject pos in AllPositions)
|
||||
{
|
||||
pos.GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
Target.GetComponent<SpriteRenderer>().enabled = true;
|
||||
}
|
||||
*/
|
||||
|
||||
if (TargetingPlayer && transform.Find("PursuingIndicator"))
|
||||
{
|
||||
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
|
||||
if (AbilityInvisible)
|
||||
{
|
||||
Cloak(false);
|
||||
}
|
||||
}
|
||||
else if (transform.Find("PursuingIndicator"))
|
||||
{
|
||||
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
if (AbilityInvisible)
|
||||
{
|
||||
Cloak(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (CurrentlyReloading && transform.Find("ReloadingIndicator"))
|
||||
{
|
||||
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
|
||||
}
|
||||
else if (transform.Find("ReloadingIndicator"))
|
||||
{
|
||||
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
|
||||
//if (90 <= angle || angle <= 270) // FIX THIS
|
||||
//{
|
||||
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
|
||||
//}
|
||||
#endregion
|
||||
|
||||
#region MISC PATHFINDING
|
||||
// Player ESP
|
||||
if (AbilityPlayerESP)
|
||||
{
|
||||
LastKnownPlayerLocation = Player;
|
||||
}
|
||||
|
||||
if (path == null)
|
||||
return;
|
||||
|
||||
if (Target == null)
|
||||
return;
|
||||
if (currentWaypoint >= path.vectorPath.Count)
|
||||
{
|
||||
reachedEndOfPath = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
reachedEndOfPath = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// Rotate barrel towards player
|
||||
if (Barrel != null) // PRevents error
|
||||
{
|
||||
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, BarrelAngle));
|
||||
Barrel.transform.rotation = Quaternion.RotateTowards(Barrel.transform.rotation, targetRotation, 200 * Time.deltaTime);
|
||||
}
|
||||
|
||||
#region TARGET DETERMINATION & PATROL & PLAYER DETECTION
|
||||
|
||||
// Check if the enemy is at the target location, used for moving to the next patrol target
|
||||
if (Vector2.Distance(transform.position, Target.transform.position) <= 1)
|
||||
{
|
||||
PatrolLock = false;
|
||||
MoveNextPatrol();
|
||||
}
|
||||
|
||||
// Patrol Countdown
|
||||
PatrolCooldown -= Time.deltaTime;
|
||||
if (PatrolCooldown <= UnityEngine.Random.Range(-3, 3))
|
||||
PatrolLock = false;
|
||||
else
|
||||
PatrolLock = true;
|
||||
|
||||
// If enemy has line of sight and is close enough the player is detected
|
||||
if (DetermineLineOfSight(gameObject, Player) && Vector2.Distance(transform.position, Player.transform.position) <= PlayerDetectionRange)
|
||||
{
|
||||
TargetingPlayer = true;
|
||||
PositionRecomputeLock = false;
|
||||
Primed = true; // for explosive enemies
|
||||
|
||||
// Get the last know player location by finding which of the positions is closest to the player
|
||||
if (LastKnownPlayerLocation == null)
|
||||
{
|
||||
LastKnownPlayerLocation = gameObject;
|
||||
}
|
||||
foreach (GameObject pos in AllPositions)
|
||||
{
|
||||
if (Vector2.Distance(Player.transform.position, pos.transform.position) < Vector2.Distance(Player.transform.position, LastKnownPlayerLocation.transform.position))
|
||||
{
|
||||
LastKnownPlayerLocation = pos;
|
||||
}
|
||||
}
|
||||
|
||||
// Angle barrel towards player
|
||||
if (Barrel != null)
|
||||
{
|
||||
BarrelAngle = Mathf.Atan2(Player.transform.position.y - Barrel.transform.position.y, Player.transform.position.x - Barrel.transform.position.x) * Mathf.Rad2Deg;
|
||||
}
|
||||
|
||||
}
|
||||
// Player has broken line of sight and the enemy will attempt to move to the last known location
|
||||
else if (LastKnownPlayerLocation != null)
|
||||
{
|
||||
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
|
||||
{
|
||||
PositionRecomputeLock = true;
|
||||
Target = LastKnownPlayerLocation;
|
||||
|
||||
if (AbilityTeleport && TeleportLock == false)
|
||||
{
|
||||
Teleport();
|
||||
}
|
||||
|
||||
}
|
||||
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(Player, gameObject) == false)
|
||||
{
|
||||
TargetingPlayer = false;
|
||||
LastKnownPlayerLocation = null;
|
||||
}
|
||||
|
||||
// Reset barrel rotation
|
||||
BarrelAngle = 0f;
|
||||
}
|
||||
// Go back to patrol move
|
||||
else
|
||||
{
|
||||
Primed = false;
|
||||
TargetingPlayer = false;
|
||||
|
||||
if (MoveLock == false)
|
||||
{
|
||||
MoveNextPatrol();
|
||||
}
|
||||
|
||||
// Reset barrel rotation
|
||||
BarrelAngle = 0f;
|
||||
}
|
||||
|
||||
if (PositionRecomputeLock == false)
|
||||
{
|
||||
// Catch desired distance error
|
||||
if (DesiredDistance <= MinumumDistance)
|
||||
{
|
||||
DesiredDistance = MinumumDistance + 1;
|
||||
}
|
||||
|
||||
// If the player moves away (CHANGE TARGET)
|
||||
if (Vector2.Distance(Target.transform.position, Player.transform.position) > DesiredDistance)
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
}
|
||||
|
||||
// If the player is too close to the target (CHANGE TARGET)
|
||||
if (Vector2.Distance(Target.transform.position, Player.transform.position) < MinumumDistance)
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
}
|
||||
|
||||
// If the target is on the other side of the player (CHANGE TARGET)
|
||||
//if (Vector2.Distance(transform.position, player.transform.position) < Vector2.Distance(target.transform.position, player.transform.position))
|
||||
//{
|
||||
// ComputeClosestPositionToPlayer();
|
||||
//}
|
||||
|
||||
// If the player is not within line of sight of the desired position (CHANGE TARGET)
|
||||
if (DetermineLineOfSight(Target, Player) == false)
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
}
|
||||
|
||||
if (TeleportLock == false && AbilityTeleport)
|
||||
{
|
||||
if (Vector2.Distance(transform.position, Target.transform.position) > 0.5)
|
||||
{
|
||||
Teleport();
|
||||
}
|
||||
}
|
||||
|
||||
// If the enemy reaches the target
|
||||
if (Vector2.Distance(Target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, Player))
|
||||
{
|
||||
if (EnemyType == "AIR")
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
}
|
||||
if (TeleportLock == false && AbilityTeleport)
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
Teleport();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MOVEMENT & GROUND DETECTION
|
||||
|
||||
//Detecting if the enemy has reached the ground
|
||||
if (EnemyType == "GROUND" && AbilityJump && GetComponentInChildren<GroundCheck>()) // Makes sure the enemy can jump before calculating
|
||||
{
|
||||
if (GetComponent<GroundCheck>().isGrounded == true)
|
||||
{
|
||||
JumpCooldown -= Time.deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
JumpCooldown = JumpCooldownReset;
|
||||
}
|
||||
}
|
||||
|
||||
// Decriment dash timer
|
||||
DashCooldown -= Time.deltaTime;
|
||||
if (DashCooldown <= 0 && Vector2.Distance(transform.position, Target.transform.position) > 2)
|
||||
DashLock = false;
|
||||
else
|
||||
DashLock = true;
|
||||
// Call Dash
|
||||
if (DashLock == false && AbilityDash)
|
||||
{
|
||||
Dash();
|
||||
}
|
||||
|
||||
// Decriment teleport timer
|
||||
TeleportCooldown -= Time.deltaTime;
|
||||
if (TeleportCooldown <= 0 && Vector2.Distance(transform.position, Target.transform.position) > 2)
|
||||
TeleportLock = false;
|
||||
else
|
||||
TeleportLock = true;
|
||||
|
||||
// Ground Movement
|
||||
if (MoveLock == false && EnemyType == "GROUND" && AbilityMove)
|
||||
{
|
||||
//FireLock = false;
|
||||
|
||||
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
|
||||
|
||||
if (GetComponent<GroundCheck>().isGrounded == true) // Movement while grounded
|
||||
{
|
||||
if (direction.x > 0) // Move right
|
||||
{
|
||||
if (TargetingPlayer)
|
||||
{
|
||||
if (Math.Abs(rb.linearVelocity.x) < Speed * 20) // Targeting player speed Cap
|
||||
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Math.Abs(rb.linearVelocity.x) < Speed * 5) // Wandering speed Cap
|
||||
rb.AddForce(new Vector2(Speed * 10, rb.linearVelocity.y));
|
||||
}
|
||||
}
|
||||
|
||||
if (direction.x < 0) // Move left
|
||||
{
|
||||
if (TargetingPlayer)
|
||||
{
|
||||
if (Math.Abs(rb.linearVelocity.x) < Speed * 20) // Targeting player speed Cap
|
||||
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Math.Abs(rb.linearVelocity.x) < Speed * 5) // Wandering speed Cap
|
||||
rb.AddForce(new Vector2(-1 * Speed * 10, rb.linearVelocity.y));
|
||||
}
|
||||
}
|
||||
|
||||
if (direction.y > 1f) // Wants to jump
|
||||
{
|
||||
Jump(direction.x);
|
||||
}
|
||||
}
|
||||
else // Movement while in the air
|
||||
{
|
||||
if (direction.x > 0) // Move right
|
||||
{
|
||||
rb.AddForce(new Vector2(Speed * 2, rb.linearVelocity.y));
|
||||
}
|
||||
|
||||
if (direction.x < 0) // Move left
|
||||
{
|
||||
rb.AddForce(new Vector2(-1 * Speed * 2, rb.linearVelocity.y));
|
||||
}
|
||||
}
|
||||
|
||||
// A* logic
|
||||
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
|
||||
|
||||
if (distance < nextWaypointDistance)
|
||||
{
|
||||
currentWaypoint++;
|
||||
}
|
||||
}
|
||||
// Air Movement
|
||||
if (MoveLock == false && EnemyType == "AIR" && AbilityMove)
|
||||
{
|
||||
Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] - rb.position).normalized;
|
||||
Vector2 force = direction * Speed * 20;
|
||||
|
||||
rb.AddForce(force);
|
||||
|
||||
// A* logic
|
||||
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
|
||||
|
||||
if (distance < nextWaypointDistance)
|
||||
{
|
||||
currentWaypoint++;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ATTACK
|
||||
|
||||
// Decriment timer
|
||||
FireCooldown -= Time.deltaTime;
|
||||
if (FireCooldown <= 0 && CurrentlyReloading == false)
|
||||
FireLock = false;
|
||||
else
|
||||
FireLock = true;
|
||||
|
||||
if (WeaponCurrentMagazineAmmount > 0 && FireLock == false && CurrentlyReloading == false && WeaponType != "NONE")
|
||||
{
|
||||
if (DetermineLineOfSight(gameObject, Player) == true && Vector2.Distance(transform.position, Player.transform.position) <= WeaponRange)
|
||||
{
|
||||
UseWeapon();
|
||||
}
|
||||
}
|
||||
else if (WeaponCurrentMagazineAmmount == 0 && CurrentlyReloading == false)
|
||||
{
|
||||
CurrentlyReloading = true;
|
||||
}
|
||||
|
||||
// Engage periodical reloading if player moves too far away and mag is low
|
||||
if (Vector2.Distance(transform.position, Player.transform.position) > WeaponRange + 5 && WeaponCurrentMagazineAmmount / WeaponMagazineSize < 0.75f)
|
||||
{
|
||||
ReloadCooldown = ReloadCooldownReset / 5; // Make reloading faster
|
||||
CurrentlyReloading = true;
|
||||
}
|
||||
|
||||
// Reloading
|
||||
if (CurrentlyReloading)
|
||||
{
|
||||
ReloadCooldown -= Time.deltaTime;
|
||||
if (ReloadCooldown <= 0)
|
||||
{
|
||||
ReloadCooldown = ReloadCooldownReset;
|
||||
CurrentlyReloading = false;
|
||||
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
|
||||
// Dynamic Relocation
|
||||
if (NumberOfHitsPerMag / WeaponMagazineSize < 0.5 && AbilityDynamicRelocation)
|
||||
DesiredDistance -= 5;
|
||||
NumberOfHitsPerMag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void UseWeapon()
|
||||
{
|
||||
FireCooldown = FireCooldownReset;
|
||||
|
||||
switch (WeaponType)
|
||||
{
|
||||
case "RANGED":
|
||||
// Create Projectile
|
||||
GameObject BulletInstance;
|
||||
BulletInstance = Instantiate(EnemyProjectile, Barrel.transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
|
||||
//BulletInstance.transform.parent = transform;
|
||||
|
||||
// Variables
|
||||
BulletInstance.GetComponent<EnemyProjectileScript>().WeaponDamage = WeaponDamage;
|
||||
BulletInstance.GetComponent<EnemyProjectileScript>().WeaponRange = WeaponRange;
|
||||
|
||||
// Send it on it's way
|
||||
BulletInstance.GetComponent<Rigidbody2D>().linearVelocity = BulletInstance.transform.forward * -1 * WeaponProjectileSpeed;
|
||||
BulletInstance.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, BulletInstance.transform.forward) - 90));
|
||||
break;
|
||||
|
||||
case "ROCKET":
|
||||
|
||||
// Create Rocket
|
||||
GameObject Rocket;
|
||||
Rocket = Instantiate(EnemyProjectile, Barrel.transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
|
||||
|
||||
// Variables
|
||||
Rocket.GetComponent<EnemyRocket>().WeaponDamage = WeaponDamage;
|
||||
Rocket.GetComponent<EnemyRocket>().duration = 30;
|
||||
|
||||
// Send it on its way
|
||||
Rocket.GetComponent<Rigidbody2D>().linearVelocity = Rocket.transform.forward * -1 * WeaponProjectileSpeed;
|
||||
Rocket.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, Rocket.transform.forward) - 90));
|
||||
|
||||
break;
|
||||
|
||||
case "PARTICLE":
|
||||
|
||||
// Create particle
|
||||
GameObject ParticleWeapon;
|
||||
|
||||
ParticleWeapon = Instantiate(EnemyProjectile, new Vector3(Barrel.transform.position.x + UnityEngine.Random.Range(-0.5f, 0.5f), Barrel.transform.position.y + UnityEngine.Random.Range(-0.5f, 0.5f), EnemyProjectile.transform.position.z), Quaternion.identity);
|
||||
ParticleWeapon.GetComponent<Rigidbody2D>().linearVelocity = new Vector2(transform.position.x - Player.transform.position.x + UnityEngine.Random.Range(-WeaponRandomSpread, WeaponRandomSpread), transform.position.y - Player.transform.position.y + UnityEngine.Random.Range(-WeaponRandomSpread, WeaponRandomSpread)).normalized * 1.25f * WeaponRange * -1;
|
||||
|
||||
// Set variables
|
||||
ParticleWeapon.GetComponent<EnemyParticleWeapon>().destroy = true;
|
||||
ParticleWeapon.GetComponent<EnemyParticleWeapon>().opacity = true;
|
||||
ParticleWeapon.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
|
||||
|
||||
break;
|
||||
|
||||
case "MELEE":
|
||||
|
||||
GameObject.Find("GameData").GetComponent<GameData>().CurrentHealth -= WeaponDamage;
|
||||
|
||||
break;
|
||||
|
||||
case "GRENADE":
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.Log("Invalid or no weapon seleted.");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
WeaponCurrentMagazineAmmount--;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
// General Utility
|
||||
bool DetermineLineOfSight(GameObject object1, GameObject object2)
|
||||
{
|
||||
Vector3 RaycastStart = object1.transform.position;
|
||||
Vector3 RaycastDirection = (object2.transform.position - object1.transform.position).normalized;
|
||||
float RaycastDistance = Vector3.Distance(object2.transform.position, object1.transform.position);
|
||||
|
||||
if (Physics2D.Raycast(RaycastStart, RaycastDirection, RaycastDistance, LayerMask.GetMask("SolidGround")) == false)
|
||||
{
|
||||
Debug.DrawRay(RaycastStart, RaycastDirection * RaycastDistance);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Jump(float JumpDirection)
|
||||
{
|
||||
if (JumpCooldown <= 0 && AbilityJump)
|
||||
{
|
||||
JumpCooldown = JumpCooldownReset;
|
||||
rb.linearVelocity = new Vector2(rb.linearVelocity.x + JumpDirection, JumpHeight * 12);
|
||||
}
|
||||
}
|
||||
|
||||
// Part of the pursue cycle
|
||||
void ComputeClosestPositionToPlayer()
|
||||
{
|
||||
MoveLock = false;
|
||||
|
||||
if (EnemyType == "GROUND")
|
||||
{
|
||||
|
||||
SuitablePositions.Clear();
|
||||
foreach (GameObject query in AllPositions)
|
||||
{
|
||||
// Check the distance of the position
|
||||
if (Vector2.Distance(query.transform.position, Player.transform.position) < DesiredDistance && Vector2.Distance(query.transform.position, Player.transform.position) >= MinumumDistance)
|
||||
{
|
||||
// Check line of sight of the position
|
||||
if (DetermineLineOfSight(query, Player))
|
||||
{
|
||||
SuitablePositions.Add(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SuitablePositions.Count > 0)
|
||||
{
|
||||
Target = SuitablePositions[UnityEngine.Random.Range(0, SuitablePositions.Count)];
|
||||
|
||||
if (AbilityTeleport == false)
|
||||
{
|
||||
foreach (GameObject pos in SuitablePositions)
|
||||
{
|
||||
//Find the point that is closest to the enemy
|
||||
if (Vector2.Distance(transform.position, pos.transform.position) < Vector2.Distance(transform.position, Target.transform.position))
|
||||
{
|
||||
Target = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EnemyType == "AIR")
|
||||
{
|
||||
//if (DetermineLineOfSight(player, gameObject))
|
||||
//{
|
||||
Target.transform.position = new Vector2((Player.transform.position.x + UnityEngine.Random.Range(-MinumumDistance, MinumumDistance)), (Player.transform.position.y + MinumumDistance + UnityEngine.Random.Range(-5, 0)));
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
// Part of the patrol cycle
|
||||
void MoveNextPatrol() // Determine the next place to move to
|
||||
{
|
||||
if (PatrolLock == false)
|
||||
{
|
||||
PatrolCooldown = PatrolCooldownReset;
|
||||
PositionRecomputeLock = true;
|
||||
LastKnownPlayerLocation = null;
|
||||
DesiredDistance = WeaponRange - 5;
|
||||
|
||||
if (EnemyType == "GROUND")
|
||||
{
|
||||
//Find Random Position nearby
|
||||
if (PatrolPositions.Count > 1)
|
||||
Target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
|
||||
}
|
||||
|
||||
if (EnemyType == "AIR")
|
||||
{
|
||||
//Find Random Position nearby
|
||||
Target.transform.position = new Vector2((StartPosition.x + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)), (StartPosition.y + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Explode
|
||||
void Explode()
|
||||
{
|
||||
// Shake Camera
|
||||
Camera.GetComponent<CameraMovement>().shakeCamera(0.8f, 0.5f);
|
||||
|
||||
// Create Explosion
|
||||
GameObject Explosion;
|
||||
Explosion = Instantiate(GameObject.Find("Explosion"), new Vector3(transform.position.x, transform.position.y, GameObject.Find("Explosion").transform.position.z), Quaternion.identity);
|
||||
Explosion.transform.rotation = Quaternion.Euler(Vector3.forward);
|
||||
|
||||
// Set Variables
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().destroy = true;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().opacity = true;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().timer = 3;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
|
||||
|
||||
// Destroy Flying Target
|
||||
//if (EnemyType == "AIR")
|
||||
//{
|
||||
// Destroy(target);
|
||||
//}
|
||||
|
||||
//gameObject.GetComponent<MasterEnemyAI>().enabled = false;
|
||||
|
||||
// Destroy GameObject
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
void Cloak(bool state)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, HiddenTransparencyAmmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
void Dash()
|
||||
{
|
||||
DashCooldown = DashCooldownReset;
|
||||
// Perform dash
|
||||
if (AbilityPlayerESP)
|
||||
rb.linearVelocity = new Vector2(transform.position.x - Player.transform.position.x, transform.position.y - Player.transform.position.y).normalized * DashSpeed * -1;
|
||||
else
|
||||
rb.linearVelocity = new Vector2(transform.position.x - Target.transform.position.x, transform.position.y - Target.transform.position.y).normalized * DashSpeed * -1;
|
||||
}
|
||||
|
||||
void Teleport()
|
||||
{
|
||||
TeleportCooldown = TeleportCooldownReset;
|
||||
transform.position = Target.transform.position;
|
||||
}
|
||||
|
||||
// On contact
|
||||
void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
if (Primed && AbilityExplodeOnContact)
|
||||
{
|
||||
if (collision.gameObject.layer == LayerMask.NameToLayer("SolidGround") || collision.gameObject.layer == LayerMask.NameToLayer("Enemies") || collision.gameObject.layer == LayerMask.NameToLayer("Player"))
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user