Fixed small visual bugs

This commit is contained in:
weedmjac000
2026-01-21 10:56:26 -07:00
parent fc5efd89bf
commit 649345ec01
814 changed files with 1649 additions and 8 deletions

View File

@@ -0,0 +1,500 @@
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 Jacob Weedman
//Use on Brute type enemies
public class BruteAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canJump = true;
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = false;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 5f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
int NumberOfHitsPerMag = 0;
float angle;
bool canDash = true;
//ENEMY STATS (Changeable)
public float Speed = 0.6f; // In relation to player's walking speed
public float JumpHeight = 0.8f; // In relation to player's regular jump height
public float Health = 250;
public float PatrolDistance = 10;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 25;
public float dashSpeed = 20f; // Strength of the dash
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 20; // Damage per hit
public int WeaponFireRate = 1000; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 6f; // Random direction of lanched projectiles
public int WeaponRange = 30; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles
public int WeaponMagazineSize = 15; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 7000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// 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 (Vector2.Distance(transform.position, target.transform.position) > 0.5 && canDash == true)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform)
{
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//CALL DASH
if (DetermineLineOfSight(gameObject, player) && targetingPlayer && canDash == true && canJump == true)
{
Dash(player);
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
//float xDirection = target.transform.position.x - transform.position.x;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// 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
angle = 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)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// 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 the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Dash
async Task Dash(GameObject endLocation)
{
canDash = false;
// Perform dash
rb.linearVelocity = new Vector2(transform.position.x - player.transform.position.x, transform.position.y - player.transform.position.y).normalized * dashSpeed * -1;
await Task.Delay(5000);
canDash = true;
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
if (NumberOfHitsPerMag / WeaponMagazineSize < 0.5)
{
DesiredDistance -= 5;
}
NumberOfHitsPerMag = 0;
canFire = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
DesiredDistance = WeaponRange - 5;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// 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;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
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)];
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;
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9776525c92b362242a58f959cbe6b91e

View File

@@ -0,0 +1 @@
uid://d4eldf5x4kddm

View File

