Added assets from old repo

This commit is contained in:
weedmjac000
2026-01-21 10:30:32 -07:00
parent 44117ec414
commit fc5efd89bf
713 changed files with 148036 additions and 1 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e3f4bf5bfa244ad42bb0aee2a2ae9299
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c1c590ca1f619314ca9de654d499ae32
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 4
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}

View File

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

View File

@@ -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();
}
}
}

View File

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

View File

@@ -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;
}
}

View File

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

View File

@@ -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
*/

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ad647c10099d0ee49895d85a8051bf07
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5e4fba3e90705634d87c5f003412fdff
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}
}
}

View File

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

View File

@@ -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);
}
}
}
}
}

View File

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

View File

@@ -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);
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0352972f1b0f7bf44a209f0d71fc13b8

View File

@@ -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();
}
}
}

View File

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

View File

@@ -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
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1c2fe015b31da6b409479a7d804d4c67
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 5
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 480f622e764a4c54d9e7e2f48f7978f6

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4dec8478c6d3efb48ab0d10ff7e0dc5e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 1
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: df6e2d19b2ac1664fbffd73cbd649528
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

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

View File

@@ -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;
}
}

View File

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

View File

@@ -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");
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5436d63c5bce7ce4ca0948f62f6492c1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 03e5cbcf7de66a84385dcdc476db3830
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 271eb2e29c34a0c4ebb249963781b3bb

View File

@@ -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;
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4a01a4d6a4955e74ebbcc0ec59721400

View File

@@ -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;
}
}

View File

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

View File

@@ -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;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 71e63fd6b84ea2b488a89c0cbf454fc4

View File

@@ -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;
}
}

View File

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

View File

@@ -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);
}
}

View File

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

View File

@@ -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
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 43123429e7f993140b4cf6d8bd8c7b35

View File

