Fixed small visual bugs
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3f4bf5bfa244ad42bb0aee2a2ae9299
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,411 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Pathfinding;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
public class Sector1BossScript : MonoBehaviour
|
||||
{
|
||||
|
||||
// Designed by Jacob Weedman
|
||||
|
||||
GameObject Player;
|
||||
GameObject Barrel;
|
||||
GameObject Target;
|
||||
GameObject ChosenFireZone;
|
||||
GameObject Spotlight;
|
||||
GameObject Camera;
|
||||
GameObject BossProjectile;
|
||||
|
||||
public float Phase = 0.5f;
|
||||
public float Health = 800;
|
||||
|
||||
public float angle;
|
||||
|
||||
bool canDeploy = true;
|
||||
public float DeployTimer = 4; // sec
|
||||
float CurrentDeployTimer; // sec
|
||||
public List<GameObject> DeployLocations;
|
||||
public List<GameObject> FireZones;
|
||||
|
||||
public int Choice; //1 == shoot >1 == deploy
|
||||
public float InitialChoiceCountdown = 2f; // sec
|
||||
public float ChoiceCountdown; // sec
|
||||
float InitialBulletInterval = 0.01f;
|
||||
float BulletInterval = 0.01f;
|
||||
float InitialMoveCountdown = 2; //sec
|
||||
float MoveCountdown = 6; // sec
|
||||
|
||||
float LaunchCooldown = 2f;
|
||||
|
||||
bool canJump = true;
|
||||
float InitialJumpDelay = 1000;
|
||||
float JumpDelay = 1000;
|
||||
|
||||
bool canShockwaveDamage = true;
|
||||
int ShockwaveDamage = 10;
|
||||
int WeaponDamage = 1;
|
||||
int WeaponRange = 50;
|
||||
int WeaponProjectileSpeed = 20;
|
||||
int WeaponRandomSpread = 8;
|
||||
|
||||
float MovementSpeed = 2.5f;
|
||||
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Awake()
|
||||
{
|
||||
Camera = GameObject.FindGameObjectWithTag("MainCamera");
|
||||
BossProjectile = GameObject.Find("EnemyProjectile");
|
||||
Player = GameObject.FindWithTag("Player");
|
||||
Spotlight = transform.Find("SpotlightAxis").gameObject;
|
||||
Barrel = transform.Find("Barrel").gameObject;
|
||||
Target = GameObject.Find("BossTarget");
|
||||
Target.transform.position = transform.position;
|
||||
|
||||
transform.Find("DamagerPiece").gameObject.GetComponent<GenericDamager>().LockDamage = true;
|
||||
|
||||
foreach (Transform spawner in transform)
|
||||
{
|
||||
if (spawner.name == "SwitchbladeSpawner")
|
||||
{
|
||||
DeployLocations.Add(spawner.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
FireZones = GameObject.FindGameObjectsWithTag("1").ToList();
|
||||
|
||||
ChoiceCountdown = InitialChoiceCountdown;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Update is called once per frame
|
||||
void FixedUpdate()
|
||||
{
|
||||
Health = gameObject.GetComponent<GenericDestructable>().Health;
|
||||
|
||||
GameObject.Find("HealthIndicator").transform.localScale = new Vector3(Health / 800 * 30, 1, 1);
|
||||
|
||||
if (Phase == 1 && Choice > 1)
|
||||
{
|
||||
BackgroundMove();
|
||||
}
|
||||
|
||||
switch (Phase)
|
||||
{
|
||||
#region Phase1
|
||||
|
||||
case 1: // Phase 1
|
||||
|
||||
if (Health <= 400)
|
||||
{
|
||||
Health = 400;
|
||||
Phase = 1.5f;
|
||||
gameObject.GetComponent<Rigidbody2D>().linearVelocity = Vector2.up * 60;
|
||||
}
|
||||
|
||||
if (ChosenFireZone)
|
||||
{
|
||||
// Angle spotlight towards fireing zone
|
||||
angle = Mathf.Atan2(ChosenFireZone.transform.position.y + 10 - Barrel.transform.position.y, ChosenFireZone.transform.position.x - Barrel.transform.position.x) * Mathf.Rad2Deg;
|
||||
angle += 90;
|
||||
// Rotate spotlight towards fireing zone
|
||||
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
|
||||
Spotlight.transform.rotation = Quaternion.RotateTowards(Spotlight.transform.rotation, targetRotation, 200 * Time.deltaTime);
|
||||
}
|
||||
|
||||
// Change attack speed
|
||||
if (Health >= 750)
|
||||
{
|
||||
DeployTimer = 4;
|
||||
InitialChoiceCountdown = 3.5f;
|
||||
LaunchCooldown = 1.75f;
|
||||
}
|
||||
else if (Health >= 700)
|
||||
{
|
||||
DeployTimer = 2;
|
||||
InitialChoiceCountdown = 3;
|
||||
LaunchCooldown = 1.50f;
|
||||
}
|
||||
else if (Health >= 650)
|
||||
{
|
||||
DeployTimer = 1;
|
||||
InitialChoiceCountdown = 2.5f;
|
||||
LaunchCooldown = 1.25f;
|
||||
}
|
||||
else if (Health >= 500)
|
||||
{
|
||||
DeployTimer = 0.5f;
|
||||
InitialChoiceCountdown = 1;
|
||||
LaunchCooldown = 0.75f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ChoiceCountdown -= Time.deltaTime;
|
||||
if (ChoiceCountdown <= 0)
|
||||
{
|
||||
ChoiceCountdown = InitialChoiceCountdown;
|
||||
Choice = UnityEngine.Random.Range(1, 4);
|
||||
|
||||
if (Choice == 1) // Find random firing zone
|
||||
{
|
||||
|
||||
foreach (GameObject location in FireZones) // Set all fire zones to invisible
|
||||
{
|
||||
//location.GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
|
||||
ChosenFireZone = FireZones[UnityEngine.Random.Range(0, FireZones.Count())];
|
||||
//ChosenFireZone.GetComponent<SpriteRenderer>().enabled = true;
|
||||
|
||||
Spotlight.transform.Find("Spotlight").gameObject.GetComponent<SpriteRenderer>().enabled = true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (GameObject location in FireZones) // Set all fire zones to invisible
|
||||
{
|
||||
//location.GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
|
||||
Spotlight.transform.Find("Spotlight").gameObject.GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
MoveCountdown -= Time.deltaTime;
|
||||
if (Vector2.Distance(Target.transform.position, transform.position) <= 0.1)
|
||||
{
|
||||
if (MoveCountdown <= 0 )
|
||||
{
|
||||
MoveCountdown = InitialMoveCountdown;
|
||||
Target.transform.position = new Vector2(UnityEngine.Random.Range(-20, 13), UnityEngine.Random.Range(-1, 4));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MoveCountdown = InitialMoveCountdown;
|
||||
}
|
||||
|
||||
if (Choice > 1) // Deploy
|
||||
{
|
||||
CurrentDeployTimer -= Time.deltaTime;
|
||||
if (CurrentDeployTimer <= 0)
|
||||
{
|
||||
canDeploy = true;
|
||||
}
|
||||
|
||||
if (canDeploy)
|
||||
{
|
||||
CurrentDeployTimer = DeployTimer;
|
||||
canDeploy = false;
|
||||
Deploy();
|
||||
}
|
||||
}
|
||||
else // Shoot
|
||||
{
|
||||
transform.position = Vector3.MoveTowards(transform.position, new Vector3(-3.5f, 6, transform.position.z), MovementSpeed * Time.deltaTime);
|
||||
|
||||
BulletInterval -= Time.deltaTime;
|
||||
if (BulletInterval <= 0)
|
||||
{
|
||||
BulletInterval = InitialBulletInterval;
|
||||
Shoot();
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
#endregion
|
||||
|
||||
#region Cutscene between 1 - 2
|
||||
|
||||
case 1.5f: // Cutscene between plases 1 & 2
|
||||
gameObject.GetComponent<Rigidbody2D>().gravityScale = 3;
|
||||
gameObject.GetComponent<BoxCollider2D>().isTrigger = false;
|
||||
transform.Find("DamagerPiece").gameObject.GetComponent<GenericDamager>().LockDamage = false;
|
||||
|
||||
gameObject.layer = LayerMask.NameToLayer("FlyingEnemies");
|
||||
|
||||
if (transform.Find("SpotlightAxis")){
|
||||
Spotlight.transform.Find("Spotlight").gameObject.GetComponent<SpriteRenderer>().enabled = false;
|
||||
Destroy(transform.Find("SpotlightAxis").gameObject);
|
||||
}
|
||||
|
||||
foreach (Transform child in transform)
|
||||
{
|
||||
if (child.name != "DamagerPiece")
|
||||
{
|
||||
child.gameObject.layer = LayerMask.NameToLayer("FlyingEnemies");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (transform.position.y <= 1.5)
|
||||
{
|
||||
Phase = 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Phase2
|
||||
case 2: // Phase 2
|
||||
|
||||
// Change attack speed
|
||||
if (Health >= 550)
|
||||
{
|
||||
float InitialJumpDelay = 1000;
|
||||
}
|
||||
else if (Health >= 400)
|
||||
{
|
||||
float InitialJumpDelay = 600;
|
||||
}
|
||||
else if (Health >= 300)
|
||||
{
|
||||
float InitialJumpDelay = 300;
|
||||
}
|
||||
else if (Health >= 200)
|
||||
{
|
||||
float InitialJumpDelay = 200;
|
||||
}
|
||||
|
||||
if (Health <= 0)
|
||||
{
|
||||
Health = 0;
|
||||
Phase = 2.5f;
|
||||
}
|
||||
|
||||
if (gameObject.GetComponent<Rigidbody2D>().linearVelocity.y < 0 && transform.position.y < -3f)
|
||||
{
|
||||
if (canShockwaveDamage)
|
||||
{
|
||||
for (int i = 0; i < 1; i++)
|
||||
{
|
||||
// Spawn Grunt
|
||||
GameObject GrenadeInstance = Instantiate(GameObject.Find("EnemyGrenade").gameObject, transform.position, Quaternion.identity);
|
||||
GrenadeInstance.GetComponent<Rigidbody2D>().gravityScale = 1.5f;
|
||||
GrenadeInstance.GetComponent<EnemyGrenade>().enabled = true;
|
||||
GrenadeInstance.GetComponent<EnemyGrenade>().ExplodeOnContact = true;
|
||||
GrenadeInstance.GetComponent<EnemyGrenade>().Duration = UnityEngine.Random.Range(3, 8);
|
||||
GrenadeInstance.GetComponent<Rigidbody2D>().linearVelocity = new Vector2(UnityEngine.Random.Range(-25,25), UnityEngine.Random.Range(10,25));
|
||||
}
|
||||
|
||||
// Damage Boss
|
||||
gameObject.GetComponent<GenericDestructable>().Health -= ShockwaveDamage;
|
||||
|
||||
// Shake Camera
|
||||
Camera.GetComponent<CameraMovement>().shakeCamera(0.8f, 0.5f);
|
||||
canJump = true;
|
||||
if (Player.transform.GetComponentInChildren<GroundCheck>().isGrounded == true)
|
||||
{
|
||||
// Shockwave Damage
|
||||
GameObject.Find("GameData").GetComponent<GameData>().CurrentHealth -= ShockwaveDamage;
|
||||
}
|
||||
}
|
||||
canShockwaveDamage = false;
|
||||
}
|
||||
|
||||
if (canJump)
|
||||
{
|
||||
Jump();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#region Death Animation
|
||||
case 2.5f:
|
||||
Phase = 3;
|
||||
break;
|
||||
#endregion
|
||||
|
||||
#region Death
|
||||
case 3:
|
||||
break;
|
||||
#endregion
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
async Awaitable Deploy()
|
||||
{
|
||||
// Find Which module to deploy from
|
||||
GameObject ChosenSpawner = DeployLocations[UnityEngine.Random.Range(0, DeployLocations.Count())];
|
||||
|
||||
GameObject Switchblade;
|
||||
Switchblade = Instantiate(GameObject.Find("SwitchbladeEnemy"), new Vector3(ChosenSpawner.transform.position.x, ChosenSpawner.transform.position.y, -1), Quaternion.identity);
|
||||
Switchblade.transform.parent = gameObject.transform;
|
||||
|
||||
Switchblade.GetComponent<MasterEnemyAI>().enabled = true;
|
||||
Switchblade.GetComponent<MasterEnemyAI>().AbilityMove = false;
|
||||
Switchblade.GetComponent<MasterEnemyAI>().AbilityDash = false;
|
||||
|
||||
await Awaitable.WaitForSecondsAsync(LaunchCooldown);
|
||||
|
||||
Switchblade.GetComponent<Seeker>().enabled = true;
|
||||
Switchblade.GetComponent<MasterEnemyAI>().AbilityMove = true;
|
||||
Switchblade.GetComponent<MasterEnemyAI>().AbilityDash = true;
|
||||
Switchblade.GetComponent<MasterEnemyAI>().AbilityPlayerESP = true;
|
||||
|
||||
// Launch
|
||||
Switchblade.GetComponent<Rigidbody2D>().linearVelocity = new Vector2(UnityEngine.Random.Range(-15,15), 20);
|
||||
|
||||
Switchblade.transform.parent = null;
|
||||
}
|
||||
|
||||
async Awaitable Jump()
|
||||
{
|
||||
canJump = false;
|
||||
canShockwaveDamage = true;
|
||||
|
||||
await Awaitable.WaitForSecondsAsync(1);
|
||||
|
||||
// Jump Towards Player
|
||||
if (Player.transform.position.x - transform.position.x > 0) // Jump right
|
||||
{
|
||||
GetComponent<Rigidbody2D>().linearVelocity = new Vector2(15, 30);
|
||||
}
|
||||
else if (Player.transform.position.x - transform.position.x < 0) // Jump left
|
||||
{
|
||||
GetComponent<Rigidbody2D>().linearVelocity = new Vector2(-15, 30);
|
||||
}
|
||||
else // Jump straight up
|
||||
{
|
||||
GetComponent<Rigidbody2D>().linearVelocity = new Vector2(0, 30);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Shoot()
|
||||
{
|
||||
if (ChosenFireZone)
|
||||
{
|
||||
// Create Projectile
|
||||
GameObject BulletInstance;
|
||||
BulletInstance = Instantiate(BossProjectile, Barrel.transform.position, Quaternion.LookRotation(transform.position - ChosenFireZone.transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
|
||||
//BulletInstance.transform.parent = transform;
|
||||
|
||||
// Variables
|
||||
BulletInstance.GetComponent<EnemyProjectileScript>().WeaponDamage = WeaponDamage;
|
||||
BulletInstance.GetComponent<EnemyProjectileScript>().WeaponRange = WeaponRange;
|
||||
|
||||
// Send it on it's way
|
||||
BulletInstance.GetComponent<Rigidbody2D>().linearVelocity = BulletInstance.transform.forward * -1 * WeaponProjectileSpeed;
|
||||
BulletInstance.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, BulletInstance.transform.forward) - 90));
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundMove()
|
||||
{
|
||||
transform.position = Vector3.MoveTowards(transform.position, new Vector3(Target.transform.position.x, Target.transform.position.y, transform.position.z), MovementSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1c590ca1f619314ca9de654d499ae32
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 4
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
uid://d3nlejagtenkx
|
||||
@@ -0,0 +1,177 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Pathfinding;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
public class Sector6BossScript : MonoBehaviour
|
||||
{
|
||||
|
||||
// Designed by Jacob Weedman
|
||||
|
||||
GameObject Player;
|
||||
GameObject ChosenSpawnZone;
|
||||
GameObject Camera;
|
||||
|
||||
public Dictionary<string, int> EnemyDict = new Dictionary<string, int>();
|
||||
public List<string> EnemyList;
|
||||
|
||||
public float Phase = 1f;
|
||||
public float Health = 1200;
|
||||
|
||||
bool canSpawn = true;
|
||||
public List<GameObject> SpawnLocations;
|
||||
|
||||
float InitialSpawnCooldown = 10;
|
||||
public float SpawnCooldown;
|
||||
|
||||
|
||||
void Start()
|
||||
{
|
||||
// Add spawn locations to list
|
||||
SpawnLocations = GameObject.FindGameObjectsWithTag("1").ToList();
|
||||
|
||||
// Setup
|
||||
SpawnCooldown = InitialSpawnCooldown;
|
||||
EnemyDict["Grunt"] = 1;
|
||||
|
||||
SpawnEnemy();
|
||||
SpawnEnemy();
|
||||
SpawnEnemy();
|
||||
SpawnEnemy();
|
||||
SpawnEnemy();
|
||||
SpawnEnemy();
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
// Health
|
||||
GameObject.Find("HealthIndicator").transform.localScale = new Vector3(Health / 1200 * 30, 1, 1);
|
||||
|
||||
if (Health >= 1100)
|
||||
{
|
||||
EnemyDict["Grunt"] = 1;
|
||||
InitialSpawnCooldown = 10;
|
||||
}
|
||||
else if (Health >= 1000)
|
||||
{
|
||||
EnemyDict["Grunt"] = 2;
|
||||
EnemyDict["Sniper"] = 1;
|
||||
InitialSpawnCooldown = 8;
|
||||
}
|
||||
else if (Health >= 900)
|
||||
{
|
||||
EnemyDict["Grunt"] = 5;
|
||||
EnemyDict["Sniper"] = 2;
|
||||
//EnemyDict["Brute"] = 1;
|
||||
InitialSpawnCooldown = 6;
|
||||
}
|
||||
else if (Health >= 800)
|
||||
{
|
||||
EnemyDict["Grunt"] = 6;
|
||||
EnemyDict["Sniper"] = 3;
|
||||
//EnemyDict["Brute"] = 2;
|
||||
EnemyDict["Warper"] = 1;
|
||||
InitialSpawnCooldown = 4;
|
||||
}
|
||||
else if (Health >= 700)
|
||||
{
|
||||
EnemyDict["Grunt"] = 3;
|
||||
EnemyDict["Sniper"] = 4;
|
||||
//EnemyDict["Brute"] = 3;
|
||||
EnemyDict["Warper"] = 3;
|
||||
InitialSpawnCooldown = 2;
|
||||
}
|
||||
else if (Health >= 600)
|
||||
{
|
||||
EnemyDict["Sniper"] = 1;
|
||||
EnemyDict["Warper"] = 1;
|
||||
EnemyDict["Grunt"] = 0;
|
||||
//EnemyDict["Brute"] = 0;
|
||||
InitialSpawnCooldown = 1;
|
||||
}
|
||||
|
||||
switch (Phase)
|
||||
{
|
||||
#region Phase1
|
||||
|
||||
case 1: // Phase 1
|
||||
|
||||
// Decriment Health Automatically
|
||||
Health -= Time.deltaTime * 5;
|
||||
|
||||
SpawnCooldown -= Time.deltaTime;
|
||||
|
||||
if (SpawnCooldown <= 0)
|
||||
{
|
||||
SpawnCooldown = InitialSpawnCooldown;
|
||||
SpawnEnemy();
|
||||
SpawnEnemy();
|
||||
SpawnEnemy();
|
||||
}
|
||||
|
||||
break;
|
||||
#endregion
|
||||
|
||||
#region Cutscene between 1 - 2
|
||||
|
||||
case 1.5f: // Cutscene between plases 1 & 2
|
||||
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Phase2
|
||||
case 2: // Phase 2
|
||||
|
||||
break;
|
||||
|
||||
#region Death Animation
|
||||
case 2.5f:
|
||||
Phase = 3;
|
||||
break;
|
||||
#endregion
|
||||
|
||||
#region Death
|
||||
case 3:
|
||||
break;
|
||||
#endregion
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
void SpawnEnemy()
|
||||
{
|
||||
// Put enemies into a list
|
||||
EnemyList.Clear();
|
||||
foreach (KeyValuePair<string, int> entry in EnemyDict)
|
||||
{
|
||||
int EndAmmount = entry.Value;
|
||||
for (int j = 0; j < EndAmmount; j++)
|
||||
{
|
||||
EnemyList.Add(entry.Key);
|
||||
}
|
||||
}
|
||||
// Choose spawn zone
|
||||
ChosenSpawnZone = SpawnLocations[UnityEngine.Random.Range(0, SpawnLocations.Count)];
|
||||
|
||||
// Choose enemy to spawn
|
||||
GameObject ChosenEnemy = GameObject.Find("EnemiesToSpawn").transform.Find(EnemyList[UnityEngine.Random.Range(0, EnemyList.Count())]).gameObject;
|
||||
|
||||
// Give life
|
||||
GameObject InstantiatedEnemy = Instantiate(ChosenEnemy, ChosenSpawnZone.transform.position, Quaternion.identity);
|
||||
InstantiatedEnemy.GetComponent<Rigidbody2D>().gravityScale = 1.5f;
|
||||
InstantiatedEnemy.GetComponent<MasterEnemyAI>().enabled = true;
|
||||
InstantiatedEnemy.GetComponent<Seeker>().enabled = true;
|
||||
InstantiatedEnemy.GetComponent<MasterEnemyAI>().AbilityPlayerESP = true;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac4e3de578868dc4390b633a15e3178b
|
||||
@@ -0,0 +1 @@
|
||||
uid://c4mwp02o1302d
|
||||
@@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class CharacterSelectionButtonScript : MonoBehaviour
|
||||
{
|
||||
public GameObject characterSelectionManager;
|
||||
|
||||
public string button;
|
||||
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
{
|
||||
Debug.Log(characterSelectionManager);
|
||||
Debug.Log(characterSelectionManager.GetComponent<CharacterSelectionScript>());
|
||||
}
|
||||
void OnMouseDown()
|
||||
{
|
||||
if (button == "right")
|
||||
{
|
||||
Debug.Log(button);
|
||||
characterSelectionManager.GetComponent<CharacterSelectionScript>().CycleRight();
|
||||
}
|
||||
if (button == "left")
|
||||
{
|
||||
Debug.Log(button);
|
||||
characterSelectionManager.GetComponent<CharacterSelectionScript>().CycleLeft();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d637ecefe89a0e546855a572d1eeb807
|
||||
@@ -0,0 +1 @@
|
||||
uid://ctqimfg1astny
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class CharacterSelectionScript : MonoBehaviour
|
||||
{
|
||||
private int selectedCharacterIndex = 0;
|
||||
|
||||
private string[] characters = {"Sloane", "Cade", "LeoAndAri", "Gamma07"};
|
||||
|
||||
private GameObject selectedCharacter;
|
||||
|
||||
|
||||
private int framesSinceChange = 0;
|
||||
|
||||
|
||||
void Awake()
|
||||
{
|
||||
selectedCharacter = GameObject.Find(characters[selectedCharacterIndex]);
|
||||
}
|
||||
|
||||
|
||||
void FixedUpdate() {
|
||||
framesSinceChange ++;
|
||||
|
||||
if (framesSinceChange > 5) {
|
||||
if (Input.GetKey(KeyCode.LeftArrow))
|
||||
{
|
||||
CycleLeft();
|
||||
}
|
||||
|
||||
|
||||
if (Input.GetKey(KeyCode.RightArrow))
|
||||
{
|
||||
CycleRight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CycleLeft() {
|
||||
if (selectedCharacterIndex == 0)
|
||||
{
|
||||
selectedCharacterIndex = characters.Length - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedCharacterIndex --;
|
||||
}
|
||||
selectedCharacter.GetComponent<SpriteRenderer>().enabled = false;
|
||||
selectedCharacter = GameObject.Find(characters[selectedCharacterIndex]);
|
||||
selectedCharacter.GetComponent<SpriteRenderer>().enabled = true;
|
||||
framesSinceChange = 0;
|
||||
}
|
||||
public void CycleRight() {
|
||||
if (selectedCharacterIndex == characters.Length - 1)
|
||||
{
|
||||
selectedCharacterIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedCharacterIndex += 1;
|
||||
}
|
||||
selectedCharacter.GetComponent<SpriteRenderer>().enabled = false;
|
||||
selectedCharacter = GameObject.Find(characters[selectedCharacterIndex]);
|
||||
selectedCharacter.GetComponent<SpriteRenderer>().enabled = true;
|
||||
framesSinceChange = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de0b956d5118ba54ca473a139e269602
|
||||
@@ -0,0 +1 @@
|
||||
uid://dwlht7cbx0w2h
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
|
||||
V 0.0.1
|
||||
|
||||
This doccument outlines some important information to keep in mind
|
||||
|
||||
1. Camera follows the player and has a "Size" value of 15 and a Z position of -10
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad647c10099d0ee49895d85a8051bf07
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
uid://cby6ea8ej1vu0
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e4fba3e90705634d87c5f003412fdff
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,53 @@
|
||||
using UnityEngine;
|
||||
|
||||
// Designed by Jacob Weedman
|
||||
// Attach to the grenade weapon prefab
|
||||
|
||||
public class EnemyGrenade : MonoBehaviour
|
||||
{
|
||||
public float Duration = 3;
|
||||
public int WeaponDamage = 20;
|
||||
public bool ExplodeOnContact = false;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
GetComponent<Rigidbody2D>().gravityScale = 2;
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
if (Duration <= 0)
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
Duration -= Time.deltaTime;
|
||||
}
|
||||
|
||||
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>().timer = 3;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().destroy = true;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().opacity = true;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
|
||||
|
||||
//Delete Grenade
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
if (ExplodeOnContact)
|
||||
{
|
||||
if (collision.gameObject.layer == LayerMask.NameToLayer("SolidGround") || collision.gameObject.layer == LayerMask.NameToLayer("Enemies") || collision.gameObject.layer == LayerMask.NameToLayer("Player"))
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80c412ade4dc79c409678eb649f2328d
|
||||
@@ -0,0 +1 @@
|
||||
uid://bt1llr72mfuo
|
||||
@@ -0,0 +1,105 @@
|
||||
using UnityEngine;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
|
||||
//Designed by Jacob Weedman
|
||||
// Attatch to particle weapons
|
||||
|
||||
public class EnemyParticleWeapon : MonoBehaviour
|
||||
{
|
||||
public bool destroy = false;
|
||||
public bool rotate = false;
|
||||
public bool opacity = false;
|
||||
public bool destroyOnCollide = false;
|
||||
public bool damageEnemies;
|
||||
public int damageAmmount;
|
||||
public float timer;
|
||||
float startTime;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
startTime = timer;
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
/*
|
||||
if (IsExplosion)
|
||||
{
|
||||
// Tick down animation counter
|
||||
AnimationTimer -= Time.deltaTime;
|
||||
GetComponent<SpriteRenderer>().sprite = ExplosionSprites[CurrentFrame];
|
||||
|
||||
if (AnimationTimer <= 0 && CurrentFrame < 0)
|
||||
{
|
||||
AnimationTimer = 0.5f;
|
||||
CurrentFrame++;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Rotation
|
||||
if (rotate)
|
||||
{
|
||||
transform.rotation = Quaternion.Euler(Vector3.forward * UnityEngine.Random.Range(-90, 90));
|
||||
}
|
||||
|
||||
// Opacity
|
||||
if (opacity)
|
||||
{
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, (timer / startTime));
|
||||
}
|
||||
|
||||
// Destruction Timer
|
||||
if (destroy)
|
||||
{
|
||||
timer -= Time.deltaTime;
|
||||
if (timer <= 0)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove Collider To Prevent Multiple Damage Occurances
|
||||
if (timer/startTime <= 0.99)
|
||||
{
|
||||
gameObject.GetComponent<BoxCollider2D>().enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
if (collision.gameObject.tag == "Player")
|
||||
{
|
||||
//Damage
|
||||
GameObject.Find("GameData").GetComponent<GameData>().CurrentHealth -= damageAmmount;
|
||||
}
|
||||
if (collision.gameObject.tag == "Attackable")
|
||||
{
|
||||
//Enemies
|
||||
if (collision.GetComponent<MasterEnemyAI>())
|
||||
{
|
||||
collision.GetComponent<MasterEnemyAI>().Health -= damageAmmount;
|
||||
}
|
||||
|
||||
//Generic Destructable Object
|
||||
if (collision.GetComponent<GenericDestructable>())
|
||||
{
|
||||
collision.GetComponent<GenericDestructable>().Health -= damageAmmount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (destroyOnCollide)
|
||||
{
|
||||
if (collision.gameObject.tag == "Ground")
|
||||
{
|
||||
if (collision.gameObject.layer == 6)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1bbf0aa2ca47db4cb2b99e096097fd3
|
||||
@@ -0,0 +1 @@
|
||||
uid://dnd1mdwubw0it
|
||||
@@ -0,0 +1,58 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
//Designed by Jacob Weedman
|
||||
|
||||
public class EnemyProjectileScript : MonoBehaviour
|
||||
{
|
||||
Vector2 StartPosition;
|
||||
|
||||
public int WeaponDamage;
|
||||
public int WeaponRange;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
StartPosition = transform.position;
|
||||
GetComponent<SpriteRenderer>().enabled = true;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
//transform.rotation = Quaternion.Euler(new Vector3(0, 0, GetComponent<Rigidbody2D>().angularVelocity));//FIX THIS
|
||||
|
||||
if (Vector2.Distance(transform.position, StartPosition) > WeaponRange)
|
||||
{
|
||||
GetComponent<Rigidbody2D>().gravityScale = 0.5f;
|
||||
|
||||
}
|
||||
|
||||
if (transform.position.y <= -10000)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
if (collision.gameObject.tag == "Player")
|
||||
{
|
||||
//Damage
|
||||
GameObject.Find("GameData").GetComponent<GameData>().CurrentHealth -= WeaponDamage;
|
||||
|
||||
//Send Hit Data (for repositioning)
|
||||
//if (GetComponentInParent<MasterEnemyAI>())
|
||||
//{
|
||||
// GetComponentInParent<MasterEnemyAI>().NumberOfHitsPerMag += 1;
|
||||
//}
|
||||
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
if (collision.gameObject.tag == "Ground")
|
||||
{
|
||||
if (collision.gameObject.layer == 6)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0352972f1b0f7bf44a209f0d71fc13b8
|
||||
@@ -0,0 +1 @@
|
||||
uid://c03naau3o536o
|
||||
@@ -0,0 +1,55 @@
|
||||
using UnityEngine;
|
||||
|
||||
// Designed by Jacob Weedman
|
||||
// Attach to the rocket weapon prefab
|
||||
|
||||
public class EnemyRocket : MonoBehaviour
|
||||
{
|
||||
public float duration;
|
||||
public int WeaponDamage;
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
if (duration <= 0)
|
||||
{
|
||||
GetComponent<Rigidbody2D>().gravityScale = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
GetComponent<Rigidbody2D>().gravityScale = 0;
|
||||
}
|
||||
duration -= Time.deltaTime;
|
||||
}
|
||||
|
||||
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>().timer = 3;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().destroy = true;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().opacity = true;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
|
||||
|
||||
//Delete Rocket
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
if (collision.gameObject.tag == "Ground")
|
||||
{
|
||||
if (collision.gameObject.layer == 6)
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
}
|
||||
if (collision.gameObject.tag == "Player")
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca804d481f50ae64393e4a8aedbe8e13
|
||||
@@ -0,0 +1 @@
|
||||
uid://c1sn8ld81mjht
|
||||
@@ -0,0 +1,925 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Pathfinding;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
// Designed by the goat Jacob Weedman
|
||||
// Use on any basic enemy
|
||||
//
|
||||
// Configure to your likeing
|
||||
// Not all options apply with every configuration
|
||||
//
|
||||
// PREREQUISITES
|
||||
// 1. The "Seeker" script from the A* pathfinding library must be attatched to the same game object
|
||||
// 2. A Rigidbody2D component must be attatched to the same game object
|
||||
// 3. A _Collider2D component must be attatched to the same game object
|
||||
// 4. Various game objects are required to be in the scene in order for this to function properly
|
||||
// 5. Various children game objects are required in order for this to funciton properly
|
||||
|
||||
public class MasterEnemyAI : MonoBehaviour
|
||||
{
|
||||
|
||||
#region MISC VARIABLES (DO NOT CHANGE VALUES)
|
||||
GameObject Target = null;
|
||||
GameObject Camera = null;
|
||||
GameObject Player = null;
|
||||
GameObject Barrel = null;
|
||||
Vector2 StartPosition;
|
||||
public GameObject LastKnownPlayerLocation = null;
|
||||
float DistanceFromPlayer;
|
||||
public List<GameObject> SuitablePositions;
|
||||
public List<GameObject> AllPositions;
|
||||
public List<GameObject> PatrolPositions;
|
||||
// start pathfinding
|
||||
float nextWaypointDistance = 5;
|
||||
Path path = null;
|
||||
int currentWaypoint = 0;
|
||||
bool reachedEndOfPath = false;
|
||||
// end pathfinding
|
||||
#endregion
|
||||
|
||||
#region CONDITIONS/GENERAL INFORMATION
|
||||
bool PositionRecomputeLock = false;
|
||||
public bool TargetingPlayer = false;
|
||||
public bool CurrentlyReloading = false;
|
||||
bool PatrolLock = false;
|
||||
bool Lock = false;
|
||||
bool MoveLock = false;
|
||||
bool FireLock = false;
|
||||
bool DashLock = false;
|
||||
bool TeleportLock = true;
|
||||
bool CurrentlyMovingToNextPatrolTarget = false;
|
||||
float DesiredDistance;
|
||||
public int WeaponCurrentMagazineAmmount;
|
||||
public int NumberOfHitsPerMag = 0;
|
||||
float BarrelAngle;
|
||||
bool Primed = false; // For self-explosion
|
||||
|
||||
#endregion
|
||||
|
||||
#region ENEMY STATS (Changeable in Unity)
|
||||
public float Speed = 1f; // In relation to player's walking speed
|
||||
public float JumpHeight = 1.5f; // In relation to player's regular jump height
|
||||
public float Health = 100;
|
||||
public float MinumumDistance = 5f;
|
||||
public float PatrolDistance = 10;
|
||||
public int PlayerDetectionRange = 50;
|
||||
float PatrolCooldown;
|
||||
public float PatrolCooldownReset = 20.0f;
|
||||
float JumpCooldown;
|
||||
public float JumpCooldownReset = 1.0f;
|
||||
float FireCooldown;
|
||||
public float FireCooldownReset = 0.1f;
|
||||
float ReloadCooldown;
|
||||
public float ReloadCooldownReset = 5.0f;
|
||||
public float DashSpeed = 40f; // Strength of the dash
|
||||
float DashCooldown;
|
||||
public float DashCooldownReset = 4.0f;
|
||||
float TeleportCooldown;
|
||||
public float TeleportCooldownReset = 0.5f;
|
||||
public float HiddenTransparencyAmmount = 0.05f; // Strength of the cloaked transparency
|
||||
public int MaxBatteryCapacity = 30; // Depletes one every second it is out of the bay
|
||||
public int RechargeTime = 6000; //ms
|
||||
|
||||
// Capabiltiies
|
||||
public bool AbilityDash = false;
|
||||
public bool AbilityInvisible = false;
|
||||
public bool AbilityJump = true;
|
||||
public bool AbilityTeleport = false;
|
||||
public bool AbilityReloadAndMove = false;
|
||||
public bool AbilityMove = true;
|
||||
public bool AbilityDynamicRelocation = true;
|
||||
public bool AbilityExplodeOnContact = false;
|
||||
public bool AbilityExplodeNearPlayer = false;
|
||||
public bool AbilityExplodeOnDeath = false;
|
||||
public bool AbilityPlayerESP = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region WEAPON STATS (CHANGEABLE in Unity)
|
||||
|
||||
public GameObject EnemyProjectile;
|
||||
public string EnemyType = "GROUND"; // Options: "GROUND", "AIR"
|
||||
public string WeaponType = "RANGED"; // Options: "RANGED", "ROCKET", "PARTICLE", "MELEE", "GRENADE", "NONE"
|
||||
public int WeaponDamage = 5; // Damage per hit
|
||||
public float WeaponRandomSpread = 7.5f; // Random direction of lanched projectiles
|
||||
public int WeaponRange = 15; // Maximum range of the projectile before it drops off
|
||||
public float WeaponProjectileSpeed = 40f; // Speed of launched projectiles
|
||||
public int WeaponMagazineSize = 20; // Number of shots the enemy will take before having to reloade
|
||||
|
||||
#endregion
|
||||
|
||||
#region COMPONENT REFERENCES
|
||||
Seeker seeker = null;
|
||||
Rigidbody2D rb = null;
|
||||
#endregion
|
||||
|
||||
#region ONCE THE ENEMY IS SPAWNED IN
|
||||
void Awake()
|
||||
{
|
||||
if (GetComponent<Seeker>())
|
||||
seeker = GetComponent<Seeker>();
|
||||
if (GetComponent<Rigidbody2D>())
|
||||
rb = GetComponent<Rigidbody2D>();
|
||||
|
||||
if (transform.Find("ReloadingIndicator"))
|
||||
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
if (transform.Find("PursuingIndicator"))
|
||||
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
|
||||
StartPosition = transform.position;
|
||||
|
||||
if (GameObject.FindGameObjectsWithTag("PossiblePositions").Count() > 0)
|
||||
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
|
||||
|
||||
if (EnemyType == "GROUND") // Configure settings for Ground enemies
|
||||
{
|
||||
foreach (GameObject pos in AllPositions)
|
||||
{
|
||||
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
|
||||
{
|
||||
PatrolPositions.Add(pos);
|
||||
}
|
||||
}
|
||||
|
||||
gameObject.layer = LayerMask.NameToLayer("Enemies");
|
||||
|
||||
foreach (Transform child in gameObject.transform)
|
||||
{
|
||||
child.gameObject.layer = LayerMask.NameToLayer("Enemies");
|
||||
}
|
||||
|
||||
if (PatrolPositions.Count() > 0)
|
||||
{
|
||||
Target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
|
||||
}
|
||||
else
|
||||
{
|
||||
Target = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (EnemyType == "AIR") // Configure settings for Air enemies
|
||||
{
|
||||
gameObject.layer = LayerMask.NameToLayer("FlyingEnemies");
|
||||
|
||||
foreach (Transform child in gameObject.transform)
|
||||
{
|
||||
child.gameObject.layer = LayerMask.NameToLayer("FlyingEnemies");
|
||||
}
|
||||
|
||||
rb.gravityScale = 0;
|
||||
if (GameObject.Find("FlyingTarget"))
|
||||
Target = Instantiate(GameObject.Find("FlyingTarget"), transform.position, Quaternion.identity);
|
||||
}
|
||||
|
||||
if (GameObject.FindGameObjectWithTag("MainCamera"))
|
||||
Camera = GameObject.FindGameObjectWithTag("MainCamera");
|
||||
if (GameObject.FindGameObjectWithTag("Player"))
|
||||
Player = GameObject.FindGameObjectWithTag("Player");
|
||||
|
||||
if (transform.Find("Barrel"))
|
||||
Barrel = transform.Find("Barrel").gameObject;
|
||||
|
||||
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
|
||||
DesiredDistance = WeaponRange - 5;
|
||||
|
||||
if (EnemyProjectile == null) // Automatically set enemy projectile if level designer did not
|
||||
{
|
||||
switch (WeaponType)
|
||||
{
|
||||
case "RANGED":
|
||||
EnemyProjectile = GameObject.Find("GameObjectFolder").transform.Find("EnemyProjectile").gameObject;
|
||||
break;
|
||||
|
||||
case "ROCKET":
|
||||
EnemyProjectile = GameObject.Find("GameObjectFolder").transform.Find("EnemyRocket").gameObject;
|
||||
break;
|
||||
|
||||
case "PARTICLE":
|
||||
EnemyProjectile = GameObject.Find("GameObjectFolder").transform.Find("EvilAura").gameObject;
|
||||
break;
|
||||
|
||||
case "GRENADE":
|
||||
EnemyProjectile = GameObject.Find("GameObjectFolder").transform.Find("Grenade").gameObject;
|
||||
break;
|
||||
|
||||
default:
|
||||
EnemyProjectile = GameObject.Find("GameObjectFolder").transform.Find("EnemyProjectile").gameObject;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
InvokeRepeating("UpdatePath", 0f, 0.1f);
|
||||
InvokeRepeating("PathfindingTimeout", 0f, 30);
|
||||
|
||||
// Initialize timers
|
||||
JumpCooldown = JumpCooldownReset;
|
||||
FireCooldown = FireCooldownReset;
|
||||
ReloadCooldown = ReloadCooldownReset;
|
||||
DashCooldown = DashCooldownReset;
|
||||
PatrolCooldown = 0;
|
||||
TeleportCooldown = TeleportCooldownReset;
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region INVOKE REPEATING METHODS
|
||||
// When enemy has reached the next node
|
||||
void OnPathComplete(Path p)
|
||||
{
|
||||
if (!p.error)
|
||||
{
|
||||
path = p;
|
||||
currentWaypoint = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Select next node
|
||||
void UpdatePath()
|
||||
{
|
||||
if (seeker.IsDone() && Target != null)
|
||||
{
|
||||
seeker.StartPath(rb.position, Target.transform.position, OnPathComplete);
|
||||
}
|
||||
}
|
||||
|
||||
// Pathfiniding Timeout
|
||||
void PathfindingTimeout()
|
||||
{
|
||||
if (Target != null && Vector2.Distance(transform.position, Target.transform.position) > 0.5 || LastKnownPlayerLocation == null)
|
||||
{
|
||||
LastKnownPlayerLocation = null;
|
||||
MoveNextPatrol();
|
||||
|
||||
if (AbilityTeleport && TeleportLock == false)
|
||||
{
|
||||
Teleport();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MAIN LOGIC
|
||||
void FixedUpdate()
|
||||
{
|
||||
#region DEATH
|
||||
if (Health <= 0)
|
||||
{
|
||||
if (AbilityExplodeNearPlayer == false && AbilityExplodeOnContact == false && AbilityExplodeOnDeath == false)
|
||||
{
|
||||
// Create carcas
|
||||
GameObject DeadBody;
|
||||
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
|
||||
DeadBody.GetComponent<Rigidbody2D>().gravityScale = 1.5f;
|
||||
Destroy(GameObject.Find(DeadBody.name).GetComponent<MasterEnemyAI>());
|
||||
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
|
||||
|
||||
foreach (Transform child in DeadBody.transform)
|
||||
{
|
||||
GameObject.Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
Destroy(gameObject);
|
||||
}
|
||||
else if (AbilityExplodeOnDeath == true)
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
}
|
||||
|
||||
// Explode when close to the player
|
||||
if (AbilityExplodeNearPlayer && Primed && Vector2.Distance(Player.transform.position, transform.position) <= 2)
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICONS
|
||||
|
||||
// See where the enemy wants to go (DEBUGGING ONLY)
|
||||
/*
|
||||
if (Target != null)
|
||||
{
|
||||
foreach (GameObject pos in AllPositions)
|
||||
{
|
||||
pos.GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
Target.GetComponent<SpriteRenderer>().enabled = true;
|
||||
}
|
||||
*/
|
||||
|
||||
if (TargetingPlayer && transform.Find("PursuingIndicator"))
|
||||
{
|
||||
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
|
||||
if (AbilityInvisible)
|
||||
{
|
||||
Cloak(false);
|
||||
}
|
||||
}
|
||||
else if (transform.Find("PursuingIndicator"))
|
||||
{
|
||||
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
if (AbilityInvisible)
|
||||
{
|
||||
Cloak(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (CurrentlyReloading && transform.Find("ReloadingIndicator"))
|
||||
{
|
||||
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
|
||||
}
|
||||
else if (transform.Find("ReloadingIndicator"))
|
||||
{
|
||||
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
|
||||
//if (90 <= angle || angle <= 270) // FIX THIS
|
||||
//{
|
||||
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
|
||||
//}
|
||||
#endregion
|
||||
|
||||
#region MISC PATHFINDING
|
||||
// Player ESP
|
||||
if (AbilityPlayerESP)
|
||||
{
|
||||
LastKnownPlayerLocation = Player;
|
||||
}
|
||||
|
||||
if (path == null)
|
||||
return;
|
||||
|
||||
if (Target == null)
|
||||
return;
|
||||
if (currentWaypoint >= path.vectorPath.Count)
|
||||
{
|
||||
reachedEndOfPath = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
reachedEndOfPath = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// Rotate barrel towards player
|
||||
if (Barrel != null) // PRevents error
|
||||
{
|
||||
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, BarrelAngle));
|
||||
Barrel.transform.rotation = Quaternion.RotateTowards(Barrel.transform.rotation, targetRotation, 200 * Time.deltaTime);
|
||||
}
|
||||
|
||||
#region TARGET DETERMINATION & PATROL & PLAYER DETECTION
|
||||
|
||||
// Check if the enemy is at the target location, used for moving to the next patrol target
|
||||
if (Vector2.Distance(transform.position, Target.transform.position) <= 1)
|
||||
{
|
||||
PatrolLock = false;
|
||||
MoveNextPatrol();
|
||||
}
|
||||
|
||||
// Patrol Countdown
|
||||
PatrolCooldown -= Time.deltaTime;
|
||||
if (PatrolCooldown <= UnityEngine.Random.Range(-3, 3))
|
||||
PatrolLock = false;
|
||||
else
|
||||
PatrolLock = true;
|
||||
|
||||
// If enemy has line of sight and is close enough the player is detected
|
||||
if (DetermineLineOfSight(gameObject, Player) && Vector2.Distance(transform.position, Player.transform.position) <= PlayerDetectionRange)
|
||||
{
|
||||
TargetingPlayer = true;
|
||||
PositionRecomputeLock = false;
|
||||
Primed = true; // for explosive enemies
|
||||
|
||||
// Get the last know player location by finding which of the positions is closest to the player
|
||||
if (LastKnownPlayerLocation == null)
|
||||
{
|
||||
LastKnownPlayerLocation = gameObject;
|
||||
}
|
||||
foreach (GameObject pos in AllPositions)
|
||||
{
|
||||
if (Vector2.Distance(Player.transform.position, pos.transform.position) < Vector2.Distance(Player.transform.position, LastKnownPlayerLocation.transform.position))
|
||||
{
|
||||
LastKnownPlayerLocation = pos;
|
||||
}
|
||||
}
|
||||
|
||||
// Angle barrel towards player
|
||||
if (Barrel != null)
|
||||
{
|
||||
BarrelAngle = Mathf.Atan2(Player.transform.position.y - Barrel.transform.position.y, Player.transform.position.x - Barrel.transform.position.x) * Mathf.Rad2Deg;
|
||||
}
|
||||
|
||||
}
|
||||
// Player has broken line of sight and the enemy will attempt to move to the last known location
|
||||
else if (LastKnownPlayerLocation != null)
|
||||
{
|
||||
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
|
||||
{
|
||||
PositionRecomputeLock = true;
|
||||
Target = LastKnownPlayerLocation;
|
||||
|
||||
if (AbilityTeleport && TeleportLock == false)
|
||||
{
|
||||
Teleport();
|
||||
}
|
||||
|
||||
}
|
||||
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(Player, gameObject) == false)
|
||||
{
|
||||
TargetingPlayer = false;
|
||||
LastKnownPlayerLocation = null;
|
||||
}
|
||||
|
||||
// Reset barrel rotation
|
||||
BarrelAngle = 0f;
|
||||
}
|
||||
// Go back to patrol move
|
||||
else
|
||||
{
|
||||
Primed = false;
|
||||
TargetingPlayer = false;
|
||||
|
||||
if (MoveLock == false)
|
||||
{
|
||||
MoveNextPatrol();
|
||||
}
|
||||
|
||||
// Reset barrel rotation
|
||||
BarrelAngle = 0f;
|
||||
}
|
||||
|
||||
if (PositionRecomputeLock == false)
|
||||
{
|
||||
// Catch desired distance error
|
||||
if (DesiredDistance <= MinumumDistance)
|
||||
{
|
||||
DesiredDistance = MinumumDistance + 1;
|
||||
}
|
||||
|
||||
// If the player moves away (CHANGE TARGET)
|
||||
if (Vector2.Distance(Target.transform.position, Player.transform.position) > DesiredDistance)
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
}
|
||||
|
||||
// If the player is too close to the target (CHANGE TARGET)
|
||||
if (Vector2.Distance(Target.transform.position, Player.transform.position) < MinumumDistance)
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
}
|
||||
|
||||
// If the target is on the other side of the player (CHANGE TARGET)
|
||||
//if (Vector2.Distance(transform.position, player.transform.position) < Vector2.Distance(target.transform.position, player.transform.position))
|
||||
//{
|
||||
// ComputeClosestPositionToPlayer();
|
||||
//}
|
||||
|
||||
// If the player is not within line of sight of the desired position (CHANGE TARGET)
|
||||
if (DetermineLineOfSight(Target, Player) == false)
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
}
|
||||
|
||||
if (TeleportLock == false && AbilityTeleport)
|
||||
{
|
||||
if (Vector2.Distance(transform.position, Target.transform.position) > 0.5)
|
||||
{
|
||||
Teleport();
|
||||
}
|
||||
}
|
||||
|
||||
// If the enemy reaches the target
|
||||
if (Vector2.Distance(Target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, Player))
|
||||
{
|
||||
if (EnemyType == "AIR")
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
}
|
||||
if (TeleportLock == false && AbilityTeleport)
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
Teleport();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MOVEMENT & GROUND DETECTION
|
||||
|
||||
//Detecting if the enemy has reached the ground
|
||||
if (EnemyType == "GROUND" && AbilityJump && GetComponentInChildren<GroundCheck>()) // Makes sure the enemy can jump before calculating
|
||||
{
|
||||
if (GetComponent<GroundCheck>().isGrounded == true)
|
||||
{
|
||||
JumpCooldown -= Time.deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
JumpCooldown = JumpCooldownReset;
|
||||
}
|
||||
}
|
||||
|
||||
// Decriment dash timer
|
||||
DashCooldown -= Time.deltaTime;
|
||||
if (DashCooldown <= 0 && Vector2.Distance(transform.position, Target.transform.position) > 2)
|
||||
DashLock = false;
|
||||
else
|
||||
DashLock = true;
|
||||
// Call Dash
|
||||
if (DashLock == false && AbilityDash)
|
||||
{
|
||||
Dash();
|
||||
}
|
||||
|
||||
// Decriment teleport timer
|
||||
TeleportCooldown -= Time.deltaTime;
|
||||
if (TeleportCooldown <= 0 && Vector2.Distance(transform.position, Target.transform.position) > 2)
|
||||
TeleportLock = false;
|
||||
else
|
||||
TeleportLock = true;
|
||||
|
||||
// Ground Movement
|
||||
if (MoveLock == false && EnemyType == "GROUND" && AbilityMove)
|
||||
{
|
||||
//FireLock = false;
|
||||
|
||||
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
|
||||
|
||||
if (GetComponent<GroundCheck>().isGrounded == true) // Movement while grounded
|
||||
{
|
||||
if (direction.x > 0) // Move right
|
||||
{
|
||||
if (TargetingPlayer)
|
||||
{
|
||||
if (Math.Abs(rb.linearVelocity.x) < Speed * 20) // Targeting player speed Cap
|
||||
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Math.Abs(rb.linearVelocity.x) < Speed * 5) // Wandering speed Cap
|
||||
rb.AddForce(new Vector2(Speed * 10, rb.linearVelocity.y));
|
||||
}
|
||||
}
|
||||
|
||||
if (direction.x < 0) // Move left
|
||||
{
|
||||
if (TargetingPlayer)
|
||||
{
|
||||
if (Math.Abs(rb.linearVelocity.x) < Speed * 20) // Targeting player speed Cap
|
||||
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Math.Abs(rb.linearVelocity.x) < Speed * 5) // Wandering speed Cap
|
||||
rb.AddForce(new Vector2(-1 * Speed * 10, rb.linearVelocity.y));
|
||||
}
|
||||
}
|
||||
|
||||
if (direction.y > 1f) // Wants to jump
|
||||
{
|
||||
Jump(direction.x);
|
||||
}
|
||||
}
|
||||
else // Movement while in the air
|
||||
{
|
||||
if (direction.x > 0) // Move right
|
||||
{
|
||||
rb.AddForce(new Vector2(Speed * 2, rb.linearVelocity.y));
|
||||
}
|
||||
|
||||
if (direction.x < 0) // Move left
|
||||
{
|
||||
rb.AddForce(new Vector2(-1 * Speed * 2, rb.linearVelocity.y));
|
||||
}
|
||||
}
|
||||
|
||||
// A* logic
|
||||
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
|
||||
|
||||
if (distance < nextWaypointDistance)
|
||||
{
|
||||
currentWaypoint++;
|
||||
}
|
||||
}
|
||||
// Air Movement
|
||||
if (MoveLock == false && EnemyType == "AIR" && AbilityMove)
|
||||
{
|
||||
Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] - rb.position).normalized;
|
||||
Vector2 force = direction * Speed * 20;
|
||||
|
||||
rb.AddForce(force);
|
||||
|
||||
// A* logic
|
||||
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
|
||||
|
||||
if (distance < nextWaypointDistance)
|
||||
{
|
||||
currentWaypoint++;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ATTACK
|
||||
|
||||
// Decriment timer
|
||||
FireCooldown -= Time.deltaTime;
|
||||
if (FireCooldown <= 0 && CurrentlyReloading == false)
|
||||
FireLock = false;
|
||||
else
|
||||
FireLock = true;
|
||||
|
||||
if (WeaponCurrentMagazineAmmount > 0 && FireLock == false && CurrentlyReloading == false && WeaponType != "NONE")
|
||||
{
|
||||
if (DetermineLineOfSight(gameObject, Player) == true && Vector2.Distance(transform.position, Player.transform.position) <= WeaponRange)
|
||||
{
|
||||
UseWeapon();
|
||||
}
|
||||
}
|
||||
else if (WeaponCurrentMagazineAmmount == 0 && CurrentlyReloading == false)
|
||||
{
|
||||
CurrentlyReloading = true;
|
||||
}
|
||||
|
||||
// Engage periodical reloading if player moves too far away and mag is low
|
||||
if (Vector2.Distance(transform.position, Player.transform.position) > WeaponRange + 5 && WeaponCurrentMagazineAmmount / WeaponMagazineSize < 0.75f)
|
||||
{
|
||||
ReloadCooldown = ReloadCooldownReset / 5; // Make reloading faster
|
||||
CurrentlyReloading = true;
|
||||
}
|
||||
|
||||
// Reloading
|
||||
if (CurrentlyReloading)
|
||||
{
|
||||
ReloadCooldown -= Time.deltaTime;
|
||||
if (ReloadCooldown <= 0)
|
||||
{
|
||||
ReloadCooldown = ReloadCooldownReset;
|
||||
CurrentlyReloading = false;
|
||||
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
|
||||
// Dynamic Relocation
|
||||
if (NumberOfHitsPerMag / WeaponMagazineSize < 0.5 && AbilityDynamicRelocation)
|
||||
DesiredDistance -= 5;
|
||||
NumberOfHitsPerMag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void UseWeapon()
|
||||
{
|
||||
FireCooldown = FireCooldownReset;
|
||||
|
||||
switch (WeaponType)
|
||||
{
|
||||
case "RANGED":
|
||||
// Create Projectile
|
||||
GameObject BulletInstance;
|
||||
BulletInstance = Instantiate(EnemyProjectile, Barrel.transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
|
||||
//BulletInstance.transform.parent = transform;
|
||||
|
||||
// Variables
|
||||
BulletInstance.GetComponent<EnemyProjectileScript>().WeaponDamage = WeaponDamage;
|
||||
BulletInstance.GetComponent<EnemyProjectileScript>().WeaponRange = WeaponRange;
|
||||
|
||||
// Send it on it's way
|
||||
BulletInstance.GetComponent<Rigidbody2D>().linearVelocity = BulletInstance.transform.forward * -1 * WeaponProjectileSpeed;
|
||||
BulletInstance.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, BulletInstance.transform.forward) - 90));
|
||||
break;
|
||||
|
||||
case "ROCKET":
|
||||
|
||||
// Create Rocket
|
||||
GameObject Rocket;
|
||||
Rocket = Instantiate(EnemyProjectile, Barrel.transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
|
||||
|
||||
// Variables
|
||||
Rocket.GetComponent<EnemyRocket>().WeaponDamage = WeaponDamage;
|
||||
Rocket.GetComponent<EnemyRocket>().duration = 30;
|
||||
|
||||
// Send it on its way
|
||||
Rocket.GetComponent<Rigidbody2D>().linearVelocity = Rocket.transform.forward * -1 * WeaponProjectileSpeed;
|
||||
Rocket.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, Rocket.transform.forward) - 90));
|
||||
|
||||
break;
|
||||
|
||||
case "PARTICLE":
|
||||
|
||||
// Create particle
|
||||
GameObject ParticleWeapon;
|
||||
|
||||
ParticleWeapon = Instantiate(EnemyProjectile, new Vector3(Barrel.transform.position.x + UnityEngine.Random.Range(-0.5f, 0.5f), Barrel.transform.position.y + UnityEngine.Random.Range(-0.5f, 0.5f), EnemyProjectile.transform.position.z), Quaternion.identity);
|
||||
ParticleWeapon.GetComponent<Rigidbody2D>().linearVelocity = new Vector2(transform.position.x - Player.transform.position.x + UnityEngine.Random.Range(-WeaponRandomSpread, WeaponRandomSpread), transform.position.y - Player.transform.position.y + UnityEngine.Random.Range(-WeaponRandomSpread, WeaponRandomSpread)).normalized * 1.25f * WeaponRange * -1;
|
||||
|
||||
// Set variables
|
||||
ParticleWeapon.GetComponent<EnemyParticleWeapon>().destroy = true;
|
||||
ParticleWeapon.GetComponent<EnemyParticleWeapon>().opacity = true;
|
||||
ParticleWeapon.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
|
||||
|
||||
break;
|
||||
|
||||
case "MELEE":
|
||||
|
||||
GameObject.Find("GameData").GetComponent<GameData>().CurrentHealth -= WeaponDamage;
|
||||
|
||||
break;
|
||||
|
||||
case "GRENADE":
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.Log("Invalid or no weapon seleted.");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
WeaponCurrentMagazineAmmount--;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
// General Utility
|
||||
bool DetermineLineOfSight(GameObject object1, GameObject object2)
|
||||
{
|
||||
Vector3 RaycastStart = object1.transform.position;
|
||||
Vector3 RaycastDirection = (object2.transform.position - object1.transform.position).normalized;
|
||||
float RaycastDistance = Vector3.Distance(object2.transform.position, object1.transform.position);
|
||||
|
||||
if (Physics2D.Raycast(RaycastStart, RaycastDirection, RaycastDistance, LayerMask.GetMask("SolidGround")) == false)
|
||||
{
|
||||
Debug.DrawRay(RaycastStart, RaycastDirection * RaycastDistance);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Jump(float JumpDirection)
|
||||
{
|
||||
if (JumpCooldown <= 0 && AbilityJump)
|
||||
{
|
||||
JumpCooldown = JumpCooldownReset;
|
||||
rb.linearVelocity = new Vector2(rb.linearVelocity.x + JumpDirection, JumpHeight * 12);
|
||||
}
|
||||
}
|
||||
|
||||
// Part of the pursue cycle
|
||||
void ComputeClosestPositionToPlayer()
|
||||
{
|
||||
MoveLock = false;
|
||||
|
||||
if (EnemyType == "GROUND")
|
||||
{
|
||||
|
||||
SuitablePositions.Clear();
|
||||
foreach (GameObject query in AllPositions)
|
||||
{
|
||||
// Check the distance of the position
|
||||
if (Vector2.Distance(query.transform.position, Player.transform.position) < DesiredDistance && Vector2.Distance(query.transform.position, Player.transform.position) >= MinumumDistance)
|
||||
{
|
||||
// Check line of sight of the position
|
||||
if (DetermineLineOfSight(query, Player))
|
||||
{
|
||||
SuitablePositions.Add(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SuitablePositions.Count > 0)
|
||||
{
|
||||
Target = SuitablePositions[UnityEngine.Random.Range(0, SuitablePositions.Count)];
|
||||
|
||||
if (AbilityTeleport == false)
|
||||
{
|
||||
foreach (GameObject pos in SuitablePositions)
|
||||
{
|
||||
//Find the point that is closest to the enemy
|
||||
if (Vector2.Distance(transform.position, pos.transform.position) < Vector2.Distance(transform.position, Target.transform.position))
|
||||
{
|
||||
Target = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EnemyType == "AIR")
|
||||
{
|
||||
//if (DetermineLineOfSight(player, gameObject))
|
||||
//{
|
||||
Target.transform.position = new Vector2((Player.transform.position.x + UnityEngine.Random.Range(-MinumumDistance, MinumumDistance)), (Player.transform.position.y + MinumumDistance + UnityEngine.Random.Range(-5, 0)));
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
// Part of the patrol cycle
|
||||
void MoveNextPatrol() // Determine the next place to move to
|
||||
{
|
||||
if (PatrolLock == false)
|
||||
{
|
||||
PatrolCooldown = PatrolCooldownReset;
|
||||
PositionRecomputeLock = true;
|
||||
LastKnownPlayerLocation = null;
|
||||
DesiredDistance = WeaponRange - 5;
|
||||
|
||||
if (EnemyType == "GROUND")
|
||||
{
|
||||
//Find Random Position nearby
|
||||
if (PatrolPositions.Count > 1)
|
||||
Target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
|
||||
}
|
||||
|
||||
if (EnemyType == "AIR")
|
||||
{
|
||||
//Find Random Position nearby
|
||||
Target.transform.position = new Vector2((StartPosition.x + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)), (StartPosition.y + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Explode
|
||||
void Explode()
|
||||
{
|
||||
// Shake Camera
|
||||
Camera.GetComponent<CameraMovement>().shakeCamera(0.8f, 0.5f);
|
||||
|
||||
// Create Explosion
|
||||
GameObject Explosion;
|
||||
Explosion = Instantiate(GameObject.Find("Explosion"), new Vector3(transform.position.x, transform.position.y, GameObject.Find("Explosion").transform.position.z), Quaternion.identity);
|
||||
Explosion.transform.rotation = Quaternion.Euler(Vector3.forward);
|
||||
|
||||
// Set Variables
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().destroy = true;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().opacity = true;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().timer = 3;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
|
||||
|
||||
// Destroy Flying Target
|
||||
//if (EnemyType == "AIR")
|
||||
//{
|
||||
// Destroy(target);
|
||||
//}
|
||||
|
||||
//gameObject.GetComponent<MasterEnemyAI>().enabled = false;
|
||||
|
||||
// Destroy GameObject
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
void Cloak(bool state)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, HiddenTransparencyAmmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
void Dash()
|
||||
{
|
||||
DashCooldown = DashCooldownReset;
|
||||
// Perform dash
|
||||
if (AbilityPlayerESP)
|
||||
rb.linearVelocity = new Vector2(transform.position.x - Player.transform.position.x, transform.position.y - Player.transform.position.y).normalized * DashSpeed * -1;
|
||||
else
|
||||
rb.linearVelocity = new Vector2(transform.position.x - Target.transform.position.x, transform.position.y - Target.transform.position.y).normalized * DashSpeed * -1;
|
||||
}
|
||||
|
||||
void Teleport()
|
||||
{
|
||||
TeleportCooldown = TeleportCooldownReset;
|
||||
transform.position = Target.transform.position;
|
||||
}
|
||||
|
||||
// On contact
|
||||
void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
if (Primed && AbilityExplodeOnContact)
|
||||
{
|
||||
if (collision.gameObject.layer == LayerMask.NameToLayer("SolidGround") || collision.gameObject.layer == LayerMask.NameToLayer("Enemies") || collision.gameObject.layer == LayerMask.NameToLayer("Player"))
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c2fe015b31da6b409479a7d804d4c67
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 5
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
uid://cwlkexjl6d5yb
|
||||
@@ -0,0 +1,946 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Pathfinding;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
// Designed by the goat Jacob Weedman
|
||||
// Use on any basic enemy
|
||||
//
|
||||
// Configure to your likeing
|
||||
// Not all options apply with every configuration
|
||||
//
|
||||
// PREREQUISITES
|
||||
// 1. The "Seeker" script from the A* pathfinding library must be attatched to the same game object
|
||||
// 2. A Rigidbody2D component must be attatched to the same game object
|
||||
// 3. A _Collider2D component must be attatched to the same game object
|
||||
// 4. Various game objects are required to be in the scene in order for this to function properly
|
||||
// 5. Various children game objects are required in order for this to funciton properly
|
||||
|
||||
public class MasterEnemyAIOld : MonoBehaviour
|
||||
{
|
||||
|
||||
#region MISC VARIABLES (DO NOT CHANGE VALUES)
|
||||
GameObject target;
|
||||
GameObject Camera;
|
||||
float nextWaypointDistance = 5;
|
||||
Path path;
|
||||
int currentWaypoint = 0;
|
||||
bool reachedEndOfPath = false;
|
||||
GameObject player;
|
||||
GameObject barrel;
|
||||
public List<GameObject> SuitablePositions;
|
||||
public List<GameObject> AllPositions;
|
||||
float DistanceFromPlayer;
|
||||
Vector2 StartPosition;
|
||||
public List<GameObject> PatrolPositions;
|
||||
public GameObject LastKnownPlayerLocation;
|
||||
Transform DroneBayLocation;
|
||||
#endregion
|
||||
|
||||
#region CONDITIONS/GENERAL INFORMATION
|
||||
public bool targetingPlayer = false;
|
||||
public bool inFiringCycle = false;
|
||||
bool currentlyReloading = false;
|
||||
bool currentlyPatrolling;
|
||||
bool canJump = true;
|
||||
bool canMove = true; // Prevent all movement
|
||||
bool canPursue = false; // Follow player
|
||||
bool canFire = true;
|
||||
bool canDash = true;
|
||||
bool currentlyMovingToNextPatrolTarget = false;
|
||||
float DesiredDistance;
|
||||
public int WeaponCurrentMagazineAmmount;
|
||||
public int NumberOfHitsPerMag = 0;
|
||||
bool canTeleport = true;
|
||||
float angle;
|
||||
bool currentlyInDroneBay = false;
|
||||
int CurrentBatteryCapacity;
|
||||
bool currentlyTravelingToDroneBay = false;
|
||||
bool currentlyRecharging = false;
|
||||
bool primed = false; // For self-explosion
|
||||
|
||||
#endregion
|
||||
|
||||
#region ENEMY STATS (Changeable in Unity)
|
||||
public float Speed = 1f; // In relation to player's walking speed
|
||||
public float JumpHeight = 1f; // In relation to player's regular jump height
|
||||
public float Health = 100;
|
||||
public float MinumumDistance = 5f;
|
||||
public float PatrolDistance = 15;
|
||||
public int PatrolStallTime = 2000; //ms
|
||||
public int PlayerDetectionRange = 20;
|
||||
public float dashSpeed = 40f; // Strength of the dash
|
||||
public int dashDelay = 1000;
|
||||
public float HiddenTransparencyAmmount = 0.05f; // Strength of the cloaked transparency
|
||||
public int TeleportCooldown = 500; //ms
|
||||
public int MaxBatteryCapacity = 30; // Depletes one every second it is out of the bay
|
||||
public int RechargeTime = 6000; //ms
|
||||
|
||||
// Capabiltiies
|
||||
public bool AbilityDash = false;
|
||||
public bool AbilityInvisible = false;
|
||||
public bool AbilityJump = false;
|
||||
public bool AbilityTeleport = false;
|
||||
public bool AbilityShootAndMove = false;
|
||||
public bool AbilityReloadAndMove = false;
|
||||
public bool AbilityMove = false;
|
||||
public bool AbilityDynamicRelocation = false;
|
||||
public bool AbilityExplodeOnContact = false;
|
||||
public bool AbilityExplodeNearPlayer = false;
|
||||
public bool AbilityExplodeOnDeath = false;
|
||||
public bool AbilityPlayerESP = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region WEAPON STATS (CHANGEABLE in Unity)
|
||||
|
||||
public GameObject EnemyProjectile;
|
||||
public string EnemyType = "GROUND"; // Options: "GROUND", "AIR"
|
||||
public bool IsDrone = false;
|
||||
public string WeaponType = "RANGED"; // Options: "RANGED", "ROCKET", "PARTICLE", "MELEE", "GRENADE", "NONE"
|
||||
public int WeaponDamage = 5; // Damage per hit
|
||||
public int WeaponFireRate = 300; // 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
|
||||
#endregion
|
||||
|
||||
#region COMPONENT REFERENCES
|
||||
Seeker seeker;
|
||||
Rigidbody2D rb;
|
||||
#endregion
|
||||
|
||||
#region ONCE THE ENEMY IS SPAWNED IN
|
||||
void Awake()
|
||||
{
|
||||
seeker = GetComponent<Seeker>();
|
||||
rb = GetComponent<Rigidbody2D>();
|
||||
|
||||
if (transform.Find("ReloadingIndicator")) // Ensures Reloading Indicator Exists
|
||||
{
|
||||
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
if (transform.Find("PursuingIndicator")) // Ensures Pursuing Indicator Exists
|
||||
{
|
||||
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
|
||||
StartPosition = transform.position;
|
||||
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
|
||||
|
||||
if (EnemyType == "GROUND") // Configure settings for Ground enemies
|
||||
{
|
||||
foreach (GameObject pos in AllPositions)
|
||||
{
|
||||
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
|
||||
{
|
||||
PatrolPositions.Add(pos);
|
||||
}
|
||||
}
|
||||
|
||||
gameObject.layer = LayerMask.NameToLayer("Enemies");
|
||||
|
||||
foreach (Transform child in gameObject.transform)
|
||||
{
|
||||
child.gameObject.layer = LayerMask.NameToLayer("Enemies");
|
||||
}
|
||||
|
||||
if (PatrolPositions.Count() > 0) // Catches error when the game object starts outside of the game area
|
||||
{
|
||||
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
|
||||
}
|
||||
else
|
||||
{
|
||||
target = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (EnemyType == "AIR") // Configure settings for Air enemies
|
||||
{
|
||||
gameObject.layer = LayerMask.NameToLayer("FlyingEnemies");
|
||||
|
||||
foreach (Transform child in gameObject.transform)
|
||||
{
|
||||
child.gameObject.layer = LayerMask.NameToLayer("FlyingEnemies");
|
||||
}
|
||||
|
||||
GetComponent<Rigidbody2D>().gravityScale = 0;
|
||||
target = Instantiate(GameObject.Find("FlyingTarget"), transform.position, Quaternion.identity);
|
||||
}
|
||||
|
||||
Camera = GameObject.FindGameObjectWithTag("MainCamera");
|
||||
player = GameObject.FindGameObjectWithTag("Player");
|
||||
|
||||
if (transform.Find("Barrel")) // Ensures barrel exists
|
||||
{
|
||||
barrel = transform.Find("Barrel").gameObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
barrel = null;
|
||||
}
|
||||
|
||||
LastKnownPlayerLocation = null;
|
||||
|
||||
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
|
||||
DesiredDistance = WeaponRange - 5;
|
||||
|
||||
// Set default EnemyProjectile if it starts as NULL (DEV forgot to change it lmao)
|
||||
if (EnemyProjectile == null)
|
||||
{
|
||||
EnemyProjectile = GameObject.Find("GameObjectFolder").transform.Find("EnemyProjectile").gameObject;
|
||||
}
|
||||
|
||||
|
||||
InvokeRepeating("UpdatePath", 0f, 0.1f);
|
||||
InvokeRepeating("PathfindingTimeout", 0f, 10);
|
||||
|
||||
if (IsDrone == true)
|
||||
{
|
||||
InvokeRepeating("BatteryDrain", 0f, 1);
|
||||
CurrentBatteryCapacity = MaxBatteryCapacity;
|
||||
DroneBayLocation = transform.parent.transform;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region INVOKE REPEATING METHODS
|
||||
// When enemy has reached the next node
|
||||
void OnPathComplete(Path p)
|
||||
{
|
||||
if (!p.error)
|
||||
{
|
||||
path = p;
|
||||
currentWaypoint = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Select next node
|
||||
void UpdatePath()
|
||||
{
|
||||
if (seeker.IsDone() && target != null)
|
||||
{
|
||||
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
|
||||
}
|
||||
}
|
||||
|
||||
// Pathfiniding Timeout
|
||||
void PathfindingTimeout()
|
||||
{
|
||||
if (target != null && Vector2.Distance(transform.position, target.transform.position) > 0.5 || LastKnownPlayerLocation == null)
|
||||
{
|
||||
//target = gameObject;
|
||||
MoveNextPatrol();
|
||||
|
||||
if (AbilityTeleport && canTeleport)
|
||||
{
|
||||
Teleport();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Battery Drain
|
||||
void BatteryDrain()
|
||||
{
|
||||
if (currentlyInDroneBay == false)
|
||||
{
|
||||
CurrentBatteryCapacity -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MAIN LOGIC
|
||||
void FixedUpdate()
|
||||
{
|
||||
#region DEATH
|
||||
if (Health <= 0)
|
||||
{
|
||||
if (AbilityExplodeNearPlayer == false && AbilityExplodeOnContact == false && AbilityExplodeOnDeath == false)
|
||||
{
|
||||
// Create carcas
|
||||
GameObject DeadBody;
|
||||
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
|
||||
DeadBody.GetComponent<Rigidbody2D>().gravityScale = 1.5f;
|
||||
Destroy(GameObject.Find(DeadBody.name).GetComponent<MasterEnemyAI>());
|
||||
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
|
||||
|
||||
foreach (Transform child in DeadBody.transform)
|
||||
{
|
||||
GameObject.Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
Destroy(gameObject);
|
||||
}
|
||||
else if (AbilityExplodeOnDeath == true)
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
}
|
||||
|
||||
// Explode when close to the player
|
||||
if (AbilityExplodeNearPlayer && primed && Vector2.Distance(player.transform.position, transform.position) <= 2)
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICONS
|
||||
|
||||
// See where the enemy wants to go (DEBUGGING ONLY)
|
||||
/*
|
||||
if (target != null)
|
||||
{
|
||||
foreach (GameObject pos in AllPositions)
|
||||
{
|
||||
pos.GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
target.GetComponent<SpriteRenderer>().enabled = true;
|
||||
}
|
||||
*/
|
||||
|
||||
if (targetingPlayer && transform.Find("PursuingIndicator"))
|
||||
{
|
||||
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
|
||||
if (AbilityInvisible)
|
||||
{
|
||||
Cloak(false);
|
||||
}
|
||||
}
|
||||
else if (transform.Find("PursuingIndicator"))
|
||||
{
|
||||
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
if (AbilityInvisible)
|
||||
{
|
||||
Cloak(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentlyReloading && transform.Find("ReloadingIndicator"))
|
||||
{
|
||||
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
|
||||
}
|
||||
else if (transform.Find("ReloadingIndicator"))
|
||||
{
|
||||
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
|
||||
//if (90 <= angle || angle <= 270) // FIX THIS
|
||||
//{
|
||||
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
|
||||
//}
|
||||
#endregion
|
||||
|
||||
#region MISC PATHFINDING
|
||||
// Player ESP
|
||||
if (AbilityPlayerESP)
|
||||
{
|
||||
LastKnownPlayerLocation = player;
|
||||
}
|
||||
|
||||
if (path == null)
|
||||
return;
|
||||
|
||||
if (target == null)
|
||||
return;
|
||||
if (currentWaypoint >= path.vectorPath.Count)
|
||||
{
|
||||
reachedEndOfPath = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
reachedEndOfPath = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region WEAPONATTACK
|
||||
// Check if enemy has line of sight on the player & if they are in the acceptable range
|
||||
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && WeaponType != "NONE")
|
||||
{
|
||||
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange)
|
||||
{
|
||||
UseWeapon();
|
||||
}
|
||||
}
|
||||
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
|
||||
{
|
||||
ReloadWeapon();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MOVEMENT
|
||||
|
||||
// Call Dash
|
||||
if (DetermineLineOfSight(gameObject, player) && targetingPlayer && canDash == true && AbilityDash)
|
||||
{
|
||||
Dash();
|
||||
}
|
||||
|
||||
// Ground Movement
|
||||
if (canMove == true && EnemyType == "GROUND" && AbilityMove)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
}
|
||||
// Air Movement
|
||||
if (canMove == true && EnemyType == "AIR" && AbilityMove)
|
||||
{
|
||||
Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] - rb.position).normalized;
|
||||
Vector2 force = direction * Speed * 20;
|
||||
|
||||
rb.AddForce(force);
|
||||
|
||||
// A* logic
|
||||
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
|
||||
|
||||
if (distance < nextWaypointDistance)
|
||||
{
|
||||
currentWaypoint++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region GROUND DETECTION
|
||||
//Detecting if the enemy has reached the ground
|
||||
if (EnemyType == "GROUND" && AbilityJump && GetComponentInChildren<GroundCheck>()) // Makes sure the enemy can jump before calculating
|
||||
{
|
||||
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
|
||||
{
|
||||
canJump = true;
|
||||
if (inFiringCycle == false)
|
||||
{
|
||||
canFire = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
canJump = false;
|
||||
canFire = false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PATROL & DETECTION
|
||||
|
||||
// Check if the enemy is at the target location, used for moving to the next patrol target
|
||||
if (Vector2.Distance(transform.position, target.transform.position) <= 1)
|
||||
{
|
||||
currentlyMovingToNextPatrolTarget = false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Angle barrel towards player
|
||||
if (barrel != null) // Prevents Error
|
||||
{
|
||||
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 (AbilityTeleport && canTeleport)
|
||||
{
|
||||
Teleport();
|
||||
}
|
||||
|
||||
}
|
||||
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
|
||||
{
|
||||
primed = false;
|
||||
//LastKnownPlayerLocation = gameObject;
|
||||
currentlyPatrolling = true;
|
||||
targetingPlayer = false;
|
||||
|
||||
if (IsDrone)
|
||||
{
|
||||
ReturnToDroneBay();
|
||||
}
|
||||
else if (canMove == true && currentlyMovingToNextPatrolTarget == false)
|
||||
{
|
||||
MoveNextPatrol();
|
||||
}
|
||||
|
||||
// Reset barrel rotation
|
||||
angle = 0f;
|
||||
}
|
||||
|
||||
// Rotate barrel towards player
|
||||
if (barrel != null) // PRevents error
|
||||
{
|
||||
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
|
||||
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 200 * Time.deltaTime);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 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 (canTeleport && AbilityTeleport)
|
||||
{
|
||||
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
|
||||
{
|
||||
Teleport();
|
||||
}
|
||||
}
|
||||
|
||||
// If the enemy reaches the target
|
||||
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
|
||||
{
|
||||
if (EnemyType == "AIR")
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
}
|
||||
if (canTeleport && AbilityTeleport)
|
||||
{
|
||||
ComputeClosestPositionToPlayer();
|
||||
Teleport();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region USE WEAPON METHOD
|
||||
// Use Weapon
|
||||
async Awaitable UseWeapon()
|
||||
{
|
||||
if (AbilityShootAndMove == false)
|
||||
{
|
||||
canMove = false;
|
||||
}
|
||||
|
||||
canFire = false;
|
||||
inFiringCycle = true;
|
||||
|
||||
switch (WeaponType)
|
||||
{
|
||||
case "RANGED":
|
||||
// Create Projectile
|
||||
GameObject BulletInstance;
|
||||
BulletInstance = Instantiate(EnemyProjectile, barrel.transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
|
||||
//BulletInstance.transform.parent = transform;
|
||||
|
||||
// Variables
|
||||
BulletInstance.GetComponent<EnemyProjectileScript>().WeaponDamage = WeaponDamage;
|
||||
BulletInstance.GetComponent<EnemyProjectileScript>().WeaponRange = WeaponRange;
|
||||
|
||||
// Send it on it's way
|
||||
BulletInstance.GetComponent<Rigidbody2D>().linearVelocity = BulletInstance.transform.forward * -1 * WeaponProjectileSpeed;
|
||||
BulletInstance.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, BulletInstance.transform.forward) - 90));
|
||||
break;
|
||||
|
||||
case "ROCKET":
|
||||
|
||||
// Create Rocket
|
||||
GameObject Rocket;
|
||||
Rocket = Instantiate(EnemyProjectile, barrel.transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
|
||||
|
||||
// Variables
|
||||
Rocket.GetComponent<EnemyRocket>().WeaponDamage = WeaponDamage;
|
||||
Rocket.GetComponent<EnemyRocket>().duration = 30;
|
||||
|
||||
// Send it on its way
|
||||
Rocket.GetComponent<Rigidbody2D>().linearVelocity = Rocket.transform.forward * -1 * WeaponProjectileSpeed;
|
||||
Rocket.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, Rocket.transform.forward) - 90));
|
||||
|
||||
break;
|
||||
|
||||
case "PARTICLE":
|
||||
|
||||
// Create particle
|
||||
GameObject ParticleWeapon;
|
||||
|
||||
ParticleWeapon = Instantiate(EnemyProjectile, new Vector3(barrel.transform.position.x + UnityEngine.Random.Range(-0.5f, 0.5f), barrel.transform.position.y + UnityEngine.Random.Range(-0.5f, 0.5f), EnemyProjectile.transform.position.z), Quaternion.identity);
|
||||
ParticleWeapon.GetComponent<Rigidbody2D>().linearVelocity = new Vector2(transform.position.x - player.transform.position.x + UnityEngine.Random.Range(-WeaponRandomSpread, WeaponRandomSpread), transform.position.y - player.transform.position.y + UnityEngine.Random.Range(-WeaponRandomSpread, WeaponRandomSpread)).normalized * 1.25f * WeaponRange * -1;
|
||||
|
||||
// Set variables
|
||||
ParticleWeapon.GetComponent<EnemyParticleWeapon>().destroy = true;
|
||||
ParticleWeapon.GetComponent<EnemyParticleWeapon>().opacity = true;
|
||||
ParticleWeapon.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
|
||||
|
||||
break;
|
||||
|
||||
case "MELEE":
|
||||
|
||||
GameObject.Find("GameData").GetComponent<GameData>().CurrentHealth -= WeaponDamage;
|
||||
|
||||
break;
|
||||
|
||||
case "GRENADE":
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.Log("Invalid or no weapon seleted.");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
WeaponCurrentMagazineAmmount--;
|
||||
await Awaitable.WaitForSecondsAsync(WeaponFireRate/1000);
|
||||
|
||||
canFire = true;
|
||||
canMove = true;
|
||||
inFiringCycle = false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MISC METHODS
|
||||
|
||||
async Awaitable Dash()
|
||||
{
|
||||
canDash = false;
|
||||
|
||||
|
||||
await Awaitable.WaitForSecondsAsync(dashDelay/1000); // Dash delay ms
|
||||
|
||||
// Flash Red
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 0f, 0f, 1f);
|
||||
|
||||
await Awaitable.WaitForSecondsAsync(500/1000);
|
||||
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, 1f);
|
||||
|
||||
await Awaitable.WaitForSecondsAsync(500/1000);
|
||||
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 0f, 0f, 1f);
|
||||
|
||||
await Awaitable.WaitForSecondsAsync(500/1000);
|
||||
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, 1f);
|
||||
|
||||
await Awaitable.WaitForSecondsAsync(500/1000);
|
||||
|
||||
// Perform dash
|
||||
rb.linearVelocity = new Vector2(transform.position.x - player.transform.position.x, transform.position.y - player.transform.position.y).normalized * dashSpeed * -1;
|
||||
|
||||
canDash = true;
|
||||
}
|
||||
|
||||
// Reload Weapon
|
||||
async Awaitable ReloadWeapon()
|
||||
{
|
||||
canFire = false;
|
||||
|
||||
if (AbilityReloadAndMove == false)
|
||||
{
|
||||
canMove = false;
|
||||
}
|
||||
|
||||
//play reload animation
|
||||
currentlyReloading = true;
|
||||
await Awaitable.WaitForSecondsAsync(WeaponReloadTime/1000);
|
||||
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
|
||||
currentlyReloading = false;
|
||||
|
||||
if (NumberOfHitsPerMag / WeaponMagazineSize < 0.5 && AbilityDynamicRelocation)
|
||||
{
|
||||
DesiredDistance -= 5;
|
||||
}
|
||||
|
||||
NumberOfHitsPerMag = 0;
|
||||
|
||||
canFire = true;
|
||||
canMove = true;
|
||||
}
|
||||
|
||||
// Part of the patrol cycle
|
||||
async Awaitable MoveNextPatrol()
|
||||
{
|
||||
LastKnownPlayerLocation = null;
|
||||
DesiredDistance = WeaponRange - 5;
|
||||
|
||||
canPursue = false;
|
||||
currentlyMovingToNextPatrolTarget = true;
|
||||
|
||||
if (EnemyType == "GROUND")
|
||||
{
|
||||
//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 Awaitable.WaitForSecondsAsync(PatrolStallTime/1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (EnemyType == "AIR")
|
||||
{
|
||||
//Find Random Position nearby
|
||||
target.transform.position = new Vector2((StartPosition.x + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)), (StartPosition.y + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)));
|
||||
await Task.Delay(PatrolStallTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Teleport
|
||||
async Awaitable Teleport()
|
||||
{
|
||||
canTeleport = false;
|
||||
transform.position = target.transform.position;
|
||||
await Awaitable.WaitForSecondsAsync(TeleportCooldown/1000);
|
||||
canTeleport = true;
|
||||
}
|
||||
|
||||
// Cloak
|
||||
void Cloak(bool state)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, HiddenTransparencyAmmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
if (EnemyType == "GROUND")
|
||||
{
|
||||
|
||||
SuitablePositions.Clear();
|
||||
foreach (GameObject query in AllPositions)
|
||||
{
|
||||
// Check the distance of the position
|
||||
if (Vector2.Distance(query.transform.position, player.transform.position) < DesiredDistance && Vector2.Distance(query.transform.position, player.transform.position) >= MinumumDistance)
|
||||
{
|
||||
// Check line of sight of the position
|
||||
if (DetermineLineOfSight(query, player))
|
||||
{
|
||||
SuitablePositions.Add(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SuitablePositions.Count > 0)
|
||||
{
|
||||
target = SuitablePositions[UnityEngine.Random.Range(0, SuitablePositions.Count)];
|
||||
|
||||
if (AbilityTeleport == false)
|
||||
{
|
||||
foreach (GameObject pos in SuitablePositions)
|
||||
{
|
||||
//Find the point that is closest to the enemy
|
||||
if (Vector2.Distance(transform.position, pos.transform.position) < Vector2.Distance(transform.position, target.transform.position))
|
||||
{
|
||||
target = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EnemyType == "AIR")
|
||||
{
|
||||
//if (DetermineLineOfSight(player, gameObject))
|
||||
//{
|
||||
target.transform.position = new Vector2((player.transform.position.x + UnityEngine.Random.Range(-MinumumDistance, MinumumDistance)), (player.transform.position.y + MinumumDistance + UnityEngine.Random.Range(-5, 0)));
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform jump
|
||||
async Awaitable JumpMethod()
|
||||
{
|
||||
if (canJump == true && AbilityJump)
|
||||
{
|
||||
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
|
||||
canJump = false;
|
||||
await Awaitable.WaitForSecondsAsync(500/1000);
|
||||
}
|
||||
}
|
||||
|
||||
// Return To Drone Bay
|
||||
async Awaitable ReturnToDroneBay()
|
||||
{
|
||||
if (currentlyTravelingToDroneBay == false && currentlyInDroneBay == false)
|
||||
{
|
||||
currentlyTravelingToDroneBay = true;
|
||||
target.transform.position = DroneBayLocation.position;
|
||||
}
|
||||
}
|
||||
|
||||
// Recharge
|
||||
async Awaitable Recharge()
|
||||
{
|
||||
currentlyRecharging = true;
|
||||
canMove = false;
|
||||
canFire = false;
|
||||
seeker.enabled = false;
|
||||
transform.position = DroneBayLocation.position;
|
||||
rb.linearVelocity = Vector3.zero;
|
||||
currentlyTravelingToDroneBay = false;
|
||||
await Awaitable.WaitForSecondsAsync(RechargeTime/1000);
|
||||
CurrentBatteryCapacity = MaxBatteryCapacity;
|
||||
currentlyRecharging = false;
|
||||
canFire = true;
|
||||
}
|
||||
|
||||
// Explode
|
||||
void Explode()
|
||||
{
|
||||
// Shake Camera
|
||||
Camera.GetComponent<CameraMovement>().shakeCamera(0.8f, 0.5f);
|
||||
|
||||
// Create Explosion
|
||||
GameObject Explosion;
|
||||
Explosion = Instantiate(GameObject.Find("Explosion"), new Vector3(transform.position.x, transform.position.y, GameObject.Find("Explosion").transform.position.z), Quaternion.identity);
|
||||
Explosion.transform.rotation = Quaternion.Euler(Vector3.forward);
|
||||
|
||||
// Set Variables
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().destroy = true;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().opacity = true;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().timer = 3;
|
||||
Explosion.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
|
||||
|
||||
// Destroy Flying Target
|
||||
//if (EnemyType == "AIR")
|
||||
//{
|
||||
// Destroy(target);
|
||||
//}
|
||||
|
||||
//gameObject.GetComponent<MasterEnemyAI>().enabled = false;
|
||||
|
||||
// Destroy GameObject
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
// On contact
|
||||
void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
if (primed && AbilityExplodeOnContact)
|
||||
{
|
||||
if (collision.gameObject.layer == LayerMask.NameToLayer("SolidGround") || collision.gameObject.layer == LayerMask.NameToLayer("Enemies") || collision.gameObject.layer == LayerMask.NameToLayer("Player"))
|
||||
{
|
||||
Explode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 480f622e764a4c54d9e7e2f48f7978f6
|
||||
@@ -0,0 +1 @@
|
||||
uid://bshg66l8hqjfa
|
||||
@@ -0,0 +1,32 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
// Designed by Jacob Weedman
|
||||
// Part of the "GAMESCRIPTS" required prefab
|
||||
|
||||
public class PossiblePositionsSetup : MonoBehaviour
|
||||
{
|
||||
public List<GameObject> groundList;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
//Setup List
|
||||
groundList = GameObject.FindGameObjectsWithTag("Ground").ToList();
|
||||
|
||||
//Iterate through each ground object
|
||||
foreach (GameObject ground in groundList)
|
||||
{
|
||||
float RemainingWidth = ground.transform.localScale.x;
|
||||
|
||||
while (RemainingWidth > (-1 * ground.transform.localScale.x))
|
||||
{
|
||||
GameObject position;
|
||||
position = Instantiate(GameObject.Find("PossiblePosition"), new Vector3((ground.transform.position.x + (GameObject.Find("PossiblePosition").transform.localScale.x / 4) - (RemainingWidth / 2)), (ground.transform.position.y + (GameObject.Find("PossiblePosition").transform.localScale.y / 2) + (ground.transform.localScale.y / 2)), ground.transform.position.z), ground.transform.rotation);
|
||||
position.transform.parent = ground.transform;
|
||||
RemainingWidth -= GameObject.Find("PossiblePosition").transform.localScale.x * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4dec8478c6d3efb48ab0d10ff7e0dc5e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 1
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
uid://d0q7qcne8ohje
|
||||
@@ -0,0 +1,70 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
//Designed by Jacob Weedman
|
||||
//Belongs to the "GameData" GameObject
|
||||
|
||||
public class GameData : MonoBehaviour
|
||||
{
|
||||
public static GameData Instance;
|
||||
|
||||
// Game Variables
|
||||
public string CharacterName; //
|
||||
public string CurrentSector;
|
||||
public string CurrentLevel;
|
||||
public float MaxHealth;
|
||||
public float CurrentHealth;
|
||||
public int LevelsCompleted;
|
||||
public int BossesDefeated;
|
||||
public int EnemiesKilled;
|
||||
public int TotalSkillPoints = 0;
|
||||
public int AvailableSkillPoints = 0;
|
||||
|
||||
// Sector transfer refrence for main endings
|
||||
public Dictionary<string, string> SectorTransferRefrence = new Dictionary<string, string>();
|
||||
|
||||
|
||||
//Changable setting while playing
|
||||
public static float CameraOffset = 5f;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
|
||||
// Set up refrence (names of the scenes) WIP
|
||||
SectorTransferRefrence.Add("Sector1Level1","Sector1Boss");
|
||||
SectorTransferRefrence.Add("Sector1Boss","Sector6Level1");
|
||||
SectorTransferRefrence.Add("Sector6Level1","Sector6Boss");
|
||||
SectorTransferRefrence.Add("Sector6Boss","Sector9Level1");
|
||||
SectorTransferRefrence.Add("Sector9Level1","Sector9Boss");
|
||||
SectorTransferRefrence.Add("Sector9Boss","Plane"); // From the plane the player chooses where to go
|
||||
SectorTransferRefrence.Add("Sector2Level1","Sector2Boss");
|
||||
SectorTransferRefrence.Add("Sector2Boss","Sector3Level1");
|
||||
SectorTransferRefrence.Add("Sector3Level1","Sector3Boss");
|
||||
SectorTransferRefrence.Add("Sector3Boss","Sector8Level1");
|
||||
SectorTransferRefrence.Add("Sector8Level1","Sector8Boss");
|
||||
SectorTransferRefrence.Add("Sector8Boss","Sector5Level1");
|
||||
SectorTransferRefrence.Add("Sector5Level1","Sector5Boss");
|
||||
SectorTransferRefrence.Add("Sector5Boss","Sector4Level1");
|
||||
SectorTransferRefrence.Add("Sector4Level1","Sector4Boss");
|
||||
SectorTransferRefrence.Add("Sector4Boss","Sector7Level1");
|
||||
SectorTransferRefrence.Add("Sector7Level1","Sector7Boss");
|
||||
SectorTransferRefrence.Add("SectorsS1Level1","SectorS1Boss");
|
||||
SectorTransferRefrence.Add("SectorsS1Boss","SectorS2Level1");
|
||||
SectorTransferRefrence.Add("SectorsS2Boss","Sector8Level1");
|
||||
|
||||
|
||||
//Initialize Variables
|
||||
CharacterName = null;
|
||||
CurrentLevel = null;
|
||||
MaxHealth = 100;
|
||||
CurrentHealth = 100;
|
||||
TotalSkillPoints = 0;
|
||||
AvailableSkillPoints = 0;
|
||||
LevelsCompleted = 0;
|
||||
BossesDefeated = 0;
|
||||
EnemiesKilled = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df6e2d19b2ac1664fbffd73cbd649528
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
uid://dyy1m668eky2s
|
||||
@@ -0,0 +1,74 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
// Designed by Jacob Weedman
|
||||
public class GameObjectButtonUI : MonoBehaviour
|
||||
{
|
||||
public string ButtonMode; // "MENU", "SCENE"
|
||||
public string DestinationScene;
|
||||
public string MenuName; // Name of the menu
|
||||
public bool StartMenuDisabled;
|
||||
|
||||
public GameObject MenuRefrence;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (ButtonMode == "MENU")
|
||||
{
|
||||
MenuRefrence = GameObject.Find(MenuName); // GameObject refrence for menu as it will otherwise not work when disabled
|
||||
|
||||
if (StartMenuDisabled && GameObject.Find(MenuName))
|
||||
{
|
||||
GameObject.Find(MenuName).SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnMouseOver()
|
||||
{
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, 0.5f);
|
||||
}
|
||||
|
||||
void OnMouseExit()
|
||||
{
|
||||
gameObject.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, 1f);
|
||||
}
|
||||
|
||||
void OnMouseDown()
|
||||
{
|
||||
switch (ButtonMode)
|
||||
{
|
||||
case "MENU":
|
||||
// Open or close UI Element
|
||||
try
|
||||
{
|
||||
// Switches the active state of the MenuGameObject every time the button is pressed
|
||||
MenuRefrence.SetActive(!MenuRefrence.activeSelf);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Debug.Log("Hey you! The button you just pressed is broken.");
|
||||
}
|
||||
break;
|
||||
case "SCENE":
|
||||
// Change Scene
|
||||
|
||||
try // Scene success
|
||||
{
|
||||
SceneManager.LoadScene(DestinationScene);
|
||||
}
|
||||
catch // Scene error
|
||||
{
|
||||
Debug.Log("Hey you! The button you just pressed is broken. It seems like the scene you selected does not exist or is not added to the build profile.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Error message
|
||||
Debug.Log("Hey you! The button you just pressed is broken. It seems like 'ButtonMode' variable is invalid.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2fdeedc0122b3e4fbcee5d5078fd118
|
||||
@@ -0,0 +1 @@
|
||||
uid://brh6ia8lqnra3
|
||||
@@ -0,0 +1,22 @@
|
||||
using UnityEngine;
|
||||
|
||||
// Designed by Jacob Weedman
|
||||
|
||||
public class GroundCheck : MonoBehaviour
|
||||
{
|
||||
public bool isGrounded;
|
||||
float PreviousVelocityY;
|
||||
float CurrentVelocityY = 0;
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
PreviousVelocityY = CurrentVelocityY;
|
||||
if (GetComponent<Rigidbody2D>())
|
||||
CurrentVelocityY = GetComponent<Rigidbody2D>().linearVelocity.y;
|
||||
|
||||
if (PreviousVelocityY == 0 && CurrentVelocityY == 0)
|
||||
isGrounded = true;
|
||||
else
|
||||
isGrounded = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e26b0770900bcd4dbb716a6d2d58794
|
||||
@@ -0,0 +1 @@
|
||||
uid://dwcm7cclkfe56
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class MainMenuScript : MonoBehaviour
|
||||
{
|
||||
public SpriteRenderer spriteRenderer;
|
||||
|
||||
|
||||
|
||||
public float targetAlpha = 0.0f;
|
||||
public float alphaSpeed = 0.07f;
|
||||
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
{
|
||||
spriteRenderer.color = new Color (1.0f, 1.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void FixedUpdate()
|
||||
{
|
||||
// update
|
||||
float newColorAlpha = spriteRenderer.color.a + (targetAlpha - spriteRenderer.color.a) * alphaSpeed;
|
||||
spriteRenderer.color = new Color(1.0f, 1.0f, 1.0f, newColorAlpha);
|
||||
}
|
||||
|
||||
void OnMouseOver()
|
||||
{
|
||||
targetAlpha = 1;
|
||||
}
|
||||
|
||||
void OnMouseExit()
|
||||
{
|
||||
targetAlpha = 0;
|
||||
}
|
||||
|
||||
void OnMouseDown()
|
||||
{
|
||||
SceneManager.LoadScene("LevelSelection");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5436d63c5bce7ce4ca0948f62f6492c1
|
||||
@@ -0,0 +1 @@
|
||||
uid://v86ourmwv01f
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03e5cbcf7de66a84385dcdc476db3830
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class BackWallCheck : MonoBehaviour
|
||||
{
|
||||
public bool backTouchingWall;
|
||||
private playerController PlayerController;
|
||||
void Start()
|
||||
{
|
||||
PlayerController = GameObject.Find("Player").GetComponent<playerController>();
|
||||
}
|
||||
private void OnCollisionEnter2D(Collision2D other)
|
||||
{
|
||||
if (other.gameObject.layer == 6 && PlayerController.isGrounded == false) PlayerController.Flip();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 271eb2e29c34a0c4ebb249963781b3bb
|
||||
@@ -0,0 +1 @@
|
||||
uid://d0s5t3y1sbtru
|
||||
@@ -0,0 +1,28 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class BasicMelee : MonoBehaviour
|
||||
{
|
||||
|
||||
public float damage = 15;
|
||||
void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
|
||||
if (collision.CompareTag("Attackable"))
|
||||
{
|
||||
if (collision.GetComponent<MasterEnemyAI>())
|
||||
{
|
||||
collision.GetComponent<MasterEnemyAI>().Health -= damage;
|
||||
}
|
||||
|
||||
if (collision.GetComponent<GenericDestructable>())
|
||||
{
|
||||
if (collision.GetComponent<GenericDestructable>().AttackableByPlayer)
|
||||
{
|
||||
collision.GetComponent<GenericDestructable>().Health -= damage;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a01a4d6a4955e74ebbcc0ec59721400
|
||||
@@ -0,0 +1 @@
|
||||
uid://dkp7hudmkw36e
|
||||
@@ -0,0 +1,15 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class DoubleCheck : MonoBehaviour
|
||||
{
|
||||
public bool isInsideGround = false;
|
||||
private void OnCollisionEnter2D(Collision2D other)
|
||||
{
|
||||
if (other.gameObject.CompareTag("Ground")) isInsideGround = true;
|
||||
}
|
||||
|
||||
private void OnCollisionExit2D(Collision2D other)
|
||||
{
|
||||
if (other.gameObject.CompareTag("Ground")) isInsideGround = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f3cfa164590ad2949a33333188132327
|
||||
@@ -0,0 +1 @@
|
||||
uid://drqqiiopmipvu
|
||||
@@ -0,0 +1,50 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class ShootScript: MonoBehaviour
|
||||
{
|
||||
public Transform Gun, ShootPoint;
|
||||
public float BulletSpeed, BulletRange, BulletDamage, BulletUnloadSpeed, BulletMagSize, BulletReloadSpeed, BulletBurstAmount;
|
||||
private float BurstTimer, BurstCounter;
|
||||
private string ProjectileType;
|
||||
Vector2 direction;
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
|
||||
direction = mousePos - (Vector2)Gun.position;
|
||||
FaceMouse();
|
||||
|
||||
|
||||
BurstTimer -= Time.deltaTime;
|
||||
|
||||
if (BulletBurstAmount > 0 && BurstTimer < 0)
|
||||
{
|
||||
GameObject BulletInstance = Instantiate(GameObject.Find(ProjectileType), ShootPoint.position, ShootPoint.rotation * Quaternion.Euler(0, 0, 90));
|
||||
BulletInstance.GetComponent<Rigidbody2D>().AddForce(BulletInstance.transform.up * -1 * BulletSpeed);
|
||||
|
||||
BurstTimer = BurstCounter;
|
||||
BulletBurstAmount--;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void FaceMouse()
|
||||
{
|
||||
Gun.transform.right = direction;
|
||||
}
|
||||
|
||||
public void Shoot(string projectile, float speed, float range, float damage, float unload, float burst = 1, float burstSpeed = 0)
|
||||
{
|
||||
ProjectileType = projectile;
|
||||
BulletRange = range;
|
||||
BulletDamage = damage;
|
||||
BulletSpeed = speed;
|
||||
BulletUnloadSpeed = unload;
|
||||
BulletBurstAmount = burst;
|
||||
BurstCounter = burstSpeed;
|
||||
BurstTimer = BurstCounter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71e63fd6b84ea2b488a89c0cbf454fc4
|
||||
@@ -0,0 +1 @@
|
||||
uid://b2mripgcwjpsn
|
||||
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class WallCheck : MonoBehaviour
|
||||
{
|
||||
public bool touchingWall;
|
||||
private void OnCollisionEnter2D(Collision2D other)
|
||||
{
|
||||
if (other.gameObject.layer == 6) touchingWall = true;
|
||||
}
|
||||
|
||||
private void OnCollisionExit2D(Collision2D other)
|
||||
{
|
||||
if (other.gameObject.layer == 6) touchingWall = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a121cc5b301b024ea2a2185f35ce482
|
||||
@@ -0,0 +1 @@
|
||||
uid://blrhilsupt0cs
|
||||
@@ -0,0 +1,59 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class bulletScript : MonoBehaviour
|
||||
{
|
||||
private ShootScript shootScript;
|
||||
private float range, damage, unload, burst;
|
||||
private Rigidbody2D body;
|
||||
Vector3 startPos;
|
||||
void Awake()
|
||||
{
|
||||
shootScript = GameObject.Find("Player").GetComponent<ShootScript>();
|
||||
body = GetComponent<Rigidbody2D>();
|
||||
range = shootScript.BulletRange;
|
||||
damage = shootScript.BulletDamage;
|
||||
unload = shootScript.BulletUnloadSpeed;
|
||||
burst = shootScript.BulletBurstAmount;
|
||||
|
||||
startPos = transform.position;
|
||||
}
|
||||
void Update()
|
||||
{
|
||||
Vector3 currentPos = transform.position;
|
||||
|
||||
if (Vector2.Distance(startPos, currentPos) > range) body.gravityScale = 1;
|
||||
if (currentPos.y < -1000) Destroy(gameObject);
|
||||
}
|
||||
|
||||
void OnTriggerEnter2D(Collider2D collision)
|
||||
{
|
||||
|
||||
if (collision.CompareTag("Attackable"))
|
||||
{
|
||||
if (collision.GetComponent<MasterEnemyAI>())
|
||||
{
|
||||
collision.GetComponent<MasterEnemyAI>().Health -= damage;
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
if (collision.GetComponent<GenericDestructable>())
|
||||
{
|
||||
if (collision.GetComponent<GenericDestructable>().AttackableByPlayer)
|
||||
{
|
||||
collision.GetComponent<GenericDestructable>().Health -= damage;
|
||||
Destroy(gameObject);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (collision.gameObject.layer == 6) Destroy(gameObject);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7e7339128775734981b0d99898e1a7f
|
||||
@@ -0,0 +1 @@
|
||||
uid://dcu6k02qpiwad
|
||||
@@ -0,0 +1,671 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
public class playerController : MonoBehaviour
|
||||
{
|
||||
|
||||
#region Imported Variables
|
||||
private GroundCheck groundCheck;
|
||||
private DoubleCheck doubleCheck;
|
||||
private WallCheck wallCheck;
|
||||
private Rigidbody2D body;
|
||||
private Collider2D hBox;
|
||||
public GameObject attackHitbox;
|
||||
public GameObject gun;
|
||||
#endregion
|
||||
#region Keybinds / Controls
|
||||
private KeyCode hop, up, down, left, right, dash, lightAttack, heavyAttack, ultimateAttack, forward;
|
||||
private String currentDirection;
|
||||
private int directionsHeld;
|
||||
private bool RIGHT, LEFT, UP, DOWN, moveLock;
|
||||
#endregion
|
||||
#region Timers
|
||||
private float coyoteTimeAmount = .1f, airjumpTurnaroundWindow = .1f, jumpBufferAmount = .2f, clickBufferAmount = .1f, wallStallAmount = .15f, dashLength = .15f, waveDashWindow = .18f, scrollSpeed = .15f;
|
||||
private float CoyoteTimer, jumpBufferTimer, clickBufferTimer, airjumpTurnTimer, wallStallTimer, dashCooldownTimer, dashLeftTimer, dashRightTimer, waveDashTimer, hitboxTimer, scrollTimer, reloadTimer;
|
||||
private float tempMaxSpeedTimer, dashCooldownAmount = 1, moveLockTimer, sideDashTimer, pauseGravTimer, dashEndTimer;
|
||||
#endregion
|
||||
#region Player Booleans
|
||||
private bool allowedToWalk = true, allowedToJump = true, allowedToWallSlide = true, allowedToDash = true, speedClampingActive = true, canScroll = true;
|
||||
public bool isGrounded, isWallSlide, canJumpAgain, isFacingRight = true, canDash, dashingLeft, dashingRight, alreadyAirDashed, waveDashing = false;
|
||||
[SerializeField] private bool canDie = true;
|
||||
#endregion
|
||||
#region Player Floats
|
||||
private float defaultMaxSpeed = 10f, defaultMoveSpeed = 10f, defaultJumpPower = 30f, defaultDashPower = 60f, defaultTurnResponsiveness = 4f, defaultExtraJumps = 1f; //Permanent Upgrades Will Affect These
|
||||
private float tempMaxSpeed = 10f, tempMoveSpeed = 10f, tempJumpPower = 30f, tempDashPower = 60f, tempTurnResponsiveness = 8f, tempExtraJumps; //Temporary Upgrades/Debuffs Will Affect These
|
||||
private float velocityDirection = 1, turnaround;
|
||||
[SerializeField] private float playerHealth;
|
||||
#endregion
|
||||
#region Characters/Inventory Management
|
||||
private List<String> playerInventory;
|
||||
public int equippedIndex = 2;
|
||||
public String equippedItem, SelectedPlayer;
|
||||
#endregion
|
||||
|
||||
|
||||
void Start()
|
||||
{
|
||||
body = GetComponent<Rigidbody2D>();
|
||||
hBox = transform.GetComponent<BoxCollider2D>();
|
||||
body.gravityScale = 6;
|
||||
|
||||
#region Character Movesets
|
||||
switch (SelectedPlayer)
|
||||
{
|
||||
case "Cade":
|
||||
playerInventory = new List<String> { "StaffSwing", "Fireball", "DragonBreath" };
|
||||
break;
|
||||
|
||||
case "Sloane":
|
||||
playerInventory = new List<String> { "Knife", "Grenade", "Rifle", "Shotgun" };
|
||||
break;
|
||||
|
||||
case "Leo":
|
||||
playerInventory = new List<String> { "ChargeFist", "JunkToss", "Grabble" };
|
||||
break;
|
||||
|
||||
case "Gamma":
|
||||
playerInventory = new List<String> { "ArmStab", "BlubberBomb", "BodyThrow" };
|
||||
break;
|
||||
|
||||
default:
|
||||
playerInventory = new List<String> { "Gun", "Melee"};
|
||||
break;
|
||||
}
|
||||
equippedItem = playerInventory[equippedIndex];
|
||||
#endregion
|
||||
|
||||
#region Character Controls
|
||||
|
||||
switch (SelectedPlayer)
|
||||
{
|
||||
case "Cade":
|
||||
case "Sloane":
|
||||
default:
|
||||
hop = KeyCode.W;
|
||||
up = KeyCode.W;
|
||||
down = KeyCode.S;
|
||||
left = KeyCode.A;
|
||||
right = KeyCode.D;
|
||||
dash = KeyCode.LeftShift;
|
||||
break;
|
||||
|
||||
case "Leo":
|
||||
case "Gamma":
|
||||
hop = KeyCode.Space;
|
||||
up = KeyCode.UpArrow;
|
||||
down = KeyCode.DownArrow;
|
||||
left = KeyCode.LeftArrow;
|
||||
right = KeyCode.RightArrow;
|
||||
dash = KeyCode.LeftShift;
|
||||
lightAttack = KeyCode.X;
|
||||
heavyAttack = KeyCode.C;
|
||||
break;
|
||||
}
|
||||
forward = right;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
StateCheck();
|
||||
|
||||
if (playerHealth > 0) {
|
||||
PhysicsTimersHandler();
|
||||
|
||||
Movement();
|
||||
|
||||
ControllerTimersHandler();
|
||||
|
||||
CheckFaceDirection();
|
||||
|
||||
RangedCombat();
|
||||
}
|
||||
}
|
||||
|
||||
#region BEHIND-THE-SCENES STUFF
|
||||
void StateCheck()
|
||||
{
|
||||
#region Ground Check
|
||||
groundCheck = GetComponentInChildren<GroundCheck>();
|
||||
doubleCheck = GetComponentInChildren<DoubleCheck>();
|
||||
|
||||
if (groundCheck.isGrounded && !doubleCheck.isInsideGround) isGrounded = true;
|
||||
else isGrounded = false;
|
||||
#endregion
|
||||
|
||||
#region Wall Check
|
||||
wallCheck = GetComponentInChildren<WallCheck>();
|
||||
if ((wallCheck.touchingWall) && !isGrounded && Input.GetKey(forward)) isWallSlide = true;
|
||||
else isWallSlide = false;
|
||||
#endregion
|
||||
|
||||
#region Reload Air Jumps
|
||||
if (isGrounded && (tempExtraJumps < defaultExtraJumps))
|
||||
tempExtraJumps = defaultExtraJumps;
|
||||
|
||||
if (tempExtraJumps > 0) canJumpAgain = true;
|
||||
else canJumpAgain = false;
|
||||
#endregion
|
||||
|
||||
#region Reload Dash
|
||||
if (isGrounded) alreadyAirDashed = false;
|
||||
#endregion
|
||||
|
||||
#region Health Update
|
||||
playerHealth = GameObject.Find("GameData").GetComponent<GameData>().CurrentHealth;
|
||||
|
||||
if (playerHealth <= 0) body.linearVelocityX = 0;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Most Recent Direction Input
|
||||
if (moveLock == false) LEFT = Input.GetKey(left);
|
||||
if (moveLock == false) RIGHT = Input.GetKey(right);
|
||||
UP = Input.GetKey(up);
|
||||
DOWN = Input.GetKey(down);
|
||||
|
||||
directionsHeld = 0;
|
||||
if (LEFT) directionsHeld++; if (RIGHT) directionsHeld++; if (UP) directionsHeld++; if (DOWN) directionsHeld++;
|
||||
|
||||
if (UP) currentDirection = "up";
|
||||
else if (DOWN) currentDirection = "down";
|
||||
else if (LEFT || RIGHT)
|
||||
{
|
||||
if (LEFT && left != forward || RIGHT && right != forward) currentDirection = "backward";
|
||||
if (LEFT && left == forward || RIGHT && right == forward) currentDirection = "forward";
|
||||
}
|
||||
else currentDirection = "neutral";
|
||||
#endregion
|
||||
|
||||
#region Gravity Updates
|
||||
if (pauseGravTimer <= 0)
|
||||
{
|
||||
if (DOWN && !UP) body.gravityScale = 8;
|
||||
else body.gravityScale = 6;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
void CheckFaceDirection()
|
||||
{
|
||||
if ((body.linearVelocity.x > 0 && !isFacingRight || body.linearVelocity.x < 0 && isFacingRight) && isGrounded) Flip();
|
||||
}
|
||||
public void Flip()
|
||||
{
|
||||
if (forward == left) forward = right;
|
||||
else if (forward == right) forward = left;
|
||||
|
||||
isFacingRight = !isFacingRight;
|
||||
velocityDirection *= -1;
|
||||
|
||||
#region Change Player Orientation
|
||||
Vector3 currentScale = transform.localScale;
|
||||
currentScale.x *= -1;
|
||||
transform.localScale = currentScale;
|
||||
|
||||
Vector3 gunScale = gun.transform.localScale;
|
||||
gunScale.x *= -1;
|
||||
gunScale.y *= -1;
|
||||
gun.transform.localScale = gunScale;
|
||||
|
||||
#endregion
|
||||
}
|
||||
void PhysicsTimersHandler()
|
||||
{
|
||||
#region Coyote Time
|
||||
if (isGrounded && !(body.linearVelocity.y > 0)) CoyoteTimer = coyoteTimeAmount;
|
||||
if (CoyoteTimer > 0) CoyoteTimer -= Time.deltaTime;
|
||||
#endregion
|
||||
|
||||
#region Jump Buffering
|
||||
if (Input.GetKeyDown(hop)) jumpBufferTimer = jumpBufferAmount;
|
||||
if (jumpBufferTimer > 0) jumpBufferTimer -= Time.deltaTime;
|
||||
#endregion
|
||||
|
||||
#region Window To Change Directions After Air Jump
|
||||
if (airjumpTurnTimer > 0) airjumpTurnTimer -= Time.deltaTime;
|
||||
#endregion
|
||||
|
||||
#region Wall Stall
|
||||
if (!isWallSlide || body.linearVelocity.y >= 0) wallStallTimer = wallStallAmount;
|
||||
if (wallStallTimer > 0) wallStallTimer -= Time.deltaTime;
|
||||
#endregion
|
||||
|
||||
#region WaveDashing
|
||||
if (isGrounded && waveDashing) waveDashTimer -= Time.deltaTime;
|
||||
if (waveDashTimer > 0) waveDashing = true;
|
||||
else waveDashing = false;
|
||||
#endregion
|
||||
|
||||
#region Resetting Speed Clamping
|
||||
|
||||
if (tempMaxSpeedTimer <= 0)
|
||||
{
|
||||
tempMaxSpeed = defaultMaxSpeed;
|
||||
body.linearVelocity = new Vector2(Mathf.Clamp(body.linearVelocity.x, -tempMaxSpeed, tempMaxSpeed), Mathf.Clamp(body.linearVelocity.y, -tempJumpPower, tempJumpPower));
|
||||
}
|
||||
else
|
||||
{
|
||||
tempMaxSpeedTimer -= Time.deltaTime;
|
||||
body.linearVelocity = new Vector2(Mathf.Clamp(body.linearVelocity.x, -tempMaxSpeed, tempMaxSpeed), Mathf.Clamp(body.linearVelocity.y, -tempMaxSpeed, tempMaxSpeed));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Gravity
|
||||
if (pauseGravTimer > 0) pauseGravTimer -= Time.deltaTime;
|
||||
#endregion
|
||||
|
||||
#region Physics After A Dash Ends
|
||||
if (dashEndTimer > 0) dashEndTimer -= Time.deltaTime;
|
||||
if (dashEndTimer < 0)
|
||||
{
|
||||
dashEndTimer = 0;
|
||||
if (body.linearVelocity.y > 0) body.linearVelocity = new Vector2(body.linearVelocity.x, 10);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
void ControllerTimersHandler()
|
||||
{
|
||||
#region Click Buffer & Reload Timers
|
||||
if (Input.GetMouseButtonDown(0)) clickBufferTimer = clickBufferAmount;
|
||||
if (clickBufferTimer > 0) clickBufferTimer -= Time.deltaTime;
|
||||
if (reloadTimer > 0) reloadTimer -= Time.deltaTime;
|
||||
#endregion
|
||||
|
||||
#region Dash Cooldown
|
||||
if (dashCooldownTimer > 0) dashCooldownTimer -= Time.deltaTime;
|
||||
if (dashCooldownTimer <= 0) canDash = true;
|
||||
else canDash = false;
|
||||
#endregion
|
||||
|
||||
#region Dash Input Window
|
||||
/*
|
||||
if (dashLeftTimer > 0 && Input.GetKeyDown(left) && canDash && !alreadyAirDashed) dashingLeft = true;
|
||||
if (Input.GetKeyDown(left))
|
||||
{
|
||||
dashLeftTimer = dashWindowAmount;
|
||||
dashRightTimer = 0;
|
||||
}
|
||||
|
||||
if (dashRightTimer > 0 && Input.GetKeyDown(right) && canDash && !alreadyAirDashed) dashingRight = true;
|
||||
if (Input.GetKeyDown(right))
|
||||
{
|
||||
dashRightTimer = dashWindowAmount;
|
||||
dashLeftTimer = 0;
|
||||
}
|
||||
|
||||
if (dashLeftTimer > 0) dashLeftTimer -= Time.deltaTime;
|
||||
if (dashRightTimer > 0) dashRightTimer -= Time.deltaTime;
|
||||
|
||||
*/
|
||||
#endregion
|
||||
|
||||
#region Attack Window
|
||||
if (hitboxTimer >= 0) hitboxTimer -= Time.deltaTime;
|
||||
if (hitboxTimer < 0) attackHitbox.SetActive(false);
|
||||
#endregion
|
||||
|
||||
#region Inventory Scrolling
|
||||
if (scrollTimer > 0) scrollTimer -= Time.deltaTime;
|
||||
if (scrollTimer > 0) canScroll = false;
|
||||
else canScroll = true;
|
||||
#endregion
|
||||
|
||||
#region Left/Right Locks
|
||||
if (moveLockTimer > 0)
|
||||
{
|
||||
moveLockTimer -= Time.deltaTime;
|
||||
moveLock = true;
|
||||
}
|
||||
else moveLock = false;
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PLAYER CONTROLLED ASPECTS
|
||||
void Movement()
|
||||
{
|
||||
|
||||
if (allowedToWalk)
|
||||
{
|
||||
#region Walking
|
||||
if (!(LEFT && RIGHT))
|
||||
{
|
||||
#region Control Responsiveness
|
||||
if (!isGrounded) turnaround = tempTurnResponsiveness * .75f;
|
||||
else turnaround = tempTurnResponsiveness;
|
||||
if (airjumpTurnTimer > 0) turnaround = tempTurnResponsiveness * 5f;
|
||||
#endregion
|
||||
|
||||
#region Moving Left
|
||||
if (LEFT) body.linearVelocity += new Vector2(-tempMoveSpeed * turnaround * Time.deltaTime, 0);
|
||||
#endregion
|
||||
|
||||
#region Moving Right
|
||||
if (RIGHT) body.linearVelocity += new Vector2(tempMoveSpeed * turnaround * Time.deltaTime, 0);
|
||||
#endregion
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Friction
|
||||
if (!(Input.GetKey(left) || Input.GetKey(right)) || (Input.GetKey(left) && Input.GetKey(right)))
|
||||
{
|
||||
float fric;
|
||||
if (Math.Abs(body.linearVelocity.x) > 5f) { fric = .97f; }
|
||||
else { fric = .92f; }
|
||||
|
||||
body.linearVelocity = new Vector2(body.linearVelocity.x * fric, body.linearVelocity.y);
|
||||
|
||||
if (Math.Abs(body.linearVelocity.x) < .4f) body.linearVelocity = new Vector2(0, body.linearVelocity.y);
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
if (allowedToJump)
|
||||
{
|
||||
#region Normal Jumps
|
||||
if (CoyoteTimer > 0 && jumpBufferTimer > 0)
|
||||
{
|
||||
body.linearVelocity = new Vector2(body.linearVelocity.x, tempJumpPower);
|
||||
jumpBufferTimer = 0;
|
||||
CoyoteTimer = 0;
|
||||
if(waveDashTimer > 0) waveDashTimer = waveDashWindow;
|
||||
Debug.Log("normalJump");
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Air Jumps
|
||||
else if (canJumpAgain && Input.GetKeyDown(hop) && !isWallSlide)
|
||||
{
|
||||
Debug.Log("doubleJump");
|
||||
jumpBufferTimer = 0;
|
||||
Debug.Log("CHECKDOUBLE");
|
||||
|
||||
|
||||
body.linearVelocity = new Vector2(body.linearVelocity.x, tempJumpPower * .8f);
|
||||
tempExtraJumps--;
|
||||
|
||||
|
||||
airjumpTurnTimer = airjumpTurnaroundWindow;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Releasing Jump
|
||||
if (!Input.GetKey(hop) && body.linearVelocity.y > 0)
|
||||
{
|
||||
body.linearVelocity = new Vector2(body.linearVelocity.x, body.linearVelocity.y * .97f);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
if (allowedToWallSlide)
|
||||
{
|
||||
#region Wall Sliding Friction
|
||||
if (isWallSlide && wallStallTimer > 0 && body.linearVelocity.y < 0)
|
||||
{
|
||||
body.linearVelocity = new Vector2(body.linearVelocity.x, body.linearVelocity.y * .95f);
|
||||
body.gravityScale = 0;
|
||||
}
|
||||
else if (isWallSlide && body.linearVelocity.y < 0) body.gravityScale = 2;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Wall Jumps
|
||||
if (isWallSlide && jumpBufferTimer > 0)
|
||||
{
|
||||
moveLockTimer = 0.15f;
|
||||
|
||||
body.linearVelocity = new Vector2(tempMoveSpeed * -velocityDirection, 20f);
|
||||
|
||||
if (velocityDirection < 0) { RIGHT = true; LEFT = false; }
|
||||
else if (velocityDirection > 0) { LEFT = true; RIGHT = false; }
|
||||
|
||||
jumpBufferTimer = 0;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
if (allowedToDash)
|
||||
{
|
||||
#region Dashing
|
||||
if (Input.GetKeyDown(dash) && canDash && !alreadyAirDashed)
|
||||
{
|
||||
tempMaxSpeed = tempDashPower;
|
||||
tempMaxSpeedTimer = dashLength;
|
||||
moveLockTimer = dashLength;
|
||||
pauseGravTimer = dashLength;
|
||||
body.linearVelocity = new Vector2(body.linearVelocity.x, 0);
|
||||
body.gravityScale = 0;
|
||||
|
||||
dashCooldownTimer = dashCooldownAmount;
|
||||
alreadyAirDashed = true;
|
||||
|
||||
if ((LEFT && DOWN || LEFT && UP || RIGHT && DOWN || RIGHT && UP) && directionsHeld == 2) tempDashPower = 0.70710678f * tempDashPower;
|
||||
|
||||
|
||||
#region Neutral Dashing
|
||||
if (!LEFT && !RIGHT && directionsHeld % 2 == 0)
|
||||
{
|
||||
if (forward == right)
|
||||
{
|
||||
RIGHT = true;
|
||||
LEFT = false;
|
||||
}
|
||||
else if (forward == left)
|
||||
{
|
||||
LEFT = true;
|
||||
RIGHT = false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Directional Dashes
|
||||
if (LEFT && !RIGHT) body.linearVelocity = new Vector2(-tempDashPower, body.linearVelocity.y);
|
||||
if (!LEFT && RIGHT) body.linearVelocity = new Vector2(tempDashPower, body.linearVelocity.y);
|
||||
|
||||
if (UP && !DOWN) { body.linearVelocity = new Vector2(body.linearVelocity.x, 2f * tempDashPower); dashEndTimer = .15f; }
|
||||
if (!UP && DOWN) body.linearVelocity = new Vector2(body.linearVelocity.x, -2f * tempDashPower);
|
||||
#endregion
|
||||
|
||||
|
||||
if ((DOWN && RIGHT || DOWN && LEFT) && directionsHeld == 2) waveDashTimer = waveDashWindow;
|
||||
|
||||
|
||||
|
||||
tempDashPower = defaultDashPower;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
public void RangedCombat()
|
||||
{
|
||||
#region Weapon Wheel
|
||||
float scrollInput = Input.GetAxis("Mouse ScrollWheel");
|
||||
|
||||
if (scrollInput != 0 && canScroll)
|
||||
{
|
||||
int scrollDirection = Math.Sign(scrollInput);
|
||||
int nextIndex = equippedIndex + scrollDirection;
|
||||
scrollTimer = scrollSpeed;
|
||||
|
||||
equippedIndex = (nextIndex % playerInventory.Count + playerInventory.Count) % playerInventory.Count;
|
||||
equippedItem = playerInventory[equippedIndex];
|
||||
|
||||
reloadTimer = 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Shooting
|
||||
|
||||
if (clickBufferTimer > 0 && reloadTimer <= 0)
|
||||
{
|
||||
|
||||
switch (equippedItem)
|
||||
{
|
||||
|
||||
#region Cade's Weapons
|
||||
case "StaffSwing":
|
||||
break;
|
||||
|
||||
case "Fireball":
|
||||
break;
|
||||
|
||||
case "DragonBreath":
|
||||
break;
|
||||
#endregion
|
||||
|
||||
#region Sloane's Weapons
|
||||
case "Knife":
|
||||
break;
|
||||
|
||||
case "Grenade":
|
||||
break;
|
||||
|
||||
case "Rifle":
|
||||
break;
|
||||
|
||||
case "Shotgun":
|
||||
break;
|
||||
#endregion
|
||||
|
||||
#region Leo's Weapons
|
||||
case "ChargeFist":
|
||||
break;
|
||||
|
||||
case "JunkToss":
|
||||
break;
|
||||
|
||||
case "Grabble":
|
||||
break;
|
||||
#endregion
|
||||
|
||||
#region Gamma's Weapons
|
||||
case "ArmStab":
|
||||
break;
|
||||
|
||||
case "BlubberBomb":
|
||||
break;
|
||||
|
||||
case "BodyThrow":
|
||||
break;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Test Weapons
|
||||
case "Melee":
|
||||
attackHitbox.SetActive(true);
|
||||
hitboxTimer = .2f;
|
||||
reloadTimer = .3f;
|
||||
Debug.Log("swing");
|
||||
break;
|
||||
|
||||
case "Gun":
|
||||
GetComponent<ShootScript>().Shoot("Bullet", 2000f, 15f, 25f, .25f, 3, .05f);
|
||||
reloadTimer = .5f;
|
||||
break;
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
public void DirectionalCombat()
|
||||
{
|
||||
|
||||
if (Input.GetKeyDown(lightAttack) && reloadTimer <= 0)
|
||||
{
|
||||
switch (currentDirection) {
|
||||
|
||||
case ("up"):
|
||||
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case ("down"):
|
||||
|
||||
break;
|
||||
|
||||
case ("backward"):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case ("forward"):
|
||||
|
||||
break;
|
||||
|
||||
case ("right"):
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (Input.GetKeyDown(heavyAttack) && reloadTimer <= 0)
|
||||
{
|
||||
switch (currentDirection)
|
||||
{
|
||||
|
||||
case ("up"):
|
||||
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case ("down"):
|
||||
|
||||
break;
|
||||
|
||||
case ("left"):
|
||||
|
||||
break;
|
||||
|
||||
case ("right"):
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43123429e7f993140b4cf6d8bd8c7b35
|
||||
@@ -0,0 +1 @@
|
||||
uid://f2l6y7a360x4
|
||||
@@ -0,0 +1 @@
|
||||
this is just a text file to see if I (Tyson) can successfully push to the repo using git
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31970e17b2bebd74cbec26ac2d292740
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee4b6189b2f1f9047b187c22df1345ea
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9776525c92b362242a58f959cbe6b91e
|
||||
@@ -0,0 +1 @@
|
||||
uid://d4eldf5x4kddm
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a49219e9fdacd2640a56d6100c2983c9
|
||||
@@ -0,0 +1 @@
|
||||
uid://b56cltkpns8eg
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1f4adc563b83f549b3b3fc9eeb38e9a
|
||||
@@ -0,0 +1 @@
|
||||
uid://bmvsmx2cghvjx
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b9c0ca6eef46ec49b42f46141997c46
|
||||
@@ -0,0 +1 @@
|
||||
uid://cw5sup7xiuq2s
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a8b83d0c517ff040ac4a88b082b85ec
|
||||
@@ -0,0 +1 @@
|
||||
uid://dfgtcghp4yxk4
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81f1c8e2d50cae34da2edf9525005d91
|
||||
@@ -0,0 +1 @@
|
||||
uid://cf3cm245clgqf
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a21aeddab50704439aa410e19bcee64
|
||||
@@ -0,0 +1 @@
|
||||
uid://btkxwdxwwqhh3
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 908158ab2214cc04ea3af93728a2c94d
|
||||
@@ -0,0 +1 @@
|
||||
uid://dbhj5fkwajasw
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user