@@ -0,0 +1,328 @@
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 Jacob Weedman
//Use on Cloaker type enemies
public class CloakerAI : MonoBehaviour
{
//MISC
GameObject target;
public float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canJump = true;
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = false;
bool currentlyReloading = false;
bool targetingPlayer = false;
bool inFiringCycle = false;
bool canDash = true;
//ENEMY STATS (Changeable)
public float Speed = 0.7f; // In relation to player's walking speed
public float JumpHeight = 1.4f; // In relation to player's regular jump height
public float Health = 15;
public int PlayerDetectionRange = 25;
public float HiddenTransparencyAmmount = 0.05f;
public float dashSpeed = 40f; // Strength of the dash
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 40; // Damage per hit
public int WeaponFireRate = 1500; // Delay in time between attacks both melee and ranged
public float WeaponMeleeRange = 0.75f;
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
LastKnownPlayerLocation = null;
target = gameObject;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// 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 (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
LastKnownPlayerLocation = null;
targetingPlayer = false;
target = gameObject;
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer && gameObject.GetComponent<SpriteRenderer>().color.a == 1)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 0f, 0f, HiddenTransparencyAmmount);
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (canFire == true && currentlyReloading == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(player.transform.position, transform.position) <= WeaponMeleeRange)
{
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 0f, 0f, 1f);
UseWeapon();
}
}
//CALL DASH
if (DetermineLineOfSight(gameObject, player) && targetingPlayer && canDash == true)
{
Dash();
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
targetingPlayer = true;
canPursue = true;
target = player;
// 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;
}
}
}
// 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)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
}
//TARGET DETERMINATION
if (canPursue == true)
{
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Dash
async Task Dash()
{
canDash = false;
// Perform dash
rb.linearVelocity = new Vector2(transform.position.x - player.transform.position.x, transform.position.y - player.transform.position.y).normalized * dashSpeed * -1;
await Task.Delay(1000); // Dash delay ms
canDash = true;
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
inFiringCycle = true;
// melee attack
//Damage
GameObject.Find("GameData").GetComponent<GameData>().CurrentHealth -= WeaponDamage;
await Task.Delay(WeaponFireRate);
canFire = true;
inFiringCycle = false;
}
// 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;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a49219e9fdacd2640a56d6100c2983c9

View File

@@ -0,0 +1 @@
uid://b56cltkpns8eg

View File

@@ -0,0 +1,465 @@
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 Jacob Weedman
//V 0.0.3
//DO NOT USE THIS ON ANY ENEMIES
public class CustomEnemyAI : MonoBehaviour
{
//MISC
public GameObject target;
public float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
public float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
public bool canJump = true;
public bool canMove = true;
public bool canPursue = true;
public bool canFire = false;
public bool currentlyReloading = false;
public bool currentlyPatrolling;
public bool currentlyMovingToNextPatrolTarget = false;
public float DesiredDistance;
public float MinumumDistance = 5f;
public bool targetingPlayer = false;
//ENEMY STATS (Changeable)
public float Speed = 1; // In relation to player's walking speed
public float JumpHeight = 1; // In relation to player's regular jump height
public float Health = 100;
public float PatrolDistance = 10;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 30;
//WEAPON STATS (CHANGEABLE)
public string WeaponType = "RANGED"; // RANGED, MELEE, PHYSICS
public int WeaponDamage = 15; // Damage per hit
public int WeaponFireRate = 250; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles (DOES NOT APPLY TO MELEE ATTACKS)
public int WeaponRange = 40; // Maximum range of the projectile before it drops off (DOES NOT APPLY TO MELEE ATTACKS)
int WeaponMeleeRange = 5; // Minimum distance the enemy has to be away from the player in order to be able to hit the player (DOES NOT APPLY TO RANGED ATTACKS)
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles (DOES NOT APPLY TO MELEE WEAPONS)
public int WeaponMagazineSize = 20; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
public int WeaponCurrentMagazineAmmount; // Current number of ammo in the mag (DO NOT CHANGE THIS)
Seeker seeker;
Rigidbody2D rb;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("TestBullet");
player = GameObject.FindGameObjectWithTag("Player");
LastKnownPlayerLocation = gameObject;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange;
InvokeRepeating("UpdatePath", 0f, 0.1f);
}
// 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);
}
}
//Main logic
void FixedUpdate()
{
if (Health <= 0)
{
Destroy(transform);
}
// 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;
}
// Change Icons
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
float xDirection = path.vectorPath[currentWaypoint].x - rb.position.x;
if (xDirection > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (xDirection < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true)
{
canJump = true;
}
else
{
canJump = false;
}
//PATROL
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
//target = null;
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(player.transform.position, pos.transform.position) < Vector2.Distance(player.transform.position, LastKnownPlayerLocation.transform.position))
{
LastKnownPlayerLocation = pos;
}
}
}
else if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
{
canPursue = false;
if (targetingPlayer == false)
{
target = LastKnownPlayerLocation;
}
}
else
{
//target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
LastKnownPlayerLocation = gameObject;
currentlyPatrolling = true;
currentlyPatrolling = true;
targetingPlayer = false;
}
if (currentlyPatrolling)
{
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
}
else
{
//RANGED ATTACK
if (WeaponType == "RANGED")
{
// Check if enemy has line of sight on the player
// Does the ray intersect any ground objects
//if (Physics2D.Raycast(EnemyRaycastStart, EnemyRaycastDirection, EnemyRaycastDistance, LayerMask.GetMask("Default")))
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, GameObject.FindGameObjectWithTag("Player").transform.position) <= WeaponRange)
{// Line of sight
// Check to see if the enemy is within range of the player to begin shooting
//if (Vector2.Distance(rb.position, GameObject.FindGameObjectWithTag("Player").transform.position) <= WeaponRange)
//{
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false)
{
UseWeapon();
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
}
else
{
canMove = true;
}
}
}
if (canPursue == true)
{
//TARGET DETERMINATION
// If the player moves away (CHANGE TARGET)
ComputeClosestPositionToPlayer();
if (Vector2.Distance(target.transform.position, player.transform.position) > WeaponRange - 2)
{
ComputeClosestPositionToPlayer();
canFire = false;
canMove = true;
}
//If the player is too close to the target (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) < MinumumDistance)
{
ComputeClosestPositionToPlayer();
canFire = false;
canMove = true;
}
//If the target is on the other side of the player
if (Vector2.Distance(transform.position, player.transform.position) < Vector2.Distance(target.transform.position, player.transform.position))
{
ComputeClosestPositionToPlayer();
canFire = false;
canMove = true;
}
// If the player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
canFire = false;
canMove = true;
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) < 0.5)
{
if (DetermineLineOfSight(gameObject, player)) // If the enemy has LOS on the player
{
if (currentlyReloading == false)
{
canFire = true;
}
}
else
{
ComputeClosestPositionToPlayer();
canFire = false;
canMove = true;
}
}
// If the enemy has not yet reached the target
else
{
}
}
}
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
canMove = false;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// Generate random angle
//Vector2 ExitVelocity = BulletInstance.transform.forward * new Vector2(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread)).normalized;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
canMove = true;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
canMove = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
canMove = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime);
}
canPursue = true;
currentlyMovingToNextPatrolTarget = false;
}
// 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("Default")) == false)
{
Debug.DrawRay(RaycastStart, RaycastDirection * RaycastDistance);
return true;
}
else
{
return false;
}
}
// Partof the pursue cycle
void ComputeClosestPositionToPlayer()
{
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)];
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))
{
if (Vector2.Distance(player.transform.position, pos.transform.position) < Vector2.Distance(player.transform.position, target.transform.position))
{
target = pos;
}
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e1f4adc563b83f549b3b3fc9eeb38e9a

View File

@@ -0,0 +1 @@
uid://bmvsmx2cghvjx

View File

@@ -0,0 +1,190 @@
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 Jacob Weedman
//Use on Flamethrower turrets
public class FlameTurretAI : MonoBehaviour
{
//MISC
GameObject projectile;
GameObject player;
GameObject barrel;
float DistanceFromPlayer;
Vector2 StartPosition;
//CONDITIONS/GENERAL INFORMATION
bool canFire = true;
bool currentlyReloading = false;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
float angle;
//ENEMY STATS (Changeable)
public float Health = 100;
public int PlayerDetectionRange = 40;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 1; // Damage per hit
public int WeaponFireRate = 50; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 2.5f; // Random direction of lanched projectiles
public int WeaponRange = 20; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 20f; // Speed of launched projectiles
public int WeaponMagazineSize = 80; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 10000; // Time it takes to reload the magazine
//ONCE THE GAME STARTS
void Start()
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
canFire = true;
}
//MAIN LOGIC
void FixedUpdate()
{
DistanceFromPlayer = Vector2.Distance(transform.position, player.transform.position);
// Death
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//PLAYER TARGETING
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange + 10)
{
targetingPlayer = true;
// Set angle to player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
else
{
// Reset barrel rotation
angle = 90f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
}
//MISC METHODS
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
inFiringCycle = true;
GameObject Flame;
Flame = Instantiate(GameObject.Find("Flame"), new Vector3(transform.position.x + UnityEngine.Random.Range(-0.5f, 0.5f), transform.position.y + UnityEngine.Random.Range(-0.5f, 0.5f), GameObject.Find("EvilAura").transform.position.z), Quaternion.identity);
Flame.transform.rotation = Quaternion.Euler(Vector3.forward * UnityEngine.Random.Range(-90, 90));
// Send it on its way
Flame.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 * 3 * WeaponRange * -1;
//Set Variables
Flame.GetComponent<EnemyParticleWeapon>().destroy = true;
Flame.GetComponent<EnemyParticleWeapon>().opacity = true;
Flame.GetComponent<EnemyParticleWeapon>().timer = 3;
Flame.GetComponent<EnemyParticleWeapon>().destroyOnCollide= true;
Flame.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
await Task.Delay(WeaponFireRate);
canFire = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
}
// 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;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1b9c0ca6eef46ec49b42f46141997c46

View File

@@ -0,0 +1 @@
uid://cw5sup7xiuq2s

View File

@@ -0,0 +1,473 @@
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 Jacob Weedman
//Use on Flamethrower type enemies
public class FlamethrowerAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canJump = true;
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = false;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 5f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
float angle;
//ENEMY STATS (Changeable)
public float Speed = 1.3f; // In relation to player's walking speed
public float JumpHeight = 1.3f; // In relation to player's regular jump height
public float Health = 30;
public float PatrolDistance = 15;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 20;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 1; // Damage per hit
public int WeaponFireRate = 50; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 3f; // Random direction of lanched projectiles
public int WeaponRange = 15; // Maximum range of the projectile before it drops off
public int WeaponMagazineSize = 200; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// 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 (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// 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
angle = 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)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 200 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// 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 the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
inFiringCycle = true;
GameObject Flame;
Flame = Instantiate(GameObject.Find("Flame"), new Vector3(transform.position.x + UnityEngine.Random.Range(-0.5f, 0.5f), transform.position.y + UnityEngine.Random.Range(-0.5f, 0.5f), GameObject.Find("EvilAura").transform.position.z), Quaternion.identity);
Flame.transform.rotation = Quaternion.Euler(Vector3.forward * UnityEngine.Random.Range(-90, 90));
// Send it on its way
Flame.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
Flame.GetComponent<EnemyParticleWeapon>().destroy = true;
Flame.GetComponent<EnemyParticleWeapon>().opacity = true;
Flame.GetComponent<EnemyParticleWeapon>().destroyOnCollide= true;
Flame.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
await Task.Delay(WeaponFireRate);
canFire = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
canMove = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
canMove = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
DesiredDistance = WeaponRange - 5;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// 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;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
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)];
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;
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9a8b83d0c517ff040ac4a88b082b85ec

View File

@@ -0,0 +1 @@
uid://dfgtcghp4yxk4

View File

@@ -0,0 +1,480 @@
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 Jacob Weedman
//Use on Grunt type enemies
public class GruntAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canJump = true;
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = false;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 5f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
public int NumberOfHitsPerMag = 0;
float angle;
//ENEMY STATS (Changeable)
public float Speed = 1.3f; // In relation to player's walking speed
public float JumpHeight = 1.3f; // In relation to player's regular jump height
public float Health = 30;
public float PatrolDistance = 15;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 20;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 1; // Damage per hit
public int WeaponFireRate = 100; // Delay in time between attacks both melee and ranged
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 reload
public int WeaponReloadTime = 3000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// 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 (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// 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
angle = 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)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 200 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// 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 the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
canMove = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
canMove = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
canMove = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
if (NumberOfHitsPerMag / WeaponMagazineSize < 0.5)
{
DesiredDistance -= 5;
}
NumberOfHitsPerMag = 0;
canFire = true;
canMove = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
DesiredDistance = WeaponRange - 5;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// 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;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
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)];
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;
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 81f1c8e2d50cae34da2edf9525005d91

View File

@@ -0,0 +1 @@
uid://cf3cm245clgqf

View File