@@ -0,0 +1 @@
this is just a text file to see if I (Tyson) can successfully push to the repo using git

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 31970e17b2bebd74cbec26ac2d292740
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ee4b6189b2f1f9047b187c22df1345ea
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,500 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Pathfinding;
using System.Threading.Tasks;
using System;
using System.Linq;
using System.Text;
//Designed by Jacob Weedman
//Use on Brute type enemies
public class BruteAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canJump = true;
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = false;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 5f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
int NumberOfHitsPerMag = 0;
float angle;
bool canDash = true;
//ENEMY STATS (Changeable)
public float Speed = 0.6f; // In relation to player's walking speed
public float JumpHeight = 0.8f; // In relation to player's regular jump height
public float Health = 250;
public float PatrolDistance = 10;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 25;
public float dashSpeed = 20f; // Strength of the dash
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 20; // Damage per hit
public int WeaponFireRate = 1000; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 6f; // Random direction of lanched projectiles
public int WeaponRange = 30; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles
public int WeaponMagazineSize = 15; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 7000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// When enemy has reached the next node
void OnPathComplete(Path p)
{
if (!p.error)
{
path = p;
currentWaypoint = 0;
}
}
// Select next node
void UpdatePath()
{
if (seeker.IsDone() && target != null)
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5 && canDash == true)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform)
{
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//CALL DASH
if (DetermineLineOfSight(gameObject, player) && targetingPlayer && canDash == true && canJump == true)
{
Dash(player);
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
//float xDirection = target.transform.position.x - transform.position.x;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// Get the last know player location by finding which of the positions is closest to the player
if (LastKnownPlayerLocation == null)
{
LastKnownPlayerLocation = gameObject;
}
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(player.transform.position, pos.transform.position) < Vector2.Distance(player.transform.position, LastKnownPlayerLocation.transform.position))
{
LastKnownPlayerLocation = pos;
}
}
// Angle barrel towards player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
// Player has broken line of sight and the enemy will attempt to move to the last known location
else if (LastKnownPlayerLocation != null)
{
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// Catch desired distance error
if (DesiredDistance <= MinumumDistance)
{
DesiredDistance = MinumumDistance + 1;
}
// If the player moves away (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) > DesiredDistance)
{
ComputeClosestPositionToPlayer();
}
// If the player is too close to the target (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) < MinumumDistance)
{
ComputeClosestPositionToPlayer();
}
// If the target is on the other side of the player (CHANGE TARGET)
if (Vector2.Distance(transform.position, player.transform.position) < Vector2.Distance(target.transform.position, player.transform.position))
{
ComputeClosestPositionToPlayer();
}
// If the player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Dash
async Task Dash(GameObject endLocation)
{
canDash = false;
// Perform dash
rb.linearVelocity = new Vector2(transform.position.x - player.transform.position.x, transform.position.y - player.transform.position.y).normalized * dashSpeed * -1;
await Task.Delay(5000);
canDash = true;
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
BulletInstance.transform.parent = transform;
// Send it on it's way
BulletInstance.GetComponent<Rigidbody2D>().linearVelocity = BulletInstance.transform.forward * -1 * WeaponProjectileSpeed;
BulletInstance.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, BulletInstance.transform.forward) - 90));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
if (NumberOfHitsPerMag / WeaponMagazineSize < 0.5)
{
DesiredDistance -= 5;
}
NumberOfHitsPerMag = 0;
canFire = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
DesiredDistance = WeaponRange - 5;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// General Utility
bool DetermineLineOfSight(GameObject object1, GameObject object2)
{
Vector3 RaycastStart = object1.transform.position;
Vector3 RaycastDirection = (object2.transform.position - object1.transform.position).normalized;
float RaycastDistance = Vector3.Distance(object2.transform.position, object1.transform.position);
if (Physics2D.Raycast(RaycastStart, RaycastDirection, RaycastDistance, LayerMask.GetMask("SolidGround")) == false)
{
Debug.DrawRay(RaycastStart, RaycastDirection * RaycastDistance);
return true;
}
else
{
return false;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
SuitablePositions.Clear();
foreach (GameObject query in AllPositions)
{
// Check the distance of the position
if (Vector2.Distance(query.transform.position, player.transform.position) < DesiredDistance && Vector2.Distance(query.transform.position, player.transform.position) >= MinumumDistance)
{
// Check line of sight of the position
if (DetermineLineOfSight(query, player))
{
SuitablePositions.Add(query);
}
}
}
if (SuitablePositions.Count > 0)
{
target = SuitablePositions[UnityEngine.Random.Range(0, SuitablePositions.Count)];
foreach (GameObject pos in SuitablePositions)
{
//Find the point that is closest to the enemy
if (Vector2.Distance(transform.position, pos.transform.position) < Vector2.Distance(transform.position, target.transform.position))
{
target = pos;
}
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,473 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Pathfinding;
using System.Threading.Tasks;
using System;
using System.Linq;
using System.Text;
//Designed by Jacob Weedman
//Use on Flamethrower type enemies
public class FlamethrowerAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canJump = true;
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = false;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 5f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
float angle;
//ENEMY STATS (Changeable)
public float Speed = 1.3f; // In relation to player's walking speed
public float JumpHeight = 1.3f; // In relation to player's regular jump height
public float Health = 30;
public float PatrolDistance = 15;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 20;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 1; // Damage per hit
public int WeaponFireRate = 50; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 3f; // Random direction of lanched projectiles
public int WeaponRange = 15; // Maximum range of the projectile before it drops off
public int WeaponMagazineSize = 200; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// When enemy has reached the next node
void OnPathComplete(Path p)
{
if (!p.error)
{
path = p;
currentWaypoint = 0;
}
}
// Select next node
void UpdatePath()
{
if (seeker.IsDone() && target != null)
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// Get the last know player location by finding which of the positions is closest to the player
if (LastKnownPlayerLocation == null)
{
LastKnownPlayerLocation = gameObject;
}
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(player.transform.position, pos.transform.position) < Vector2.Distance(player.transform.position, LastKnownPlayerLocation.transform.position))
{
LastKnownPlayerLocation = pos;
}
}
// Angle barrel towards player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
// Player has broken line of sight and the enemy will attempt to move to the last known location
else if (LastKnownPlayerLocation != null)
{
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 200 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// Catch desired distance error
if (DesiredDistance <= MinumumDistance)
{
DesiredDistance = MinumumDistance + 1;
}
// If the player moves away (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) > DesiredDistance)
{
ComputeClosestPositionToPlayer();
}
// If the player is too close to the target (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) < MinumumDistance)
{
ComputeClosestPositionToPlayer();
}
// If the target is on the other side of the player (CHANGE TARGET)
if (Vector2.Distance(transform.position, player.transform.position) < Vector2.Distance(target.transform.position, player.transform.position))
{
ComputeClosestPositionToPlayer();
}
// If the player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
inFiringCycle = true;
GameObject Flame;
Flame = Instantiate(GameObject.Find("Flame"), new Vector3(transform.position.x + UnityEngine.Random.Range(-0.5f, 0.5f), transform.position.y + UnityEngine.Random.Range(-0.5f, 0.5f), GameObject.Find("EvilAura").transform.position.z), Quaternion.identity);
Flame.transform.rotation = Quaternion.Euler(Vector3.forward * UnityEngine.Random.Range(-90, 90));
// Send it on its way
Flame.GetComponent<Rigidbody2D>().linearVelocity = new Vector2(transform.position.x - player.transform.position.x + UnityEngine.Random.Range(-WeaponRandomSpread, WeaponRandomSpread), transform.position.y - player.transform.position.y + UnityEngine.Random.Range(-WeaponRandomSpread, WeaponRandomSpread)).normalized * 1.25f * WeaponRange * -1;
//Set Variables
Flame.GetComponent<EnemyParticleWeapon>().destroy = true;
Flame.GetComponent<EnemyParticleWeapon>().opacity = true;
Flame.GetComponent<EnemyParticleWeapon>().destroyOnCollide= true;
Flame.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
await Task.Delay(WeaponFireRate);
canFire = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
canMove = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
canMove = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
DesiredDistance = WeaponRange - 5;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// General Utility
bool DetermineLineOfSight(GameObject object1, GameObject object2)
{
Vector3 RaycastStart = object1.transform.position;
Vector3 RaycastDirection = (object2.transform.position - object1.transform.position).normalized;
float RaycastDistance = Vector3.Distance(object2.transform.position, object1.transform.position);
if (Physics2D.Raycast(RaycastStart, RaycastDirection, RaycastDistance, LayerMask.GetMask("SolidGround")) == false)
{
Debug.DrawRay(RaycastStart, RaycastDirection * RaycastDistance);
return true;
}
else
{
return false;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
SuitablePositions.Clear();
foreach (GameObject query in AllPositions)
{
// Check the distance of the position
if (Vector2.Distance(query.transform.position, player.transform.position) < DesiredDistance && Vector2.Distance(query.transform.position, player.transform.position) >= MinumumDistance)
{
// Check line of sight of the position
if (DetermineLineOfSight(query, player))
{
SuitablePositions.Add(query);
}
}
}
if (SuitablePositions.Count > 0)
{
target = SuitablePositions[UnityEngine.Random.Range(0, SuitablePositions.Count)];
foreach (GameObject pos in SuitablePositions)
{
//Find the point that is closest to the enemy
if (Vector2.Distance(transform.position, pos.transform.position) < Vector2.Distance(transform.position, target.transform.position))
{
target = pos;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,480 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Pathfinding;
using System.Threading.Tasks;
using System;
using System.Linq;
using System.Text;
//Designed by Jacob Weedman
//Use on Grunt type enemies
public class GruntAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canJump = true;
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = false;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 5f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
public int NumberOfHitsPerMag = 0;
float angle;
//ENEMY STATS (Changeable)
public float Speed = 1.3f; // In relation to player's walking speed
public float JumpHeight = 1.3f; // In relation to player's regular jump height
public float Health = 30;
public float PatrolDistance = 15;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 20;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 1; // Damage per hit
public int WeaponFireRate = 100; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 7.5f; // Random direction of lanched projectiles
public int WeaponRange = 15; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 40f; // Speed of launched projectiles
public int WeaponMagazineSize = 20; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 3000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// When enemy has reached the next node
void OnPathComplete(Path p)
{
if (!p.error)
{
path = p;
currentWaypoint = 0;
}
}
// Select next node
void UpdatePath()
{
if (seeker.IsDone() && target != null)
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// Get the last know player location by finding which of the positions is closest to the player
if (LastKnownPlayerLocation == null)
{
LastKnownPlayerLocation = gameObject;
}
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(player.transform.position, pos.transform.position) < Vector2.Distance(player.transform.position, LastKnownPlayerLocation.transform.position))
{
LastKnownPlayerLocation = pos;
}
}
// Angle barrel towards player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
// Player has broken line of sight and the enemy will attempt to move to the last known location
else if (LastKnownPlayerLocation != null)
{
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 200 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// Catch desired distance error
if (DesiredDistance <= MinumumDistance)
{
DesiredDistance = MinumumDistance + 1;
}
// If the player moves away (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) > DesiredDistance)
{
ComputeClosestPositionToPlayer();
}
// If the player is too close to the target (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) < MinumumDistance)
{
ComputeClosestPositionToPlayer();
}
// If the target is on the other side of the player (CHANGE TARGET)
if (Vector2.Distance(transform.position, player.transform.position) < Vector2.Distance(target.transform.position, player.transform.position))
{
ComputeClosestPositionToPlayer();
}
// If the player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
canMove = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
BulletInstance.transform.parent = transform;
// Send it on it's way
BulletInstance.GetComponent<Rigidbody2D>().linearVelocity = BulletInstance.transform.forward * -1 * WeaponProjectileSpeed;
BulletInstance.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, BulletInstance.transform.forward) - 90));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
canMove = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
canMove = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
if (NumberOfHitsPerMag / WeaponMagazineSize < 0.5)
{
DesiredDistance -= 5;
}
NumberOfHitsPerMag = 0;
canFire = true;
canMove = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
DesiredDistance = WeaponRange - 5;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// General Utility
bool DetermineLineOfSight(GameObject object1, GameObject object2)
{
Vector3 RaycastStart = object1.transform.position;
Vector3 RaycastDirection = (object2.transform.position - object1.transform.position).normalized;
float RaycastDistance = Vector3.Distance(object2.transform.position, object1.transform.position);
if (Physics2D.Raycast(RaycastStart, RaycastDirection, RaycastDistance, LayerMask.GetMask("SolidGround")) == false)
{
Debug.DrawRay(RaycastStart, RaycastDirection * RaycastDistance);
return true;
}
else
{
return false;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
SuitablePositions.Clear();
foreach (GameObject query in AllPositions)
{
// Check the distance of the position
if (Vector2.Distance(query.transform.position, player.transform.position) < DesiredDistance && Vector2.Distance(query.transform.position, player.transform.position) >= MinumumDistance)
{
// Check line of sight of the position
if (DetermineLineOfSight(query, player))
{
SuitablePositions.Add(query);
}
}
}
if (SuitablePositions.Count > 0)
{
target = SuitablePositions[UnityEngine.Random.Range(0, SuitablePositions.Count)];
foreach (GameObject pos in SuitablePositions)
{
//Find the point that is closest to the enemy
if (Vector2.Distance(transform.position, pos.transform.position) < Vector2.Distance(transform.position, target.transform.position))
{
target = pos;
}
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,385 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Pathfinding;
using System.Threading.Tasks;
using System;
using System.Linq;
using System.Text;
//Designed by Jacob Weedman
//Use on regular flying ranged enemies
public class RegularFlyingAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canMove = true;
bool canPursue = false;
bool canFire = true;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 10f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
//ENEMY STATS (Changeable)
public float Speed = 0.7f; // In relation to player's walking speed
public float Health = 100;
public float PatrolDistance = 10;
public int PatrolStallTime = 1500; //ms
public int PlayerDetectionRange = 25;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 5; // Damage per hit
public int WeaponFireRate = 100; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles (DOES NOT APPLY TO MELEE ATTACKS)
public int WeaponRange = 30; // Maximum range of the projectile before it drops off (DOES NOT APPLY TO MELEE ATTACKS)
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles (DOES NOT APPLY TO MELEE WEAPONS)
public int WeaponMagazineSize = 50; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
Seeker seeker;
Rigidbody2D rb;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
target = Instantiate(GameObject.Find("FlyingTarget"), transform.position, Quaternion.identity);
projectile = GameObject.Find("Projectile");
player = GameObject.FindGameObjectWithTag("Player");
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 30);
}
// When enemy has reached the next node
void OnPathComplete(Path p)
{
if (!p.error)
{
path = p;
currentWaypoint = 0;
}
}
// Select next node
void UpdatePath()
{
if (seeker.IsDone())
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
//target = gameObject;
targetingPlayer = false;
LastKnownPlayerLocation = null;
MoveNextPatrol();
}
}
//Main logic
void FixedUpdate()
{
// Death
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
DeadBody.GetComponent<Rigidbody2D>().gravityScale = 3;
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIAirRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform)
{
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
// See where the enemy wants to go (DEBUGGING ONLY)
/*
if (target != null)
{
foreach (GameObject pos in AllPositions)
{
pos.GetComponent<SpriteRenderer>().enabled = false;
}
target.GetComponent<SpriteRenderer>().enabled = true;
}
*/
// Change Icons
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && inFiringCycle == false && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] - rb.position).normalized;
Vector2 force = direction * Speed * 20;
rb.AddForce(force);
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//PATROL
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
//target = null;
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// Get the last know player location by finding which of the positions is closest to the player
if (LastKnownPlayerLocation == null)
{
LastKnownPlayerLocation = gameObject;
}
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(player.transform.position, pos.transform.position) < Vector2.Distance(player.transform.position, LastKnownPlayerLocation.transform.position))
{
LastKnownPlayerLocation = pos;
}
}
}
// Player has broken line of sight and the enemy will attempt to move to the last known location
else if (LastKnownPlayerLocation != null)
{
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
{
canPursue = false;
target.transform.position = LastKnownPlayerLocation.transform.position;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
}
// Go back to patrol move
else
{
//target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
LastKnownPlayerLocation = gameObject;
currentlyPatrolling = true;
targetingPlayer = false;
}
// Call patrol method
if (currentlyPatrolling)
{
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
}
if (canPursue == true)
{
//TARGET DETERMINATION
// If the player moves away (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) > DesiredDistance)
{
ComputeClosestPositionToPlayer();
canMove = true;
}
//If the player is too close to the target (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) < MinumumDistance)
{
ComputeClosestPositionToPlayer();
canMove = true;
}
// If the player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
canMove = true;
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1)
{
if (DetermineLineOfSight(gameObject, player) == false) // If the enemy has LOS on the player
{
ComputeClosestPositionToPlayer();
canMove = true;
}
}
}
}
// Use Ranged Weapon
async Task UseWeapon() // Weapon for projectile based enemy
{
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
BulletInstance.transform.parent = transform;
// Send it on it's way
BulletInstance.GetComponent<Rigidbody2D>().linearVelocity = BulletInstance.transform.forward * -1 * WeaponProjectileSpeed;
BulletInstance.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, BulletInstance.transform.forward) - 90));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = gameObject;
target.transform.position = transform.position;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
target.transform.position = new Vector2((StartPosition.x + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)), (StartPosition.y + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)));
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
currentlyMovingToNextPatrolTarget = false;
}
// General Utility
bool DetermineLineOfSight(GameObject object1, GameObject object2)
{
Vector3 RaycastStart = object1.transform.position;
Vector3 RaycastDirection = (object2.transform.position - object1.transform.position).normalized;
float RaycastDistance = Vector3.Distance(object2.transform.position, object1.transform.position);
if (Physics2D.Raycast(RaycastStart, RaycastDirection, RaycastDistance, LayerMask.GetMask("SolidGround")) == false)
{
Debug.DrawRay(RaycastStart, RaycastDirection * RaycastDistance);
return true;
}
else
{
return false;
}
}
// Partof the pursue cycle
void ComputeClosestPositionToPlayer()
{
// find a target in the air a set radius away from the player
if (DetermineLineOfSight(player, gameObject))
{
target.transform.position = new Vector2((player.transform.position.x + UnityEngine.Random.Range(-MinumumDistance, MinumumDistance)), (player.transform.position.y + MinumumDistance + UnityEngine.Random.Range(-5, 0)));
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,468 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Pathfinding;
using System.Threading.Tasks;
using System;
using System.Linq;
using System.Text;
//Designed by Jacob Weedman
//Use on Sniper type enemies
public class SniperAI : MonoBehaviour
{
//MISC
GameObject target;
float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
bool canJump = true;
bool canMove = true; // Prevent all movement
bool canPursue = false; // Follow player
bool canFire = false;
bool currentlyReloading = false;
bool currentlyPatrolling;
bool currentlyMovingToNextPatrolTarget = false;
float DesiredDistance;
float MinumumDistance = 10f;
bool targetingPlayer = false;
bool inFiringCycle = false;
int WeaponCurrentMagazineAmmount;
float angle;
//ENEMY STATS (Changeable)
public float Speed = 0.4f; // In relation to player's walking speed
public float JumpHeight = 0.9f; // In relation to player's regular jump height
public float Health = 50;
public float PatrolDistance = 3;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 50;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 25; // Damage per hit
public int WeaponFireRate = 1000; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 0.5f; // Random direction of lanched projectiles
public int WeaponRange = 45; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 100f; // Speed of launched projectiles
public int WeaponMagazineSize = 5; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 6000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// When enemy has reached the next node
void OnPathComplete(Path p)
{
if (!p.error)
{
path = p;
currentWaypoint = 0;
}
}
// Select next node
void UpdatePath()
{
if (seeker.IsDone() && target != null)
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
//float xDirection = target.transform.position.x - transform.position.x;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// Get the last know player location by finding which of the positions is closest to the player
if (LastKnownPlayerLocation == null)
{
LastKnownPlayerLocation = gameObject;
}
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(player.transform.position, pos.transform.position) < Vector2.Distance(player.transform.position, LastKnownPlayerLocation.transform.position))
{
LastKnownPlayerLocation = pos;
}
}
// Angle barrel towards player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
// Player has broken line of sight and the enemy will attempt to move to the last known location
else if (LastKnownPlayerLocation != null)
{
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// If the player moves away (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) > DesiredDistance)
{
ComputeClosestPositionToPlayer();
}
// If the player is too close to the target (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) < MinumumDistance)
{
ComputeClosestPositionToPlayer();
}
// If the target is on the other side of the player (CHANGE TARGET)
if (Vector2.Distance(transform.position, player.transform.position) < Vector2.Distance(target.transform.position, player.transform.position))
{
ComputeClosestPositionToPlayer();
}
// If the player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
canMove = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
BulletInstance.transform.parent = transform;
// Send it on it's way
BulletInstance.GetComponent<Rigidbody2D>().linearVelocity = BulletInstance.transform.forward * -1 * WeaponProjectileSpeed;
BulletInstance.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, BulletInstance.transform.forward) - 90));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
canMove = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
canMove = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
canFire = true;
canMove = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// General Utility
bool DetermineLineOfSight(GameObject object1, GameObject object2)
{
Vector3 RaycastStart = object1.transform.position;
Vector3 RaycastDirection = (object2.transform.position - object1.transform.position).normalized;
float RaycastDistance = Vector3.Distance(object2.transform.position, object1.transform.position);
if (Physics2D.Raycast(RaycastStart, RaycastDirection, RaycastDistance, LayerMask.GetMask("SolidGround")) == false)
{
Debug.DrawRay(RaycastStart, RaycastDirection * RaycastDistance);
return true;
}
else
{
return false;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
SuitablePositions.Clear();
foreach (GameObject query in AllPositions)
{
// Check the distance of the position
if (Vector2.Distance(query.transform.position, player.transform.position) < DesiredDistance && Vector2.Distance(query.transform.position, player.transform.position) >= MinumumDistance)
{
// Check line of sight of the position
if (DetermineLineOfSight(query, player))
{
SuitablePositions.Add(query);
}
}
}
if (SuitablePositions.Count > 0)
{
target = SuitablePositions[UnityEngine.Random.Range(0, SuitablePositions.Count)];
foreach (GameObject pos in SuitablePositions)
{
//Find the point that is closest to the enemy
if (Vector2.Distance(transform.position, pos.transform.position) < Vector2.Distance(transform.position, target.transform.position))
{
target = pos;
}
}
}
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,367 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Pathfinding;
using System.Threading.Tasks;
using System;
using System.Linq;
using System.Text;
//Designed by Jacob Weedman
//Use on switchblade drone enemies
public class SwitchbladeAI : MonoBehaviour
{
//MISC
public GameObject target;
public float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> AllPositions;
public float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
public bool canMove = true;
public bool canPursue = false;
public bool canFire = true;
public bool currentlyReloading = false;
public bool currentlyPatrolling;
public bool currentlyMovingToNextPatrolTarget = false;
public float DesiredDistance = 15;
int MinumumDistance = 10;
public bool targetingPlayer = false;
public bool inFiringCycle = false;
public bool primed = false;
//ENEMY STATS (Changeable)
float Speed = 0.7f; // In relation to player's walking speed
float Health = 5;
float PatrolDistance = 10;
int PatrolStallTime = 1500; //ms
int PlayerDetectionRange = 25;
int WeaponFireRate = 1000;
int WeaponRange = 30;
int WeaponDamage = 20;
float dashSpeed = 40f;
Seeker seeker;
Rigidbody2D rb;
//START OF THE GAME
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
target = Instantiate(GameObject.Find("FlyingTarget"), transform.position, Quaternion.identity);
player = GameObject.FindGameObjectWithTag("Player");
LastKnownPlayerLocation = null;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 30);
}
// When enemy has reached the next node
void OnPathComplete(Path p)
{
if (!p.error)
{
path = p;
currentWaypoint = 0;
}
}
// Select next node
void UpdatePath()
{
if (seeker.IsDone())
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
//target = gameObject;
targetingPlayer = false;
LastKnownPlayerLocation = null;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
// Death
if (Health <= 0)
{
Explode();
}
// Explode when close to the player
if (primed && Vector2.Distance(player.transform.position, transform.position) <= 2)
{
Explode();
}
// See where the enemy wants to go (DEBUGGING ONLY)
if (target != null)
{
foreach (GameObject pos in AllPositions)
{
pos.GetComponent<SpriteRenderer>().enabled = false;
}
target.GetComponent<SpriteRenderer>().enabled = true;
}
//CHANGE ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//DIVE BOMB
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && inFiringCycle == false && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange)
{
UseWeapon();
}
}
//MOVEMENT
if (canMove == true)
{
Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] - rb.position).normalized;
Vector2 force = direction * Speed * 20;
rb.AddForce(force);
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//PATROL
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
primed = true;
// Get the last know player location by finding which of the positions is closest to the player
if (LastKnownPlayerLocation == null)
{
LastKnownPlayerLocation = gameObject;
}
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(player.transform.position, pos.transform.position) < Vector2.Distance(player.transform.position, LastKnownPlayerLocation.transform.position))
{
LastKnownPlayerLocation = pos;
}
}
}
// Player has broken line of sight and the enemy will attempt to move to the last known location
else if (LastKnownPlayerLocation != null)
{
primed = false;
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
{
canPursue = false;
target.transform.position = LastKnownPlayerLocation.transform.position;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
}
// Go back to patrol move
else
{
LastKnownPlayerLocation = gameObject;
currentlyPatrolling = true;
targetingPlayer = false;
}
// Call patrol method
if (currentlyPatrolling)
{
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
}
//TARGET DETERMINATION
if (canPursue == true)
{
/*
// If the player moves away (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) > DesiredDistance)
{
ComputeClosestPositionToPlayer();
}
*/
//If the player is too close to the target (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) < MinumumDistance)
{
ComputeClosestPositionToPlayer();
}
// If the player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1)
{
if (DetermineLineOfSight(gameObject, player) == false) // If the enemy has LOS on the player
{
ComputeClosestPositionToPlayer();
}
}
}
}
//MISC METHODS
// Attempt to explode on the player
async Task UseWeapon()
{
inFiringCycle = true;
await Task.Delay(3000); // Dash delay ms
//Dash into player
rb.linearVelocity = new Vector2(transform.position.x - player.transform.position.x, transform.position.y - player.transform.position.y).normalized * dashSpeed * -2f;
inFiringCycle = false;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = gameObject;
target.transform.position = transform.position;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
target.transform.position = new Vector2((StartPosition.x + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)), (StartPosition.y + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)));
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
currentlyMovingToNextPatrolTarget = false;
}
// General Utility
bool DetermineLineOfSight(GameObject object1, GameObject object2)
{
Vector3 RaycastStart = object1.transform.position;
Vector3 RaycastDirection = (object2.transform.position - object1.transform.position).normalized;
float RaycastDistance = Vector3.Distance(object2.transform.position, object1.transform.position);
if (Physics2D.Raycast(RaycastStart, RaycastDirection, RaycastDistance, LayerMask.GetMask("SolidGround")) == false)
{
Debug.DrawRay(RaycastStart, RaycastDirection * RaycastDistance);
return true;
}
else
{
return false;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canMove = true;
// find a target in the air a set radius away from the player
if (DetermineLineOfSight(player, gameObject))
{
target.transform.position = new Vector2(player.transform.position.x + UnityEngine.Random.Range(-MinumumDistance, MinumumDistance), player.transform.position.y + MinumumDistance);
}
}
// Explode
void Explode()
{
//Create Explosion
GameObject Explosion;
Explosion = Instantiate(GameObject.Find("Explosion"), new Vector3(transform.position.x, transform.position.y, GameObject.Find("Explosion").transform.position.z), Quaternion.identity);
Explosion.transform.rotation = Quaternion.Euler(Vector3.forward);
//Set Variables
Explosion.GetComponent<EnemyParticleWeapon>().destroy = true;
Explosion.GetComponent<EnemyParticleWeapon>().opacity = true;
Explosion.GetComponent<EnemyParticleWeapon>().timer = 3;
Explosion.GetComponent<EnemyParticleWeapon>().damageAmmount = WeaponDamage;
//Delete Enemy
Destroy(gameObject);
}
void OnTriggerEnter2D(Collider2D collision)
{
if (primed)
{
if (collision.gameObject.tag == "Ground")
{
if (collision.gameObject.layer == 6)
{
Explode();
}
}
}
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,414 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Pathfinding;
using System.Threading.Tasks;
using System;
using System.Linq;
using System.Text;
//Designed by Jacob Weedman
//V 0.0.2
//DO NOT USE THIS ON ANY ENEMIES
public class TestEnemyAIAirRanged : MonoBehaviour
{
//MISC
public GameObject target;
public float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> AllPositions;
public float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
public bool canMove = true;
public bool canPursue = false;
public bool canFire = true;
public bool currentlyReloading = false;
public bool currentlyPatrolling;
public bool currentlyMovingToNextPatrolTarget = false;
public float DesiredDistance;
public float MinumumDistance = 20f;
public bool targetingPlayer = false;
public bool inFiringCycle = false;
public int WeaponCurrentMagazineAmmount;
public int NumberOfHitsPerMag = 0;
public float angle;
//ENEMY STATS (Changeable)
public float Speed = 0.7f; // In relation to player's walking speed
public float Health = 100;
public float PatrolDistance = 10;
public int PatrolStallTime = 1500; //ms
public int PlayerDetectionRange = 25;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 5; // Damage per hit
public int WeaponFireRate = 100; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles
public int WeaponRange = 30; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles
public int WeaponMagazineSize = 50; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
Seeker seeker;
Rigidbody2D rb;
//START OF THE GAME
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
target = Instantiate(GameObject.Find("FlyingTarget"), transform.position,Quaternion.identity);
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 30);
}
// When enemy has reached the next node
void OnPathComplete(Path p)
{
if (!p.error)
{
path = p;
currentWaypoint = 0;
}
}
// Select next node
void UpdatePath()
{
if (seeker.IsDone())
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
//target = gameObject;
targetingPlayer = false;
LastKnownPlayerLocation = null;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
// Death
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
DeadBody.GetComponent<Rigidbody2D>().gravityScale = 3;
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIAirRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform)
{
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
// See where the enemy wants to go (DEBUGGING ONLY)
/*
if (target != null)
{
foreach (GameObject pos in AllPositions)
{
pos.GetComponent<SpriteRenderer>().enabled = false;
}
target.GetComponent<SpriteRenderer>().enabled = true;
}
*/
//CHANGE ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && inFiringCycle == false && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] - rb.position).normalized;
Vector2 force = direction * Speed * 20;
rb.AddForce(force);
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//PATROL
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// Angle barrel towards player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
// Get the last know player location by finding which of the positions is closest to the player
if (LastKnownPlayerLocation == null)
{
LastKnownPlayerLocation = gameObject;
}
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(player.transform.position, pos.transform.position) < Vector2.Distance(player.transform.position, LastKnownPlayerLocation.transform.position))
{
LastKnownPlayerLocation = pos;
}
}
}
// Player has broken line of sight and the enemy will attempt to move to the last known location
else if (LastKnownPlayerLocation != null)
{
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
{
canPursue = false;
target.transform.position = LastKnownPlayerLocation.transform.position;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = -90f;
}
// Go back to patrol move
else
{
LastKnownPlayerLocation = gameObject;
currentlyPatrolling = true;
targetingPlayer = false;
// Reset barrel rotation
angle = -90f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
// Call patrol method
if (currentlyPatrolling)
{
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
}
//TARGET DETERMINATION
if (canPursue == true)
{
// Catch desired distance error
if (DesiredDistance <= MinumumDistance)
{
DesiredDistance = MinumumDistance + 1;
}
// If enemy is at the target position
if (Vector2.Distance(target.transform.position, transform.position) < 1.5)
{
ComputeClosestPositionToPlayer();
}
// If the player moves away (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) > DesiredDistance)
{
ComputeClosestPositionToPlayer();
}
//If the player is too close to the target (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) < MinumumDistance)
{
ComputeClosestPositionToPlayer();
}
// If the player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1)
{
if (DetermineLineOfSight(gameObject, player) == false) // If the enemy has LOS on the player
{
ComputeClosestPositionToPlayer();
}
}
}
}
//MISC METHODS
// Use Ranged Weapon
async Task UseWeapon() // Weapon for projectile based enemy
{
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
BulletInstance.transform.parent = transform;
// Send it on it's way
BulletInstance.GetComponent<Rigidbody2D>().linearVelocity = BulletInstance.transform.forward * -1 * WeaponProjectileSpeed;
BulletInstance.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, BulletInstance.transform.forward) - 90));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
if (NumberOfHitsPerMag / WeaponMagazineSize < 0.5)
{
DesiredDistance -= 5;
}
NumberOfHitsPerMag = 0;
canFire = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = gameObject;
target.transform.position = transform.position;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
target.transform.position = new Vector2((StartPosition.x + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)), (StartPosition.y + UnityEngine.Random.Range(-1 * PatrolDistance, PatrolDistance)));
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
currentlyMovingToNextPatrolTarget = false;
}
// General Utility
bool DetermineLineOfSight(GameObject object1, GameObject object2)
{
Vector3 RaycastStart = object1.transform.position;
Vector3 RaycastDirection = (object2.transform.position - object1.transform.position).normalized;
float RaycastDistance = Vector3.Distance(object2.transform.position, object1.transform.position);
if (Physics2D.Raycast(RaycastStart, RaycastDirection, RaycastDistance, LayerMask.GetMask("SolidGround")) == false)
{
Debug.DrawRay(RaycastStart, RaycastDirection * RaycastDistance);
return true;
}
else
{
return false;
}
}
// Partof the pursue cycle
void ComputeClosestPositionToPlayer()
{
canMove = true;
// find a target in the air a set radius away from the player
if (DetermineLineOfSight(player, gameObject))
{
target.transform.position = new Vector2((player.transform.position.x + UnityEngine.Random.Range(-MinumumDistance, MinumumDistance)), (player.transform.position.y + MinumumDistance + UnityEngine.Random.Range(-5, 0)));
}
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,492 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Pathfinding;
using System.Threading.Tasks;
using System;
using System.Linq;
using System.Text;
//Designed by Jacob Weedman
//V 0.0.6
//DO NOT USE THIS ON ANY ENEMIES
public class TestEnemyAIGroundRanged : MonoBehaviour
{
//MISC
public GameObject target;
public float nextWaypointDistance = 5;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
GameObject projectile;
GameObject player;
GameObject barrel;
public List<GameObject> SuitablePositions;
public List<GameObject> AllPositions;
public float DistanceFromPlayer;
Vector2 StartPosition;
public List<GameObject> PatrolPositions;
public GameObject LastKnownPlayerLocation;
//CONDITIONS/GENERAL INFORMATION
public bool canJump = true; //
public bool canMove = true; // Prevent all movement
public bool canPursue = false; // Follow player
public bool canFire = false;
public bool currentlyReloading = false;
public bool currentlyPatrolling;
public bool currentlyMovingToNextPatrolTarget = false;
public float DesiredDistance;
public float MinumumDistance = 5f;
public bool targetingPlayer = false;
public bool inFiringCycle = false;
public int WeaponCurrentMagazineAmmount;
public int NumberOfHitsPerMag = 0;
public float angle;
//ENEMY STATS (Changeable)
public float Speed = 0.7f; // In relation to player's walking speed
public float JumpHeight = 1; // In relation to player's regular jump height
public float Health = 100;
public float PatrolDistance = 10;
public int PatrolStallTime = 2000; //ms
public int PlayerDetectionRange = 25;
//WEAPON STATS (CHANGEABLE)
public int WeaponDamage = 15; // Damage per hit
public int WeaponFireRate = 250; // Delay in time between attacks both melee and ranged
public float WeaponRandomSpread = 5f; // Random direction of lanched projectiles
public int WeaponRange = 20; // Maximum range of the projectile before it drops off
public float WeaponProjectileSpeed = 30f; // Speed of launched projectiles
public int WeaponMagazineSize = 20; // Number of shots the enemy will take before having to reload
public int WeaponReloadTime = 5000; // Time it takes to reload the magazine
//REFERENCES
Seeker seeker;
Rigidbody2D rb;
//ONCE THE GAME STARTS
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
StartPosition = transform.position;
AllPositions = GameObject.FindGameObjectsWithTag("PossiblePositions").ToList();
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(pos.transform.position, StartPosition) <= PatrolDistance)
{
PatrolPositions.Add(pos);
}
}
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
projectile = GameObject.Find("EnemyProjectile");
player = GameObject.FindGameObjectWithTag("Player");
barrel = transform.Find("Barrel").gameObject;
LastKnownPlayerLocation = null;
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
DesiredDistance = WeaponRange - 5;
InvokeRepeating("UpdatePath", 0f, 0.1f);
InvokeRepeating("PathfindingTimeout", 0f, 10);
}
// When enemy has reached the next node
void OnPathComplete(Path p)
{
if (!p.error)
{
path = p;
currentWaypoint = 0;
}
}
// Select next node
void UpdatePath()
{
if (seeker.IsDone() && target != null)
{
seeker.StartPath(rb.position, target.transform.position, OnPathComplete);
}
}
// Pathfiniding Timeout
void PathfindingTimeout()
{
if (Vector2.Distance(transform.position, target.transform.position) > 0.5)
{
target = gameObject;
MoveNextPatrol();
}
}
//MAIN LOGIC
void FixedUpdate()
{
//DEATH
if (Health <= 0)
{
GameObject DeadBody;
DeadBody = Instantiate(gameObject, transform.position, Quaternion.identity);
Destroy(GameObject.Find(DeadBody.name).GetComponent<TestEnemyAIGroundRanged>());
Destroy(GameObject.Find(DeadBody.name).GetComponent<Seeker>());
foreach (Transform child in DeadBody.transform) {
GameObject.Destroy(child.gameObject);
}
Destroy(gameObject);
}
// See where the enemy wants to go (DEBUGGING ONLY)
if (target != null)
{
foreach (GameObject pos in AllPositions)
{
pos.GetComponent<SpriteRenderer>().enabled = false;
}
target.GetComponent<SpriteRenderer>().enabled = true;
}
//ICONS
if (targetingPlayer)
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("PursuingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
if (currentlyReloading)
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = true;
}
else
{
transform.Find("ReloadingIndicator").GetComponent<SpriteRenderer>().enabled = false;
}
//if (90 <= angle || angle <= 270)
//{
// barrel.transform.localScale = new Vector2(-barrel.transform.localScale.x, barrel.transform.localScale.y);
//}
//MISC PATHFINDING
if (path == null)
return;
if (target == null)
return;
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
//RANGED ATTACK
// Check if enemy has line of sight on the player & if they are in the acceptable range
if (WeaponCurrentMagazineAmmount > 0 && canFire == true && currentlyReloading == false && currentlyPatrolling == false)
{
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= WeaponRange && Vector2.Distance(transform.position, player.transform.position) <= DesiredDistance)
{
UseWeapon();
}
}
else if (WeaponCurrentMagazineAmmount == 0 && currentlyReloading == false)
{
ReloadWeapon();
}
//MOVEMENT
if (canMove == true)
{
canFire = false;
Vector2 direction = (Vector2)path.vectorPath[currentWaypoint] - rb.position;
//float xDirection = target.transform.position.x - transform.position.x;
if (direction.x > 0) // Move right
{
rb.AddForce(new Vector2(Speed * 20, rb.linearVelocity.y));
}
if (direction.x < 0) // Move left
{
rb.AddForce(new Vector2(-1 * Speed * 20, rb.linearVelocity.y));
}
if (direction.y > 1f) // Wants to jump
{
JumpMethod();
}
// A* logic
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
}
//GROUND DETECTION
//Detecting if the enemy has reached the ground
if (GetComponentInChildren<GroundCheck>().isGrounded == true && rb.linearVelocity.y == 0)
{
canJump = true;
if (inFiringCycle == false)
{
canFire = true;
}
}
else
{
canJump = false;
canFire = false;
}
//PATROL & DETECTION
// Enemy detects player
if (DetermineLineOfSight(gameObject, player) == true && Vector2.Distance(transform.position, player.transform.position) <= PlayerDetectionRange)
{
currentlyPatrolling = false;
targetingPlayer = true;
canPursue = true;
// Get the last know player location by finding which of the positions is closest to the player
if (LastKnownPlayerLocation == null)
{
LastKnownPlayerLocation = gameObject;
}
foreach (GameObject pos in AllPositions)
{
if (Vector2.Distance(player.transform.position, pos.transform.position) < Vector2.Distance(player.transform.position, LastKnownPlayerLocation.transform.position))
{
LastKnownPlayerLocation = pos;
}
}
// Angle barrel towards player
angle = Mathf.Atan2(player.transform.position.y - barrel.transform.position.y, player.transform.position.x - barrel.transform.position.x) * Mathf.Rad2Deg;
}
// Player has broken line of sight and the enemy will attempt to move to the last known location
else if (LastKnownPlayerLocation != null)
{
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) > 0.5)
{
canPursue = false;
target = LastKnownPlayerLocation;
}
if (Vector2.Distance(transform.position, LastKnownPlayerLocation.transform.position) < 0.5 && DetermineLineOfSight(player, gameObject) == false)
{
targetingPlayer = false;
LastKnownPlayerLocation = null;
}
// Reset barrel rotation
angle = 0f;
}
// Go back to patrol move
else
{
currentlyPatrolling = true;
targetingPlayer = false;
if (canMove == true && currentlyMovingToNextPatrolTarget == false)
{
MoveNextPatrol();
}
// Reset barrel rotation
angle = 0f;
}
// Rotate barrel towards player
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, angle));
barrel.transform.rotation = Quaternion.RotateTowards(barrel.transform.rotation, targetRotation, 100 * Time.deltaTime);
//TARGET DETERMINATION
if (canPursue == true)
{
// Catch desired distance error
if (DesiredDistance <= MinumumDistance)
{
DesiredDistance = MinumumDistance + 1;
}
// If the player moves away (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) > DesiredDistance)
{
ComputeClosestPositionToPlayer();
}
// If the player is too close to the target (CHANGE TARGET)
if (Vector2.Distance(target.transform.position, player.transform.position) < MinumumDistance)
{
ComputeClosestPositionToPlayer();
}
// If the target is on the other side of the player (CHANGE TARGET)
if (Vector2.Distance(transform.position, player.transform.position) < Vector2.Distance(target.transform.position, player.transform.position))
{
ComputeClosestPositionToPlayer();
}
// If the player is not within line of sight of the desired position (CHANGE TARGET)
if (DetermineLineOfSight(target, player) == false)
{
ComputeClosestPositionToPlayer();
}
// If the enemy reaches the target
if (Vector2.Distance(target.transform.position, transform.position) <= 1 && DetermineLineOfSight(gameObject, player))
{
if (canFire == false && inFiringCycle == false)
{
canFire = true;
}
}
}
}
//MISC METHODS
// Perform jump
async Task JumpMethod()
{
if (canJump == true)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, JumpHeight * 12);
canJump = false;
await Task.Delay(500);
}
}
// Use Ranged Weapon
async Task UseWeapon()
{
canFire = false;
canMove = false;
inFiringCycle = true;
// Create Projectile
GameObject BulletInstance;
BulletInstance = Instantiate(projectile, transform.position, Quaternion.LookRotation(transform.position - GameObject.FindGameObjectWithTag("Player").transform.position + new Vector3(UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), UnityEngine.Random.Range((-1 * WeaponRandomSpread), WeaponRandomSpread), 0)));
BulletInstance.transform.parent = transform;
// Send it on it's way
BulletInstance.GetComponent<Rigidbody2D>().linearVelocity = BulletInstance.transform.forward * -1 * WeaponProjectileSpeed;
BulletInstance.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, BulletInstance.transform.forward) - 90));
WeaponCurrentMagazineAmmount--;
await Task.Delay(WeaponFireRate);
canFire = true;
canMove = true;
inFiringCycle = false;
}
// Reload Weapon
async Task ReloadWeapon()
{
canFire = false;
canMove = false;
//play reload animation
currentlyReloading = true;
await Task.Delay(WeaponReloadTime);
WeaponCurrentMagazineAmmount = WeaponMagazineSize;
currentlyReloading = false;
if (NumberOfHitsPerMag / WeaponMagazineSize < 0.5)
{
DesiredDistance -= 5;
}
NumberOfHitsPerMag = 0;
canFire = true;
canMove = true;
}
// Part of the patrol cycle
async Task MoveNextPatrol()
{
LastKnownPlayerLocation = null;
DesiredDistance = WeaponRange - 5;
canPursue = false;
currentlyMovingToNextPatrolTarget = true;
//Find Random Position nearby
if (Vector2.Distance(transform.position, target.transform.position) <= 0.5 || PatrolPositions.Contains(target) == false)
{
target = PatrolPositions[UnityEngine.Random.Range(0, PatrolPositions.Count)];
await Task.Delay(PatrolStallTime + UnityEngine.Random.Range((PatrolStallTime * -1), PatrolStallTime));
}
currentlyMovingToNextPatrolTarget = false;
}
// General Utility
bool DetermineLineOfSight(GameObject object1, GameObject object2)
{
Vector3 RaycastStart = object1.transform.position;
Vector3 RaycastDirection = (object2.transform.position - object1.transform.position).normalized;
float RaycastDistance = Vector3.Distance(object2.transform.position, object1.transform.position);
if (Physics2D.Raycast(RaycastStart, RaycastDirection, RaycastDistance, LayerMask.GetMask("SolidGround")) == false)
{
Debug.DrawRay(RaycastStart, RaycastDirection * RaycastDistance);
return true;
}
else
{
return false;
}
}
// Part of the pursue cycle
void ComputeClosestPositionToPlayer()
{
canFire = false;
canMove = true;
SuitablePositions.Clear();
foreach (GameObject query in AllPositions)
{
// Check the distance of the position
if (Vector2.Distance(query.transform.position, player.transform.position) < DesiredDistance && Vector2.Distance(query.transform.position, player.transform.position) >= MinumumDistance)
{
// Check line of sight of the position
if (DetermineLineOfSight(query, player))
{
SuitablePositions.Add(query);
}
}
}
if (SuitablePositions.Count > 0)
{
target = SuitablePositions[UnityEngine.Random.Range(0, SuitablePositions.Count)];
foreach (GameObject pos in SuitablePositions)
{
//Find the point that is closest to the enemy
if (Vector2.Distance(transform.position, pos.transform.position) < Vector2.Distance(transform.position, target.transform.position))
{
target = pos;
}
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4f73010c3b7b6934a8c5a6eebda73fd2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,211 @@
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//Designed by Jacob Weedman
//Component of the "MainCamera" game object
public class CameraMovement : MonoBehaviour
{
GameObject target;
GameObject player;
GameObject TempPos;
GameObject query;
public bool TargetingPlayer = true;
float CameraTweenAmmount = 0.005f;
float CameraTweenRateX;
float CameraTweenRateY;
float MaxCameraTweenRate = 50f;
float MinCameraTweenRate = 0.01f;
public float MaxCameraDistance = 15f;
public List<GameObject> InitialPanDestinations;
Vector3 StartLocation;
public float shakeDuration;
public float shakeAmount;
public float shakeInterval = 0.01f; //sec
public float currentShakeInterval = 0.01f; // sec
public float MinZoom = 10;
public float MaxZoom = 7;
public float PlayerVelocity;
public float ZoomAmmount;
public float TargetZoom;
void Start()
{
InitialPanDestinations = GameObject.FindGameObjectsWithTag("PanDestinations").ToList();
target = GameObject.Find("CameraTarget");
player = GameObject.FindWithTag("Player");
transform.position = new Vector3(target.transform.position.x, target.transform.position.y, -10);
float distance = 1000000;
foreach (GameObject query in InitialPanDestinations)
{
if (Vector2.Distance(query.transform.position, target.transform.position) < distance)
{
distance = Vector2.Distance(query.transform.position, target.transform.position);
TempPos = query;
}
}
if (TempPos == null)
{
TempPos = target;
}
target.transform.position = TempPos.transform.position;
TargetZoom = 0;
}
void Update()
{
// Zoom based on player velocity
if (GameObject.Find("Player"))
{
if (ZoomAmmount < TargetZoom)
{
TargetZoom -= Time.deltaTime * 2;
}
if (ZoomAmmount > TargetZoom)
{
TargetZoom += Time.deltaTime * 2;
}
PlayerVelocity = Math.Abs(GameObject.Find("Player").GetComponent<Rigidbody2D>().linearVelocity.x + GameObject.Find("Player").GetComponent<Rigidbody2D>().linearVelocity.y);
ZoomAmmount = MinZoom - PlayerVelocity / 10;
if (ZoomAmmount > MinZoom)
{
ZoomAmmount = MinZoom;
}
// Fix this later
//gameObject.GetComponent<UnityEngine.Rendering.Universal.PixelPerfectCamera>().assetsPPU = DOTween.To(()=> gameObject.GetComponent<UnityEngine.Rendering.Universal.PixelPerfectCamera>().assetsPPU, CameraTweenRateX=> gameObject.GetComponent<UnityEngine.Rendering.Universal.PixelPerfectCamera>().assetsPPU = CameraTweenRateX, Mathf.RoundToInt(TargetZoom));
}
// Difference between camera and target; abs()
CameraTweenRateX = (Math.Abs(target.transform.position.x - transform.position.x));
CameraTweenRateY = (Math.Abs(target.transform.position.y - transform.position.y));
// Ensure the Tween Rate stays between the Max and Min values
if (CameraTweenRateX > MaxCameraTweenRate)
{
CameraTweenRateX = MaxCameraTweenRate;
}
if (CameraTweenRateX < MinCameraTweenRate)
{
transform.position = new Vector3(target.transform.position.x, transform.position.y, transform.position.z);
}
if (CameraTweenRateY > MaxCameraTweenRate)
{
CameraTweenRateY = MaxCameraTweenRate;
}
if (CameraTweenRateY < MinCameraTweenRate)
{
transform.position = new Vector3(transform.position.x, target.transform.position.y, transform.position.z);
}
// Camera Shake
if (shakeDuration > 0) {
if (currentShakeInterval <= 0)
{
currentShakeInterval = shakeInterval;
transform.localPosition = new Vector3(UnityEngine.Random.Range(-shakeAmount, shakeAmount) + StartLocation.x, UnityEngine.Random.Range(-shakeAmount, shakeAmount) + StartLocation.y, -10);
}
else
{
currentShakeInterval -= Time.deltaTime;
}
shakeInterval += 0.15f * Time.deltaTime;
shakeAmount -= 0.15f * Time.deltaTime;
shakeDuration -= Time.deltaTime;
}
else
{
StartLocation = transform.position;
shakeDuration = 0.0f;
shakeAmount= 0.0f;
shakeInterval = 0.01f;
// Move Camera
transform.position = Vector3.MoveTowards(transform.position, new Vector3(target.transform.position.x, target.transform.position.y, -10), Vector2.Distance(transform.position, target.transform.position) / 100);
}
//Initial Pan
if (InitialPanDestinations.Count > 0)
{
// Lock player movement
if (Vector2.Distance(transform.position, TempPos.transform.position) < 0.5) // Camera at destination
{
InitialPanDestinations.Remove(TempPos);
TempPos = player;
float distance = 1000000;
foreach (GameObject query in InitialPanDestinations)
{
if (Vector2.Distance(query.transform.position, target.transform.position) < distance)
{
distance = Vector2.Distance(query.transform.position, target.transform.position);
TempPos = query;
}
}
target.transform.position = TempPos.transform.position;
}
else
{
target.transform.position = TempPos.transform.position;
}
}
else
{
// Hide Level Start UI
if (GameObject.Find("LevelName"))
{
Destroy(GameObject.Find("LevelName"));
}
if (GameObject.Find("BEGIN!"))
{
GameObject.Find("BEGIN!").transform.localScale = new Vector3(1, 1, 1);
}
if (Vector2.Distance(target.transform.position, transform.position) <= 0.5)
{
Destroy(GameObject.Find("BEGIN!"));
}
// Unlock player movement
// Look ahead feature based on right click
if (TargetingPlayer == true && Input.GetMouseButton(1) == true)
{
Vector3 pointer;
int speed = 10;
pointer = Camera.main.ScreenToWorldPoint(Input.mousePosition);
pointer.z = transform.position.z;
target.transform.position = Vector3.MoveTowards(new Vector2(player.transform.position.x, player.transform.position.y + 5), pointer, MaxCameraDistance);
}
// Reset target to player position
else if (TargetingPlayer == true && Input.GetMouseButton(1) == false)
{
target.transform.position = new Vector2(player.transform.position.x, player.transform.position.y + 5);
}
}
}
public void shakeCamera(float duration, float intensity)
{
shakeDuration = duration;
shakeAmount = intensity;
shakeInterval = 0.01f;
}
}

View File

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

View File

@@ -0,0 +1,18 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//Designed by Jacob Weedman
//Belongs to the "CurrentSector" GameObject in the "LevelSelector" scene
//V 0.0.1
public class CurrentSector : MonoBehaviour
{
void Update()
{
if (GameObject.Find("GameData").GetComponent<GameData>().CurrentSector != "0")
{
tag = GameObject.Find("GameData").GetComponent<GameData>().CurrentSector;
}
}
}

Some files were not shown because too many files have changed in this diff Show More