@@ -0,0 +1,468 @@
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 Jacob Weedman
//Use on heavy drone type enemies
public class HeavyDroneAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
GameObject LastKnownPlayerLocation;
Transform DroneBayLocation;
//CONDITIONS/GENERAL INFORMATION
bool canMove = false;
bool canPursue = false;
bool canFire = true;
bool currentlyReloading = false;
bool currentlyInDroneBay = true;
float DesiredDistance;
float MinumumDistance = 10f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
int CurrentBatteryCapacity;
bool currentlyTravelingToDroneBay = false;
bool currentlyRecharging = false;
float angle;
//ENEMY STATS (Changeable)
public float Speed = 0.7f; // In relation to player's walking speed
public float Health = 200;
public int PlayerDetectionRange = 25;
public int MaxBatteryCapacity = 30; // Depletes one every second it is out of the bay
public int RechargeTime = 6000; //ms
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 20; // Damage per hit
public int WeaponFireRate = 2000; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles (DOES NOT APPLY TO MELEE ATTACKS)
public int WeaponRange = 30; // Maximum range of the projectile before it drops off (DOES NOT APPLY TO MELEE ATTACKS)
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles (DOES NOT APPLY TO MELEE WEAPONS)
public int WeaponMagazineSize = 12; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
Seeker seeker;
Rigidbody2D rb;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("BatteryIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
target = Instantiate(GameObject.Find("FlyingTarget"), transform.position, Quaternion.identity);
projectile = GameObject.Find("EnemyGrenade");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
DroneBayLocation = transform.parent.transform;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
CurrentBatteryCapacity = MaxBatteryCapacity;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 30);
InvokeRepeating("BatteryDrain", 0f, 1);
Recharge();
}
// 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())
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
//target = gameObject;
targetingPlayer = false;
LastKnownPlayerLocation = null;
//ReturnToDroneBay();
}
}
// Battery Drain
void BatteryDrain()
{
if (currentlyInDroneBay == false)
{
CurrentBatteryCapacity -= 1;
}
}
// MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (CurrentBatteryCapacity == 0)
{
Health = 0;
}
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
DeadBody.GetComponent<Rigidbody2D>().gravityScale = 3;
Destroy(GameObject.Find(DeadBody.name).GetComponent<LightDroneAI>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform)
{
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//Battery
// Low battery return
if (CurrentBatteryCapacity <= 10)
{
ReturnToDroneBay();
}
// Recharge battery & bay detection
if (Vector2.Distance(transform.position, DroneBayLocation.position) <= 0.5)
{
currentlyInDroneBay = true;
currentlyTravelingToDroneBay = false;
if (currentlyRecharging == false && CurrentBatteryCapacity < 10)
{
Recharge();
}
else
{
canMove = false;
}
}
else
{
//canMove = true;
currentlyInDroneBay = false;
}
//CHANGE ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (CurrentBatteryCapacity <= MaxBatteryCapacity / 10)
{
transform.Find("BatteryIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("BatteryIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyInDroneBay == false)
{
seeker.enabled = true;
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyInDroneBay == false)
{
if (DetermineLineOfSight(gameObject, player) == true && inFiringCycle == false && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
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++;
}
}
//DETECTION
// Enemy detects player
if (DetermineLineOfSight(transform.parent.gameObject, player) && Vector2.Distance(DroneBayLocation.position, player.transform.position) <= PlayerDetectionRange && currentlyRecharging == false)
{
if (currentlyInDroneBay == true)
{
rb.linearVelocity = transform.parent.transform.up * 10;
}
canMove = true;
targetingPlayer = true;
canPursue = true;
// Angle barrel towards player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
else if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
targetingPlayer = true;
canPursue = true;
// 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;
}
}
// Reset barrel rotation
angle = -90f;
}
// 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)
{
canPursue = false;
target.transform.position = LastKnownPlayerLocation.transform.position;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = -90f;
}
// Go back to drone bay
else
{
LastKnownPlayerLocation = null;
ReturnToDroneBay();
targetingPlayer = false;
// Reset barrel rotation
angle = -90f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
if (currentlyTravelingToDroneBay == false)
{
//TARGET DETERMINATION
// If enemy is at the target position
if (Vector2.Distance(target.transform.position, transform.position) < 1.5)
{
ComputeClosestPositionToPlayer();
}
// 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 player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1)
{
if (DetermineLineOfSight(gameObject, player) == false) // If the enemy has LOS on the player
{
ComputeClosestPositionToPlayer();
}
}
}
}
//MISC METHODS
// Use Ranged Weapon
async Task UseWeapon()
{
inFiringCycle = true;
// Create Grenade
GameObject GrenadeInstance;
GrenadeInstance = Instantiate(projectile, 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)));
GrenadeInstance.GetComponent<EnemyGrenade>().WeaponDamage = WeaponDamage;
// Send it on it's way
GrenadeInstance.GetComponent<Rigidbody2D>().linearVelocity = GrenadeInstance.transform.forward * -1 * WeaponProjectileSpeed;
GrenadeInstance.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, GrenadeInstance.transform.forward) - 90));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
}
// Return To Drone Bay
async Task ReturnToDroneBay()
{
if (currentlyTravelingToDroneBay == false && currentlyInDroneBay == false)
{
currentlyTravelingToDroneBay = true;
target.transform.position = DroneBayLocation.position;
}
}
// Recharge
async Task Recharge()
{
currentlyRecharging = true;
canMove = false;
canFire = false;
seeker.enabled = false;
transform.position = DroneBayLocation.position;
rb.linearVelocity = Vector3.zero;
currentlyTravelingToDroneBay = false;
await Task.Delay(RechargeTime);
CurrentBatteryCapacity = MaxBatteryCapacity;
currentlyRecharging = false;
canFire = true;
}
// 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;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
// find a target in the air a set radius away from the player
if (DetermineLineOfSight(player, gameObject))
{
canMove = true;
target.transform.position = new Vector2((player.transform.position.x + UnityEngine.Random.Range(-MinumumDistance, MinumumDistance)), (player.transform.position.y + MinumumDistance + UnityEngine.Random.Range(-5, 0)));
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7a21aeddab50704439aa410e19bcee64

View File

@@ -0,0 +1 @@
uid://btkxwdxwwqhh3

View File

@@ -0,0 +1,468 @@
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 Jacob Weedman
//DO NOT USE ON ANY ENEMIES
public class LightDroneAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
GameObject LastKnownPlayerLocation;
Transform DroneBayLocation;
//CONDITIONS/GENERAL INFORMATION
bool canMove = false;
bool canPursue = false;
bool canFire = true;
bool currentlyReloading = false;
bool currentlyInDroneBay = true;
float DesiredDistance;
float MinumumDistance = 10f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
int CurrentBatteryCapacity;
bool currentlyTravelingToDroneBay = false;
bool currentlyRecharging = false;
float angle;
//ENEMY STATS (Changeable)
public float Speed = 0.7f; // In relation to player's walking speed
public float Health = 100;
public int PlayerDetectionRange = 25;
public int MaxBatteryCapacity = 30; // Depletes one every second it is out of the bay
public int RechargeTime = 6000; //ms
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 5; // Damage per hit
public int WeaponFireRate = 100; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles (DOES NOT APPLY TO MELEE ATTACKS)
public int WeaponRange = 30; // Maximum range of the projectile before it drops off (DOES NOT APPLY TO MELEE ATTACKS)
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles (DOES NOT APPLY TO MELEE WEAPONS)
public int WeaponMagazineSize = 50; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
Seeker seeker;
Rigidbody2D rb;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("BatteryIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
target = Instantiate(GameObject.Find("FlyingTarget"), transform.position, Quaternion.identity);
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
DroneBayLocation = transform.parent.transform;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
CurrentBatteryCapacity = MaxBatteryCapacity;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 30);
InvokeRepeating("BatteryDrain", 0f, 1);
Recharge();
}
// 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())
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
//target = gameObject;
targetingPlayer = false;
LastKnownPlayerLocation = null;
//ReturnToDroneBay();
}
}
// Battery Drain
void BatteryDrain()
{
if (currentlyInDroneBay == false)
{
CurrentBatteryCapacity -= 1;
}
}
// MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (CurrentBatteryCapacity == 0)
{
Health = 0;
}
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
DeadBody.GetComponent<Rigidbody2D>().gravityScale = 3;
Destroy(GameObject.Find(DeadBody.name).GetComponent<LightDroneAI>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform)
{
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//Battery
// Low battery return
if (CurrentBatteryCapacity <= 10)
{
ReturnToDroneBay();
}
// Recharge battery & bay detection
if (Vector2.Distance(transform.position, DroneBayLocation.position) <= 0.5)
{
currentlyInDroneBay = true;
currentlyTravelingToDroneBay = false;
if (currentlyRecharging == false && CurrentBatteryCapacity < 10)
{
Recharge();
}
else
{
canMove = false;
}
}
else
{
//canMove = true;
currentlyInDroneBay = false;
}
//CHANGE ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (CurrentBatteryCapacity <= MaxBatteryCapacity / 10)
{
transform.Find("BatteryIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("BatteryIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyInDroneBay == false)
{
seeker.enabled = true;
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyInDroneBay == false)
{
if (DetermineLineOfSight(gameObject, player) == true && inFiringCycle == false && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
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++;
}
}
//DETECTION
// Enemy detects player
if (DetermineLineOfSight(transform.parent.gameObject, player) && Vector2.Distance(DroneBayLocation.position, player.transform.position) <= PlayerDetectionRange && currentlyRecharging == false)
{
if (currentlyInDroneBay == true)
{
rb.linearVelocity = transform.parent.transform.up * 10;
}
canMove = true;
targetingPlayer = true;
canPursue = true;
// Angle barrel towards player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
else if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
targetingPlayer = true;
canPursue = true;
// 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;
}
}
// Reset barrel rotation
angle = -90f;
}
// 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)
{
canPursue = false;
target.transform.position = LastKnownPlayerLocation.transform.position;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = -90f;
}
// Go back to drone bay
else
{
LastKnownPlayerLocation = null;
ReturnToDroneBay();
targetingPlayer = false;
// Reset barrel rotation
angle = -90f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
if (currentlyTravelingToDroneBay == false)
{
//TARGET DETERMINATION
// If enemy is at the target position
if (Vector2.Distance(target.transform.position, transform.position) < 1.5)
{
ComputeClosestPositionToPlayer();
}
// 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 player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1)
{
if (DetermineLineOfSight(gameObject, player) == false) // If the enemy has LOS on the player
{
ComputeClosestPositionToPlayer();
}
}
}
}
//MISC METHODS
// Use Ranged Weapon
async Task UseWeapon() // Weapon for projectile based enemy
{
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
}
// Return To Drone Bay
async Task ReturnToDroneBay()
{
if (currentlyTravelingToDroneBay == false && currentlyInDroneBay == false)
{
currentlyTravelingToDroneBay = true;
target.transform.position = DroneBayLocation.position;
}
}
// Recharge
async Task Recharge()
{
currentlyRecharging = true;
canMove = false;
canFire = false;
seeker.enabled = false;
transform.position = DroneBayLocation.position;
rb.linearVelocity = Vector3.zero;
currentlyTravelingToDroneBay = false;
await Task.Delay(RechargeTime);
CurrentBatteryCapacity = MaxBatteryCapacity;
currentlyRecharging = false;
canFire = true;
}
// 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;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
// find a target in the air a set radius away from the player
if (DetermineLineOfSight(player, gameObject))
{
canMove = true;
target.transform.position = new Vector2((player.transform.position.x + UnityEngine.Random.Range(-MinumumDistance, MinumumDistance)), (player.transform.position.y + MinumumDistance + UnityEngine.Random.Range(-5, 0)));
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 908158ab2214cc04ea3af93728a2c94d

View File

@@ -0,0 +1 @@
uid://dbhj5fkwajasw

View File

@@ -0,0 +1,186 @@
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 Jacob Weedman
//Use on machine gun turrets
public class MachineGunTurretAI : MonoBehaviour
{
//MISC
GameObject projectile;
GameObject player;
GameObject barrel;
float DistanceFromPlayer;
Vector2 StartPosition;
//CONDITIONS/GENERAL INFORMATION
bool canFire = true;
bool currentlyReloading = false;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
float angle;
//ENEMY STATS (Changeable)
public float Health = 100;
public int PlayerDetectionRange = 25;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 15; // Damage per hit
public int WeaponFireRate = 150; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 6.5f; // Random direction of lanched projectiles
public int WeaponRange = 20; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 40f; // Speed of launched projectiles
public int WeaponMagazineSize = 50; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 10000; // Time it takes to reload the magazine
//ONCE THE GAME STARTS
void Start()
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
canFire = true;
}
//MAIN LOGIC
void FixedUpdate()
{
DistanceFromPlayer = Vector2.Distance(transform.position, player.transform.position);
// Death
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//PLAYER TARGETING
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange + 10)
{
targetingPlayer = true;
// Set angle to player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
else
{
// Reset barrel rotation
angle = 90f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
}
//MISC METHODS
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
}
// 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;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6eaccebea63257f4685a23d638a4ca16

View File

@@ -0,0 +1 @@
uid://djux2mx2lqlfc

View File

@@ -0,0 +1,385 @@
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 Jacob Weedman
//Use on regular flying ranged enemies
public class RegularFlyingAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canMove = true;
bool canPursue = false;
bool canFire = true;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 10f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
//ENEMY STATS (Changeable)
public float Speed = 0.7f; // In relation to player's walking speed
public float Health = 100;
public float PatrolDistance = 10;
public int PatrolStallTime = 1500; //ms
public int PlayerDetectionRange = 25;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 5; // Damage per hit
public int WeaponFireRate = 100; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles (DOES NOT APPLY TO MELEE ATTACKS)
public int WeaponRange = 30; // Maximum range of the projectile before it drops off (DOES NOT APPLY TO MELEE ATTACKS)
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles (DOES NOT APPLY TO MELEE WEAPONS)
public int WeaponMagazineSize = 50; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
Seeker seeker;
Rigidbody2D rb;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
target = Instantiate(GameObject.Find("FlyingTarget"), transform.position, Quaternion.identity);
projectile = GameObject.Find("Projectile");
player = GameObject.FindGameObjectWithTag("Player");
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 30);
}
// 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())
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
//target = gameObject;
targetingPlayer = false;
LastKnownPlayerLocation = null;
MoveNextPatrol();
}
}
//Main logic
void FixedUpdate()
{
// Death
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
DeadBody.GetComponent<Rigidbody2D>().gravityScale = 3;
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIAirRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform)
{
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
// 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;
}
*/
// Change Icons
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && inFiringCycle == false && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
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++;
}
}
//PATROL
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
//target = null;
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// 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;
}
}
}
// 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)
{
canPursue = false;
target.transform.position = LastKnownPlayerLocation.transform.position;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
}
// Go back to patrol move
else
{
//target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
LastKnownPlayerLocation = gameObject;
currentlyPatrolling = true;
targetingPlayer = false;
}
// Call patrol method
if (currentlyPatrolling)
{
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
}
if (canPursue == true)
{
//TARGET DETERMINATION
// If the player moves away (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) > DesiredDistance)
{
ComputeClosestPositionToPlayer();
canMove = true;
}
//If the player is too close to the target (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) < MinumumDistance)
{
ComputeClosestPositionToPlayer();
canMove = true;
}
// If the player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
canMove = true;
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1)
{
if (DetermineLineOfSight(gameObject, player) == false) // If the enemy has LOS on the player
{
ComputeClosestPositionToPlayer();
canMove = true;
}
}
}
}
// Use Ranged Weapon
async Task UseWeapon() // Weapon for projectile based enemy
{
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = gameObject;
target.transform.position = transform.position;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//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)));
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
currentlyMovingToNextPatrolTarget = false;
}
// 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;
}
}
// Partof the pursue cycle
void ComputeClosestPositionToPlayer()
{
// find a target in the air a set radius away from the player
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)));
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: bfee0f4605660014d909f908d7917b8e

View File

@@ -0,0 +1 @@
uid://bdce6nq0qj46b

View File

@@ -0,0 +1,154 @@
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 Jacob Weedman
//Use on rocket turrets
public class RocketTurretAI : MonoBehaviour
{
//MISC
GameObject projectile;
GameObject player;
GameObject barrel;
float DistanceFromPlayer;
Vector2 StartPosition;
//CONDITIONS/GENERAL INFORMATION
bool canFire = true;
bool targetingPlayer = false;
bool inFiringCycle = false;
float angle;
//ENEMY STATS (Changeable)
public float Health = 100;
public int PlayerDetectionRange = 50;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 30; // Damage per hit
public int WeaponFireRate = 2500; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 0.5f; // Random direction of lanched projectiles
public int WeaponRange = 40; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 50f; // Speed of launched projectiles
//ONCE THE GAME STARTS
void Start()
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
projectile = GameObject.Find("EnemyRocketWeapon");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
canFire = true;
}
//MAIN LOGIC
void FixedUpdate()
{
DistanceFromPlayer = Vector2.Distance(transform.position, player.transform.position);
// Death
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (canFire == true)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange)
{
UseWeapon();
}
}
//PLAYER TARGETING
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange + 10)
{
targetingPlayer = true;
// Set angle to player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
else
{
// Reset barrel rotation
angle = 90f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
}
//MISC METHODS
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
inFiringCycle = true;
GameObject Rocket;
Rocket = Instantiate(GameObject.Find("EnemyRocket"), new Vector3(transform.position.x + UnityEngine.Random.Range(-0.5f, 0.5f), transform.position.y + UnityEngine.Random.Range(-0.5f, 0.5f), GameObject.Find("EvilAura").transform.position.z), Quaternion.identity);
Rocket.transform.rotation = Quaternion.Euler(Vector3.forward * UnityEngine.Random.Range(-90, 90));
// Send it on its way
Rocket.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 * WeaponProjectileSpeed * -1;
Rocket.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, Rocket.transform.forward) - 90));
// Variables
Rocket.GetComponent<EnemyRocket>().WeaponDamage = WeaponDamage;
await Task.Delay(WeaponFireRate);
canFire = true;
inFiringCycle = false;
}
// 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;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fff6f5b1fd22d4a41afda949998e4dd0

View File

@@ -0,0 +1 @@
uid://b5dao1ktmi05l

View File

@@ -0,0 +1,469 @@
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 Jacob Weedman
//Use on Rocketman type enemies
public class RocketmanAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canJump = true;
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = false;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 5f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
float angle;
//ENEMY STATS (Changeable)
public float Speed = 0.8f; // In relation to player's walking speed
public float JumpHeight = 0.8f; // In relation to player's regular jump height
public float Health = 30;
public float PatrolDistance = 15;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 40;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 30; // Damage per hit
public int WeaponFireRate = 2500; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 1.5f; // Random direction of lanched projectiles
public int WeaponRange = 30; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 40f; // Speed of launched projectiles
public int WeaponMagazineSize = 1; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// 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 (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// 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
angle = 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)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 200 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// 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 the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
canMove = false;
inFiringCycle = true;
WeaponCurrentMagazineAmmount--;
GameObject Rocket;
Rocket = Instantiate(GameObject.Find("EnemyRocket"), new Vector3(transform.position.x + UnityEngine.Random.Range(-0.5f, 0.5f), transform.position.y + UnityEngine.Random.Range(-0.5f, 0.5f), GameObject.Find("EnemyRocket").transform.position.z), Quaternion.identity);
Rocket.transform.rotation = Quaternion.Euler(Vector3.forward * UnityEngine.Random.Range(-90, 90));
// Send it on its way
Rocket.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 * WeaponProjectileSpeed * -1;
Rocket.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, Rocket.transform.forward) - 90));
// Variables
Rocket.GetComponent<EnemyRocket>().WeaponDamage = WeaponDamage;
await Task.Delay(WeaponFireRate);
canFire = true;
canMove = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
canMove = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
canMove = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// 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;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
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)];
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;
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: cade0ad7c945f4047a65286465645db6

View File

@@ -0,0 +1 @@
uid://chiq1pru4dj02

View File

@@ -0,0 +1,468 @@
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 Jacob Weedman
//Use on Sniper type enemies
public class SniperAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canJump = true;
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = false;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 10f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
float angle;
//ENEMY STATS (Changeable)
public float Speed = 0.4f; // In relation to player's walking speed
public float JumpHeight = 0.9f; // In relation to player's regular jump height
public float Health = 50;
public float PatrolDistance = 3;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 50;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 25; // Damage per hit
public int WeaponFireRate = 1000; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 0.5f; // Random direction of lanched projectiles
public int WeaponRange = 45; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 100f; // Speed of launched projectiles
public int WeaponMagazineSize = 5; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 6000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// 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 (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
//float xDirection = target.transform.position.x - transform.position.x;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// 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
angle = 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)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// 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 the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
canMove = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
canMove = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
canMove = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
canMove = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// 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;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
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)];
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;
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 198b98dba749aa845975d64154c7837a

View File

@@ -0,0 +1 @@
uid://wbr8l875pltc

View File

@@ -0,0 +1,186 @@
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 Jacob Weedman
//Use on sniper turrets
public class SniperTurretAI : MonoBehaviour
{
//MISC
GameObject projectile;
GameObject player;
GameObject barrel;
float DistanceFromPlayer;
Vector2 StartPosition;
//CONDITIONS/GENERAL INFORMATION
bool canFire = true;
bool currentlyReloading = false;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
float angle;
//ENEMY STATS (Changeable)
public float Health = 100;
public int PlayerDetectionRange = 60;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 30; // Damage per hit
public int WeaponFireRate = 2500; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 1.5f; // Random direction of lanched projectiles
public int WeaponRange = 50; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 80f; // Speed of launched projectiles
public int WeaponMagazineSize = 20; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 10000; // Time it takes to reload the magazine
//ONCE THE GAME STARTS
void Start()
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
canFire = true;
}
//MAIN LOGIC
void FixedUpdate()
{
DistanceFromPlayer = Vector2.Distance(transform.position, player.transform.position);
// Death
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//PLAYER TARGETING
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange + 10)
{
targetingPlayer = true;
// Set angle to player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
else
{
// Reset barrel rotation
angle = 90f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
}
//MISC METHODS
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
}
// 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;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4029e0cfa8f769c4ca76d5b3da3ea1c9

View File

@@ -0,0 +1 @@
uid://ememlrxy8md8

View File

@@ -0,0 +1,367 @@
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 Jacob Weedman
//Use on switchblade drone enemies
public class SwitchbladeAI : MonoBehaviour
{
//MISC
public GameObject target;
public float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> AllPositions;
public float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
public bool canMove = true;
public bool canPursue = false;
public bool canFire = true;
public bool currentlyReloading = false;
public bool currentlyPatrolling;
public bool currentlyMovingToNextPatrolTarget = false;
public float DesiredDistance = 15;
int MinumumDistance = 10;
public bool targetingPlayer = false;
public bool inFiringCycle = false;
public bool primed = false;
//ENEMY STATS (Changeable)
float Speed = 0.7f; // In relation to player's walking speed
float Health = 5;
float PatrolDistance = 10;
int PatrolStallTime = 1500; //ms
int PlayerDetectionRange = 25;
int WeaponFireRate = 1000;
int WeaponRange = 30;
int WeaponDamage = 20;
float dashSpeed = 40f;
Seeker seeker;
Rigidbody2D rb;
//START OF THE GAME
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
target = Instantiate(GameObject.Find("FlyingTarget"), transform.position, Quaternion.identity);
player = GameObject.FindGameObjectWithTag("Player");
LastKnownPlayerLocation = null;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 30);
}
// 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())
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
//target = gameObject;
targetingPlayer = false;
LastKnownPlayerLocation = null;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
// Death
if (Health <= 0)
{
Explode();
}
// Explode when close to the player
if (primed && Vector2.Distance(player.transform.position, transform.position) <= 2)
{
Explode();
}
// 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;
}
//CHANGE ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//DIVE BOMB
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && inFiringCycle == false && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange)
{
UseWeapon();
}
}
//MOVEMENT
if (canMove == true)
{
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++;
}
}
//PATROL
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
primed = true;
// 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;
}
}
}
// Player has broken line of sight and the enemy will attempt to move to the last known location
else if (LastKnownPlayerLocation != null)
{
primed = false;
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
{
canPursue = false;
target.transform.position = LastKnownPlayerLocation.transform.position;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
}
// Go back to patrol move
else
{
LastKnownPlayerLocation = gameObject;
currentlyPatrolling = true;
targetingPlayer = false;
}
// Call patrol method
if (currentlyPatrolling)
{
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
}
//TARGET DETERMINATION
if (canPursue == true)
{
/*
// 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 player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1)
{
if (DetermineLineOfSight(gameObject, player) == false) // If the enemy has LOS on the player
{
ComputeClosestPositionToPlayer();
}
}
}
}
//MISC METHODS
// Attempt to explode on the player
async Task UseWeapon()
{
inFiringCycle = true;
await Task.Delay(3000); // Dash delay ms
//Dash into player
rb.linearVelocity = new Vector2(transform.position.x - player.transform.position.x, transform.position.y - player.transform.position.y).normalized * dashSpeed * -2f;
inFiringCycle = false;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = gameObject;
target.transform.position = transform.position;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//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)));
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
currentlyMovingToNextPatrolTarget = false;
}
// 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;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canMove = true;
// find a target in the air a set radius away from the player
if (DetermineLineOfSight(player, gameObject))
{
target.transform.position = new Vector2(player.transform.position.x + UnityEngine.Random.Range(-MinumumDistance, MinumumDistance), player.transform.position.y + MinumumDistance);
}
}
// Explode
void Explode()
{
//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;
//Delete Enemy
Destroy(gameObject);
}
void OnTriggerEnter2D(Collider2D collision)
{
if (primed)
{
if (collision.gameObject.tag == "Ground")
{
if (collision.gameObject.layer == 6)
{
Explode();
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 80de3fa3d92ba7548b32e6bbd98c513a

View File

@@ -0,0 +1 @@
uid://b0w350q6bo8kq

View File

@@ -0,0 +1,415 @@
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 Jacob Weedman
//Use on tank type enemies
public class TankAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = true;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 5f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
float angle;
//ENEMY STATS (Changeable)
public float Speed = 0.5f; // In relation to player's walking speed
public float Health = 200;
public float PatrolDistance = 10;
public int PatrolStallTime = 200; //ms
public int PlayerDetectionRange = 50;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 15; // Damage per hit
public int WeaponFireRate = 1000; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles
public int WeaponRange = 40; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 40f; // Speed of launched projectiles
public int WeaponMagazineSize = 30; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 6000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance && transform.position.y - pos.transform.position.y > 0)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 15;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// 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 (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform)
{
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
//float xDirection = target.transform.position.x - transform.position.x;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// 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
angle = 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)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// If enemy is at the target position (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, transform.position) < 1.5)
{
ComputeClosestPositionToPlayer();
}
// If the player moves away (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) > DesiredDistance)
{
ComputeClosestPositionToPlayer();
}
// If the player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// 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;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canMove = true;
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 && transform.position.y - query.transform.position.y > 0 && Vector2.Distance(query.transform.position, transform.position) < 10)
{
// 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)];
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b581fa8060dd2534c961df6092303e29

View File

@@ -0,0 +1 @@
uid://c10q5uurc7lot

View File

@@ -0,0 +1,414 @@
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 Jacob Weedman
//V 0.0.2
//DO NOT USE THIS ON ANY ENEMIES
public class TestEnemyAIAirRanged : MonoBehaviour
{
//MISC
public GameObject target;
public float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> AllPositions;
public float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
public bool canMove = true;
public bool canPursue = false;
public bool canFire = true;
public bool currentlyReloading = false;
public bool currentlyPatrolling;
public bool currentlyMovingToNextPatrolTarget = false;
public float DesiredDistance;
public float MinumumDistance = 20f;
public bool targetingPlayer = false;
public bool inFiringCycle = false;
public int WeaponCurrentMagazineAmmount;
public int NumberOfHitsPerMag = 0;
public float angle;
//ENEMY STATS (Changeable)
public float Speed = 0.7f; // In relation to player's walking speed
public float Health = 100;
public float PatrolDistance = 10;
public int PatrolStallTime = 1500; //ms
public int PlayerDetectionRange = 25;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 5; // Damage per hit
public int WeaponFireRate = 100; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles
public int WeaponRange = 30; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles
public int WeaponMagazineSize = 50; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
Seeker seeker;
Rigidbody2D rb;
//START OF THE GAME
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
target = Instantiate(GameObject.Find("FlyingTarget"), transform.position,Quaternion.identity);
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 30);
}
// 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())
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
//target = gameObject;
targetingPlayer = false;
LastKnownPlayerLocation = null;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
// Death
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
DeadBody.GetComponent<Rigidbody2D>().gravityScale = 3;
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIAirRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform)
{
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
// 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;
}
*/
//CHANGE ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && inFiringCycle == false && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
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++;
}
}
//PATROL
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// Angle barrel towards player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
// 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;
}
}
}
// 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)
{
canPursue = false;
target.transform.position = LastKnownPlayerLocation.transform.position;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = -90f;
}
// Go back to patrol move
else
{
LastKnownPlayerLocation = gameObject;
currentlyPatrolling = true;
targetingPlayer = false;
// Reset barrel rotation
angle = -90f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
// Call patrol method
if (currentlyPatrolling)
{
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
}
//TARGET DETERMINATION
if (canPursue == true)
{
// Catch desired distance error
if (DesiredDistance <= MinumumDistance)
{
DesiredDistance = MinumumDistance + 1;
}
// If enemy is at the target position
if (Vector2.Distance(target.transform.position, transform.position) < 1.5)
{
ComputeClosestPositionToPlayer();
}
// 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 player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1)
{
if (DetermineLineOfSight(gameObject, player) == false) // If the enemy has LOS on the player
{
ComputeClosestPositionToPlayer();
}
}
}
}
//MISC METHODS
// Use Ranged Weapon
async Task UseWeapon() // Weapon for projectile based enemy
{
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
if (NumberOfHitsPerMag / WeaponMagazineSize < 0.5)
{
DesiredDistance -= 5;
}
NumberOfHitsPerMag = 0;
canFire = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = gameObject;
target.transform.position = transform.position;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//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)));
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
currentlyMovingToNextPatrolTarget = false;
}
// 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;
}
}
// Partof the pursue cycle
void ComputeClosestPositionToPlayer()
{
canMove = true;
// find a target in the air a set radius away from the player
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)));
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ba7d100626939a34a940695ac9a80a8c

View File

@@ -0,0 +1 @@
uid://oxmo5iseeica

View File

@@ -0,0 +1,484 @@
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 Jacob Weedman
//V 0.0.1
//DO NOT USE ON ANY ENEMIES
public class TestEnemyAIDroneRanged : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
GameObject LastKnownPlayerLocation;
Transform DroneBayLocation;
//CONDITIONS/GENERAL INFORMATION
public bool canMove = false;
public bool canPursue = false;
public bool canFire = true;
public bool currentlyReloading = false;
public bool currentlyInDroneBay = true;
public float DesiredDistance;
public float MinumumDistance = 10f;
public bool targetingPlayer = false;
public bool inFiringCycle = false;
public int WeaponCurrentMagazineAmmount;
public int NumberOfHitsPerMag = 0;
public int CurrentBatteryCapacity;
public bool currentlyTravelingToDroneBay = false;
public bool currentlyRecharging = false;
public float angle;
//ENEMY STATS (Changeable)
public float Speed = 0.7f; // In relation to player's walking speed
public float Health = 100;
public int PlayerDetectionRange = 25;
public int MaxBatteryCapacity = 30; // Depletes one every second it is out of the bay
public int RechargeTime = 6000; //ms
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 5; // Damage per hit
public int WeaponFireRate = 100; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles (DOES NOT APPLY TO MELEE ATTACKS)
public int WeaponRange = 30; // Maximum range of the projectile before it drops off (DOES NOT APPLY TO MELEE ATTACKS)
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles (DOES NOT APPLY TO MELEE WEAPONS)
public int WeaponMagazineSize = 50; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
Seeker seeker;
Rigidbody2D rb;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("BatteryIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
target = Instantiate(GameObject.Find("FlyingTarget"), transform.position, Quaternion.identity);
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
DroneBayLocation = transform.parent.transform;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
CurrentBatteryCapacity = MaxBatteryCapacity;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 30);
InvokeRepeating("BatteryDrain", 0f, 1);
Recharge();
}
// 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())
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
//target = gameObject;
targetingPlayer = false;
LastKnownPlayerLocation = null;
//ReturnToDroneBay();
}
}
// Battery Drain
void BatteryDrain()
{
if (currentlyInDroneBay == false)
{
CurrentBatteryCapacity -= 1;
}
}
// MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (CurrentBatteryCapacity == 0)
{
Health = 0;
}
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
DeadBody.GetComponent<Rigidbody2D>().gravityScale = 3;
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIDroneRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform)
{
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//Battery
// Low battery return
if (CurrentBatteryCapacity <= MaxBatteryCapacity / 10)
{
ReturnToDroneBay();
}
// Recharge battery & bay detection
if (Vector2.Distance(transform.position, DroneBayLocation.position) <= 0.5)
{
currentlyInDroneBay = true;
currentlyTravelingToDroneBay = false;
if (currentlyRecharging == false && CurrentBatteryCapacity < MaxBatteryCapacity / 10)
{
Recharge();
}
else
{
canMove = false;
}
}
else
{
//canMove = true;
currentlyInDroneBay = false;
}
// 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;
}
*/
//CHANGE ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (CurrentBatteryCapacity <= MaxBatteryCapacity / 10)
{
transform.Find("BatteryIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("BatteryIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyInDroneBay == false)
{
seeker.enabled = true;
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyInDroneBay == false)
{
if (DetermineLineOfSight(gameObject, player) == true && inFiringCycle == false && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
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++;
}
}
//DETECTION
// Enemy detects player
if (DetermineLineOfSight(transform.parent.gameObject, player) && Vector2.Distance(DroneBayLocation.position, player.transform.position) <= PlayerDetectionRange && currentlyRecharging == false)
{
if (currentlyInDroneBay == true)
{
rb.linearVelocity = transform.parent.transform.up * 10;
}
canMove = true;
targetingPlayer = true;
canPursue = true;
// Angle barrel towards player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
else if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
targetingPlayer = true;
canPursue = true;
// 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;
}
}
// Reset barrel rotation
angle = -90f;
}
// 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)
{
canPursue = false;
target.transform.position = LastKnownPlayerLocation.transform.position;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = -90f;
}
// Go back to drone bay
else
{
LastKnownPlayerLocation = null;
ReturnToDroneBay();
targetingPlayer = false;
// Reset barrel rotation
angle = -90f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
if (currentlyTravelingToDroneBay == false)
{
//TARGET DETERMINATION
// If enemy is at the target position
if (Vector2.Distance(target.transform.position, transform.position) < 1.5)
{
ComputeClosestPositionToPlayer();
}
// 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 player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1)
{
if (DetermineLineOfSight(gameObject, player) == false) // If the enemy has LOS on the player
{
ComputeClosestPositionToPlayer();
}
}
}
}
//MISC METHODS
// Use Ranged Weapon
async Task UseWeapon() // Weapon for projectile based enemy
{
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
NumberOfHitsPerMag = 0;
canFire = true;
}
// Return To Drone Bay
async Task ReturnToDroneBay()
{
if (currentlyTravelingToDroneBay == false && currentlyInDroneBay == false)
{
currentlyTravelingToDroneBay = true;
target.transform.position = DroneBayLocation.position;
}
}
// Recharge
async Task Recharge()
{
currentlyRecharging = true;
canMove = false;
canFire = false;
seeker.enabled = false;
transform.position = DroneBayLocation.position;
rb.linearVelocity = Vector3.zero;
currentlyTravelingToDroneBay = false;
await Task.Delay(RechargeTime);
CurrentBatteryCapacity = MaxBatteryCapacity;
currentlyRecharging = false;
canFire = true;
}
// 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;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
// find a target in the air a set radius away from the player
if (DetermineLineOfSight(player, gameObject))
{
canMove = true;
target.transform.position = new Vector2((player.transform.position.x + UnityEngine.Random.Range(-MinumumDistance, MinumumDistance)), (player.transform.position.y + MinumumDistance + UnityEngine.Random.Range(-5, 0)));
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7c73bec38592c574d813f6e649bfab1c

View File

@@ -0,0 +1,492 @@
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 Jacob Weedman
//V 0.0.6
//DO NOT USE THIS ON ANY ENEMIES
public class TestEnemyAIGroundRanged : MonoBehaviour
{
//MISC
public GameObject target;
public float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
public float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
public bool canJump = true; //
public bool canMove = true; // Prevent all movement
public bool canPursue = false; // Follow player
public bool canFire = false;
public bool currentlyReloading = false;
public bool currentlyPatrolling;
public bool currentlyMovingToNextPatrolTarget = false;
public float DesiredDistance;
public float MinumumDistance = 5f;
public bool targetingPlayer = false;
public bool inFiringCycle = false;
public int WeaponCurrentMagazineAmmount;
public int NumberOfHitsPerMag = 0;
public float angle;
//ENEMY STATS (Changeable)
public float Speed = 0.7f; // In relation to player's walking speed
public float JumpHeight = 1; // In relation to player's regular jump height
public float Health = 100;
public float PatrolDistance = 10;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 25;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 15; // Damage per hit
public int WeaponFireRate = 250; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles
public int WeaponRange = 20; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles
public int WeaponMagazineSize = 20; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// 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 (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
// 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;
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
//float xDirection = target.transform.position.x - transform.position.x;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// 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
angle = 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)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// 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 the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
canMove = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
canMove = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
canMove = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
if (NumberOfHitsPerMag / WeaponMagazineSize < 0.5)
{
DesiredDistance -= 5;
}
NumberOfHitsPerMag = 0;
canFire = true;
canMove = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
DesiredDistance = WeaponRange - 5;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// 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;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
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)];
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;
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 80fa5955b49f1ca43afa1e8e6ac2eb39

View File

@@ -0,0 +1,189 @@
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 Jacob Weedman
//V 0.0.1
//DO NOT USE THIS ON ANY ENEMIES
public class TestEnemyAITurret : MonoBehaviour
{
//MISC
GameObject projectile;
GameObject player;
GameObject barrel;
public float DistanceFromPlayer;
Vector2 StartPosition;
//CONDITIONS/GENERAL INFORMATION
public bool canFire = true;
public bool currentlyReloading = false;
public bool targetingPlayer = false;
public bool inFiringCycle = false;
public int WeaponCurrentMagazineAmmount;
public float angle;
//ENEMY STATS (Changeable)
public float Health = 100;
public int PlayerDetectionRange = 25;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 15; // Damage per hit
public int WeaponFireRate = 250; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles
public int WeaponRange = 20; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles
public int WeaponMagazineSize = 20; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
//ONCE THE GAME STARTS
void Start()
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
canFire = true;
}
//MAIN LOGIC
void FixedUpdate()
{
DistanceFromPlayer = Vector2.Distance(transform.position, player.transform.position);
// Death
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//PLAYER TARGETING
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange + 10)
{
targetingPlayer = true;
// Set angle to player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
else
{
// Reset barrel rotation
angle = 90f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
}
//MISC METHODS
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, 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;
// 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));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
}
// 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;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 94c55f3189ba7ee4399dc3c6f10550ce

View File

@@ -0,0 +1 @@
uid://b6jwhvkhdkpdo

View File

@@ -0,0 +1,440 @@
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 Jacob Weedman
//Use on warper type enemies
public class WarperAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canJump = true;
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 15f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int NumberOfHitsPerMag = 0;
bool canTeleport = true;
//ENEMY STATS (Changeable)
public float Speed = 0.7f; // In relation to player's walking speed
public float JumpHeight = 0.7f; // In relation to player's regular jump height
public float Health = 100;
public float PatrolDistance = 10;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 25;
public int TeleportCooldown = 500; //ms
//WEAPON STATS (CHANGEABLE)
public int WeaponRange = 30; // Maximum range of the projectile before it drops off
public int WeaponFireRate = 5000; // ms
public int WeaponDamage = 1;
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
LastKnownPlayerLocation = null;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 30);
}
// 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 (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
if (targetingPlayer == false)
{
target = gameObject;
MoveNextPatrol();
Teleport();
}
else
{
Teleport();
}
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if ( canFire == true && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
//float xDirection = target.transform.position.x - transform.position.x;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f && targetingPlayer == false) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// 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;
}
}
}
// 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)
{
canPursue = false;
target = LastKnownPlayerLocation;
Teleport();
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
}
//TARGET DETERMINATION
if (canPursue == true)
{
// If enemy is at the target position (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, transform.position) < 1.5 && canTeleport)
{
ComputeClosestPositionToPlayer();
}
// 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();
}
// Teleport enemy
if (canTeleport)
{
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 (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
// Use Weapon
async Task UseWeapon()
{
canFire = false;
canMove = false;
inFiringCycle = true;
GameObject EvilAura;
EvilAura = Instantiate(GameObject.Find("EvilAura"), new Vector3(transform.position.x + UnityEngine.Random.Range(-0.5f, 0.5f), transform.position.y + UnityEngine.Random.Range(-0.5f, 0.5f), GameObject.Find("EvilAura").transform.position.z), Quaternion.identity);
EvilAura.transform.rotation = Quaternion.Euler(Vector3.forward * UnityEngine.Random.Range(-90, 90));
// Send it on its way
EvilAura.GetComponent<Rigidbody2D>().linearVelocity = new Vector2(transform.position.x - player.transform.position.x, transform.position.y - player.transform.position.y).normalized * WeaponRange * -1;
//Set Variables
EvilAura.GetComponent<EnemyParticleWeapon>().destroy = true;
EvilAura.GetComponent<EnemyParticleWeapon>().opacity = true;
EvilAura.GetComponent<EnemyParticleWeapon>().rotate = true;
EvilAura.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
await Task.Delay(WeaponFireRate);
canFire = true;
canMove = true;
inFiringCycle = false;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
DesiredDistance = WeaponRange - 5;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// 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;
}
}
// Teleport
async Task Teleport()
{
canTeleport = false;
transform.position = target.transform.position;
await Task.Delay(TeleportCooldown + UnityEngine.Random.Range(0, TeleportCooldown / 2));
canTeleport = true;
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
SuitablePositions.Clear();
foreach (GameObject query in AllPositions)
{
// Check the distance of the position
if (Vector2.Distance(query.transform.position, player.transform.position) < 30 && Vector2.Distance(query.transform.position, player.transform.position) >= 10)
{
// 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)];
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8326ce0bf6190774b8982a52045b38e2

View File

@@ -0,0 +1 @@
uid://c0dqxf7d6xd7d

View File

@@ -0,0 +1,124 @@
using JetBrains.Annotations;
using System;
using UnityEngine;
using static UnityEngine.Rendering.DebugUI;
public class playerMovement : MonoBehaviour
{
private GroundCheck groundCheck; //Allows Use Of GroundCheck Script Variables
private Rigidbody2D body;
private BoxCollider2D hBox;
private bool allowedToMove = true, allowedToJump = true, doubleJumpUnlocked = true; //Unlocking & Locking Abilities
private bool isGrounded, canJumpAgain; //Physics Checks
private float CoyoteTimer, BufferTimer, airjumpTurnTimer, turnaround; //Timers & Calculation Variables
private float moveSpeed = 10f, groundJumpSpeed = 18f, airJumpSpeed = 14f, turnResponsiveness = 4f; //Physics Values
private float coyoteTimeAmount = .1f, airjumpTurnaroundTimeAmount = 1.5f, jumpBufferAmount = .2f; //Leniency Velues
private KeyCode hop = KeyCode.W, crouch = KeyCode.S, left = KeyCode.A, right = KeyCode.D; //Controls
void Start()
{
body = GetComponent<Rigidbody2D>();
hBox = transform.GetComponent<BoxCollider2D>();
body.gravityScale = 4;
}
void Update()
{
TimerHandler();
GroundCheck();
Movement();
}
void GroundCheck() {
groundCheck = GetComponentInChildren<GroundCheck>(); // Ground Check
isGrounded = groundCheck.isGrounded;
if (doubleJumpUnlocked && isGrounded) canJumpAgain = true; //Realoading Double Jump
} //Ground & Double Jump Checks
void TimerHandler()
{
if (isGrounded && !(body.linearVelocity.y > 0)) CoyoteTimer = coyoteTimeAmount; //Coyote Time
else CoyoteTimer -= Time.deltaTime;
if (Input.GetKeyDown(hop)) BufferTimer = jumpBufferAmount; //Jump Buffering
if (BufferTimer > 0) BufferTimer -= Time.deltaTime;
if (airjumpTurnTimer > 0) airjumpTurnTimer -= Time.deltaTime; //Double Jump Physics
} //Input Leniency & Special Input Time Windows
void Movement() {
if (allowedToMove)
{
if (!(Input.GetKey(left) && Input.GetKey(right)))
{
if (!isGrounded) turnaround = turnResponsiveness * .75f;
else turnaround = turnResponsiveness;
if (Input.GetKey(left))
{
body.linearVelocity += new Vector2(-moveSpeed * turnaround * Time.deltaTime, 0);
body.linearVelocity = new Vector2(Mathf.Clamp(body.linearVelocity.x, -moveSpeed, moveSpeed), body.linearVelocity.y);
}
if (Input.GetKey(right))
{
body.linearVelocity += new Vector2(moveSpeed * turnaround * Time.deltaTime, 0);
body.linearVelocity = new Vector2(Mathf.Clamp(body.linearVelocity.x, -moveSpeed, moveSpeed), body.linearVelocity.y);
}
} //Walking
if ( !(Input.GetKey(left) || Input.GetKey(right)) || (Input.GetKey(left) && Input.GetKey(right)))
{
body.linearVelocity = new Vector2(body.linearVelocity.x * .985f, body.linearVelocity.y);
} //Custom friction
} //Horizontal Movement & Physics
if (allowedToJump)
{
if ((CoyoteTimer > 0 && BufferTimer > 0))
{
body.linearVelocity = new Vector2(body.linearVelocity.x, groundJumpSpeed);
BufferTimer = 0;
CoyoteTimer = 0;
} //Normal jump is performed
else if (canJumpAgain && Input.GetKeyDown(hop))
{
body.linearVelocity = new Vector2(body.linearVelocity.x, airJumpSpeed);
canJumpAgain = false;
airjumpTurnTimer = airjumpTurnaroundTimeAmount;
} //Air jump is performed
if (!Input.GetKey(hop) && body.linearVelocity.y > 0)
{
body.linearVelocity = new Vector2(body.linearVelocity.x, body.linearVelocity.y * .92f);
} //Jump Released
} //Vertical Movement & Physics
} //Check Player Input
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2627a91a1f5308c41a35eeeea160fda1

View File

@@ -0,0 +1 @@
uid://df2ji7oywfcfu