using ML.SDK;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;
namespace EnemyAi
{
public class EnemyAi : MonoBehaviour
{
public enum WayPoints { Arranged, Random };
public WayPoints PatrolPoint;
[HideInInspector]
public Transform Target;
NavMeshAgent agent;
public string PlayerName;
MLPlayer PlayerCharacter;
private float Distance;
private float Timer = 0.0f;
public float FireRate;
bool MoveToOtherPoint;
Animator Anim;
int ArrayNumber;
bool Do_once;
public Image HealthBarUI;
private float DistanceToPlayer;
public Transform Pos;
public Transform Pos1;
private bool CanISee;
private bool CanIShoot;
private bool Check;
private float Suspicion;
public Transform[] PatrolPoints;
private bool LineOne;
private bool LineTwo;
/// <summary>
/// ////
/// </summary>
public Transform TargetTransform;
private Transform aimTransform;
public Transform bone;
private float angleLimit = 90.0f;
//public float distanceLimit = 1.5f;
public Transform MuzzleFlash_Postion;
public GameObject MuzzleFlash;
private float AttackTime;
public float Damage;
public float Loudness = 1.0f;
bool Ready;
bool ReadyToHear;
private float randomDistance;
private float NavSpeed;
public Image notSign;
private TrailRenderer BulletTrail;
public AudioClip ShootingSFX;
AudioSource audioSource;
public int Ammo;
private int CurrentAmmo;
private bool CanIReload;
private float ReloadTime;
public AudioClip[] VoiceActing_Clips;
private float Health = 100.0f;
private bool Death = false;
bool IHeardSmothing = false;
float IHeardSmothingTime = 0.0f;
float DistanceToStone;
Vector3 Vector3ToStone;
public GameObject Bullet;
float bulletForce = 20.0f;
///////////// Destroy State //////////////////////
public enum DestroyED { Enable, Disable };
public DestroyED DestroyState;
[HideInInspector]
public int NumberDestroy;
float RandomDestroy;
public Material ArmMaterial;
public Material BodyMaterial;
public Material LegMaterial;
private MaterialPropertyBlock propertyBlock;
private float dissolveValue = 0f; // Tracks the dissolve progress
private bool isDying = false; // Tracks whether the robot is dissolving
public float dissolveSpeed = 0.1f; // Speed at which the dissolve happens
public GameObject DamageNumber;
public GameObject HeadObject;
public GameObject BloodVFX;
private bool hasbeenHeadshot = false;
const string EVENT_ENEMY_DIE = "EventEnemyDeath";
private EventToken tokenDeathEnemy;
private int MostRecentDamageNumber;
private IEnumerator WaitForSeconds(float duration)
{
yield return new WaitForSeconds(duration);
}
private IEnumerator WaitForInitialization()
{
yield return new WaitForSeconds(4);
MLPlayer nearestPlayer = MassiveLoopRoom.FindPlayerCloseToPosition(this.gameObject.transform.position);
AssignPlayerCharacter(nearestPlayer);
}
public void RandomizeRobotColors()
{
// Define a list of colors for randomization
Color[] colors = { Color.red, Color.yellow, Color.green, Color.blue, Color.white, Color.gray };
// Select a random color from the list
Color randomColor = colors[Random.Range(0, colors.Length)];
// Retrieve the materials
if (ArmMaterial != null)
{
ArmMaterial.color = randomColor;
}
else
{
Debug.LogError("ArmMaterial is not assigned!");
}
if (BodyMaterial != null)
{
BodyMaterial.color = randomColor;
}
else
{
Debug.LogError("BodyMaterial is not assigned!");
}
if (LegMaterial != null)
{
LegMaterial.color = randomColor;
}
else
{
Debug.LogError("LegMaterial is not assigned!");
}
Debug.Log($"Robot materials updated with color: {randomColor}");
}
// Callback for when a player is instantiated
private void OnPlayerInstantiated(ML.SDK.MLPlayer player)
{
// Debug.Log($"Player instantiated: {player.NickName}");
if (player.IsInstantiated)
{
MLPlayer nearestPlayer = MassiveLoopRoom.FindPlayerCloseToPosition(this.gameObject.transform.position);
AssignPlayerCharacter(nearestPlayer);
TargetTransform = PlayerCharacter.PlayerRoot.transform;
aimTransform = Pos;
PlayerName = PlayerCharacter.NickName;
}
}
// Assign the player character reference
private void AssignPlayerCharacter(MLPlayer player)
{
PlayerCharacter = player;
Debug.Log($"PlayerCharacter assigned: {PlayerCharacter.NickName}");
TargetTransform = PlayerCharacter.PlayerRoot.transform;
aimTransform = Pos;
PlayerName = PlayerCharacter.NickName;
// Unsubscribe from the event to avoid redundant calls
// Additional initialization logic if needed
}
private void OnEnemyDeath(object[] args)
{
Debug.Log($"Damage dealt to enemy : {args[0]}");
MostRecentDamageNumber = (int)args[0];
// Now apply the damage to the enemy
// this.Health -= (int)args[0];
// this.Check = true;
// Debug.Log($"Damage dealt to enemy: {Damage}");
}
private static readonly string[] namePrefixes =
{
"Shadow", "Inferno", "Venom", "Specter", "Rogue",
"Phantom", "Blight", "Warden", "Havoc", "Dread"
};
public string GenerateEnemyName()
{
string prefix = namePrefixes[UnityEngine.Random.Range(0, namePrefixes.Length)];
int randomNumber = UnityEngine.Random.Range(0, 1000000); // Generates a random number between 0 and 999999
return $"{prefix}_{randomNumber:D6}_Enemy"; // Appends the number as a zero-padded 6-digit string
}
private string UniqueName;
// Start is called before the first frame update
void Start()
{
Debug.Log("Begin ai");
Anim = GetComponent<Animator>();
agent = GetComponent<NavMeshAgent>();
Debug.Log("Retrieving PatrolPoints");
tokenDeathEnemy = this.AddEventHandler(EVENT_ENEMY_DIE, OnEnemyDeath);
this.gameObject.name = GenerateEnemyName();
Debug.Log($"Assigned unique name : {this.gameObject.name}");
if (PatrolPoints == null || PatrolPoints.Length == 0)
{
Debug.LogError("PatrolPoints is null or empty. Ensure patrol points are assigned in the spawner.");
return;
}
Target = PatrolPoints[Random.Range(0, PatrolPoints.Length)];
propertyBlock = new MaterialPropertyBlock();
// Pos = transform.Find("Pos").GetComponent<Transform>();
// Pos1 = transform.Find("Pos1").GetComponent<Transform>();
StartCoroutine(WaitForInitialization());
MLPlayer nearestPlayer = MassiveLoopRoom.FindPlayerCloseToPosition(this.gameObject.transform.position);
AssignPlayerCharacter(nearestPlayer);
Debug.Log("PatrolPoints Retrieved");
// RandomizeRobotColors();
// MassiveLoopRoom.OnPlayerInstantiated += OnPlayerInstantiated;
/*
// If players are already instantiated when this script starts, handle it immediately
MLPlayer nearestPlayer = MassiveLoopRoom.FindPlayerCloseToPosition(this.gameObject.transform.position);
if (nearestPlayer != null)
{
AssignPlayerCharacter(nearestPlayer);
}
*/
MuzzleFlash_Postion = transform.Find("Skeleton/Hips/Spine/Chest/UpperChest/Right_Shoulder/Right_UpperArm/Right_LowerArm/Right_Hand/Weapons_Position/MuzzleFlash_Position").GetComponent<Transform>();
// HealthBarUI = transform.Find("Suspicion_Canvas/Full").GetComponent<Image>();
// notSign = transform.Find("Suspicion_Canvas/Not_Sign").GetComponent<Image>();
notSign.gameObject.SetActive(false);
randomDistance = Random.Range(3.0f, 10.0f);
// LineRenderer BulletTrail = GetComponent<LineRenderer>();
audioSource = GetComponent<AudioSource>();
CurrentAmmo = Ammo;
// BulletTrail = transform.Find("Skeleton/Hips/Spine/Chest/UpperChest/Right_Shoulder/Right_UpperArm/Right_LowerArm/Right_Hand/Weapons_Position/MuzzleFlash_Position/BulletTrace").GetComponent<TrailRenderer>();
// bone = transform.Find("Skeleton/Hips/Spine/Chest").GetComponent<Transform>();
RandomDestroy = Random.Range(8.0f, 12.0f);
////////////////////////////// switch (HealthBarState) //////////////////////////////
switch (DestroyState)
{
case DestroyED.Enable:
{
NumberDestroy = 0;
break;
}
case DestroyED.Disable:
{
NumberDestroy = 1;
break;
}
}
}
private void ApplyDissolveValue(float dissolveValue)
{
// Find all renderers on this robot (assumes the robot has multiple parts)
Renderer[] renderers = GetComponentsInChildren<Renderer>();
foreach (Renderer renderer in renderers)
{
// Set the dissolve amount using the MaterialPropertyBlock
renderer.GetPropertyBlock(propertyBlock);
propertyBlock.SetFloat("_DissolveAmount", dissolveValue);
renderer.SetPropertyBlock(propertyBlock);
}
}
public void GetWayPoints(Vector3 waypointOne, Vector3 waypointTwo, Vector3 waypointThree)
{
Debug.Log("Get Waypoint function called");
// Create a new Transform array to store the patrol points
Transform[] randomPatrolPoints_fromSpawner = new Transform[3];
// Create GameObjects for each waypoint and assign their positions
randomPatrolPoints_fromSpawner[0] = CreateTemporaryWaypoint(waypointOne, "Waypoint_1");
randomPatrolPoints_fromSpawner[1] = CreateTemporaryWaypoint(waypointTwo, "Waypoint_2");
randomPatrolPoints_fromSpawner[2] = CreateTemporaryWaypoint(waypointThree, "Waypoint_3");
// Assign the patrol points to the PatrolPoints property
this.PatrolPoints = randomPatrolPoints_fromSpawner;
Debug.Log($"Assigned patrol points: {waypointOne}, {waypointTwo}, {waypointThree}");
}
// Helper function to create a temporary GameObject for a waypoint
private Transform CreateTemporaryWaypoint(Vector3 position, string name)
{
// Create a temporary GameObject to represent the waypoint
GameObject tempWaypoint = new GameObject(name);
tempWaypoint.transform.position = position;
// tempWaypoint.transform.parent = this.transform; // Optional: Parent it to the AI for organization
return tempWaypoint.transform;
}
// Update is called once per frame
void Update()
{
if (PlayerCharacter == null) return;
// if (!MassiveLoopClient.IsMasterClient) return;
if (IHeardSmothingTime > 0.0f)
{
IHeardSmothingTime -= Time.deltaTime;
}
if (IHeardSmothingTime <= 0.0f)
{
IHeardSmothing = false;
notSign.gameObject.SetActive(false);
}
if(MassiveLoopClient.IsMasterClient)
{
DistanceToStone = Vector3.Distance(Vector3ToStone, transform.position);
}
HealthBarUI.fillAmount = Suspicion / 100;
///////////////////// Attack //////////////////////////////////////
if (DistanceToPlayer < 15.0f && Check == false)
{
Anim.SetBool("Idle_2", false);
}
if (DistanceToPlayer >= 15.0f && Check == false)
{
Anim.SetBool("Idle_2", true);
}
//TODO :
/*
* Self Note this is OK to keep as it is. But we do need to create
* a synchronized set of functions that will set these values
* for when other players kill the enemy.
*
* The idea is that when THEY kill the enemy, the enemy will need to
* call the network function EventTarget.All to update all the other players
* of this NPC's demise.
*
* Should be easy enough to implement, I am just feeling lazy at the moment. :P
*/
if (Health <= 0.0f)
{
if (hasbeenHeadshot)
{
HeadObject.transform.localScale = Vector3.zero;
BloodVFX.SetActive(true);
}
agent.speed = 0.0f;
Death = true;
// dissolveValue = 0f;
dissolveValue += Time.deltaTime * dissolveSpeed;
dissolveValue = Mathf.Clamp01(dissolveValue); // Ensure it stays between 0 and 1
ApplyDissolveValue(dissolveValue);
// Debug.Log("Invoke network death");
// this.InvokeNetwork(EVENT_ENEMY_DIE, EventTarget.All, null, this.gameObject.GetInstanceID());
this.gameObject.GetComponent<CapsuleCollider>().enabled = false;
// this.gameObject.GetComponent<MLSynchronizer>().enabled = false;
// this.gameObject.GetComponent<TransformSyncModule>().enabled = false;
if (!MassiveLoopClient.IsMasterClient)
{
// Debug.Log("Checking all child rigidbodies to ensure they are not kinematic.");
// Get all Rigidbody components in children of this GameObject
Rigidbody[] childRigidbodies = GetComponentsInChildren<Rigidbody>();
foreach (Rigidbody rb in childRigidbodies)
{
if (rb.isKinematic)
{
// Debug.LogWarning($"Rigidbody on {rb.gameObject.name} is kinematic. Setting it to non-kinematic.");
rb.isKinematic = false; // Make the Rigidbody non-kinematic
}
}
}
Anim.SetInteger("DeathRandom", Random.Range(0, 3));
Anim.SetTrigger("Death");
Anim.enabled = false;
HealthBarUI.gameObject.SetActive(false);
notSign.gameObject.SetActive(false);
transform.GetComponent<CapsuleCollider>().enabled = false;
DeathFunction();
}
if (LineOne == true)
{
CanISee = true;
CanIShoot = true;
}
if (LineOne == false)
{
CanISee = false;
CanIShoot = false;
}
if (Check == true && Death == false)
{
AttackTime -= Time.deltaTime;
// Debug.Log("Check evaluated true, Death evaluated false, attempting next attack if statement"); this is ok
// Debug.Log($"Attack time evaluated <= 0.0, Distance to player : {DistanceToPlayer}, CanIShoot : {CanIShoot}, CanIReload : {CanIReload}, CurrentAmmo : {CurrentAmmo}");
if (AttackTime <= 0.0f && DistanceToPlayer <= 20.0f && CanIShoot && !CanIReload && CurrentAmmo > 0)
{
/*
Debug.Log($"Attack time evaluated <= 0.0, Distance to player : {DistanceToPlayer}, CanIShoot : {CanIShoot}, CanIReload : {CanIReload}, CurrentAmmo : {CurrentAmmo}");
if (AttackTime <= 0.0f)
{
Debug.Log("AttackTime reached zero");
}
if (DistanceToPlayer <= 20.0f)
{
Debug.Log($"Distance to player: {DistanceToPlayer}");
}
if (CanIShoot)
{
Debug.Log("Enemy can shoot");
}
if (!CanIReload)
{
Debug.Log("Enemy is not reloading");
}
if (CurrentAmmo > 0)
{
Debug.Log($"Current ammo: {CurrentAmmo}");
}
*/
AttackTime = FireRate;
CurrentAmmo--;
// Play attack effects
if (MuzzleFlash != null)
{
Object.Instantiate(MuzzleFlash, MuzzleFlash_Postion.position, MuzzleFlash_Postion.rotation);
}
if (ShootingSFX != null)
{
audioSource.PlayOneShot(ShootingSFX, 0.7f);
}
if (BulletTrail != null)
{
BulletTrail.enabled = true;
BulletTrail.SetPosition(0, MuzzleFlash_Postion.transform.position);
BulletTrail.SetPosition(1, MuzzleFlash_Postion.transform.position + MuzzleFlash_Postion.forward * -1000);
}
// Call shoot logic
shoot();
EventAttack();
}
if (AttackTime > 0.5f)
{
BulletTrail.enabled = false;
}
}
/////////////////////// Read to Hearing ///////////////////////////////////
/*
MakeNoise EnemyNoise = PlayerCharacter.GetComponent<MakeNoise>();
if (EnemyNoise != null)
{
if (Ready == true && EnemyNoise.Noise == true)
{
Check = true;
}
}
*/
////////// call all funtions ///////////
if (Death == false)
{
// CloudVariables.PushEvent
LookAtTarget();
LookAtNotSing();
SeePlayer();
// SeePlayerTwo();
// HearingRange();
}
//////////////// Distance btween target and enemy
DistanceToPlayer = Vector3.Distance(PlayerCharacter.PlayerRoot.transform.position, transform.position);
//////////////// Angle or SightSystem /////////////////////////////////
Vector3 targetDir = PlayerCharacter.PlayerRoot.transform.position - transform.position;
float angle = Vector3.Angle(targetDir, transform.forward);
if (angle < 90.0f && DistanceToPlayer < 15.0f && CanISee == true)
{
if (Suspicion <= 100)
{
Suspicion += 0.2f;
}
}
if (angle < 90.0f && DistanceToPlayer < 10.0f && CanISee == true && Check == false)
{
if (Suspicion <= 100)
{
Suspicion += 2.7f;
}
}
if (angle >= 90.0f || DistanceToPlayer > 15.0f || CanISee == false)
{
if (Suspicion >= 0)
{
Suspicion -= 0.2f;
}
}
///////// active Suspicion //////////////////////////
if (Suspicion <= 0.0f || Check == true && Death == false)
{
HealthBarUI.gameObject.SetActive(false);
}
if (Suspicion > 0.0f && Check == false && Death == false)
{
HealthBarUI.gameObject.SetActive(true);
notSign.gameObject.SetActive(false);
}
///////////////////////////////////////////////////////
if (Suspicion >= 100)
{
Check = true;
notSign.gameObject.SetActive(false);
}
if (DistanceToPlayer < 1.0f)
{
Check = true;
// Debug.Log($"AI is very close to player Check bool : {Check}");
}
// if(Timer > 0.0f) { }
if (Timer <= 0.0f)
{
/*
Vector3 lTargetDir = Target.position - transform.position;
lTargetDir.y = 0.0f;
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(lTargetDir), Time.time * 1.0f);
*/
if (PatrolPoint == WayPoints.Random)
{
Target = PatrolPoints[Random.Range(0, PatrolPoints.Length)];
}
if (PatrolPoint == WayPoints.Arranged)
{
Target = PatrolPoints[ArrayNumber];
}
Timer = 1.0f;
}
if (MassiveLoopClient.IsMasterClient)
{
if (IHeardSmothing == false)
{
agent.SetDestination(Target.position);
}
if (IHeardSmothing == true)
{
agent.SetDestination(Vector3ToStone);
}
if (Check == true && Death == false)
{
Anim.SetBool("Check", true);
agent.SetDestination(PlayerCharacter.PlayerRoot.transform.position);
//
if (DistanceToPlayer >= randomDistance || CanISee == false)
{
if (Death == false)
{
float[] numbers = { 6.5f, 3.2f, 0.0f };
int randomIndex = Random.Range(0, 3);
float randomFloatFromNumbers = numbers[randomIndex];
Anim.SetBool("Rifle_Walk", true);
agent.speed = 2.5f;
NavSpeed = 1.0f;
}
}
if (DistanceToPlayer < randomDistance && CanISee == true || CanIReload == true)
{
if (Death == false)
{
Anim.SetBool("Rifle_Walk", false);
NavSpeed = 0.0f;
LookAtToPlayer();
}
}
}
if (NavSpeed == 0.0f)
{
agent.speed = 0.0f;
}
if (Check == false)
{
//////////////// Distance between target and enemy
Distance = Vector3.Distance(Target.position, transform.position);
if (Distance >= 0.5f)
{
Do_once = true;
}
if (Distance < 0.5f)
{
/////// increased one ///////////////
if (Do_once == true)
{
ArrayNumber += 1;
}
////////////////////////////////////
if (ArrayNumber >= PatrolPoints.Length)
{
ArrayNumber = 0;
}
///////////////////////////////
Timer -= 0.1f * Time.deltaTime;
Do_once = false;
}
if (Distance <= 0.3f || DistanceToStone <= 0.06f)
{
agent.speed = 0.0f;
}
if (Distance <= 0.2f || DistanceToStone <= 0.2f)
{
Anim.SetBool("Walk", false);
}
if (Distance > 0.2f && Death == false || DistanceToStone > 0.06f && Death == false)
{
agent.speed = 1.5f;
}
if (Distance > 0.2f && DistanceToStone > 0.2f)
{
if (Death == false)
{
Anim.SetBool("Walk", true);
}
}
}
if (CurrentAmmo <= 0)
{
Reload();
}
}
/////////////////////// Read to Hearing ///////////////////////////////////
/*
MakeNoiseByPressingKey ZombieNoise = (MakeNoiseByPressingKey)PlayerCharacter.GetComponent(typeof(MakeNoiseByPressingKey));
if (ZombieNoise != null)
{
if (ReadyToHear == true && ZombieNoise.Noise == true)
{
Check = true;
}
}
*/
}
//////////////////// //////////////////////////
///
public void EventAttack()
{
RaycastHit Riflehit;
float Dis = 1000f;
Vector3 fromPosition = transform.position;
Vector3 toPosition = new Vector3(PlayerCharacter.PlayerRoot.transform.position.x, PlayerCharacter.PlayerRoot.transform.position.y, PlayerCharacter.PlayerRoot.transform.position.z);
Vector3 direction = toPosition - fromPosition;
// Debug.DrawRay(Pos.position, direction, Color.cyan);
if (Physics.Raycast(Pos.position, direction, out Riflehit, Dis))
{
if (Riflehit.transform.gameObject.name == PlayerName)
{
// Debug.Log("Hit");
Riflehit.transform.gameObject.SendMessage("PlayerDamage", Damage);
BulletTrail.SetPosition(1, PlayerCharacter.PlayerRoot.transform.position);
// BulletTrail.SetPosition(1, MuzzleFlash_Postion.transform.position + MuzzleFlash_Postion.transform.forward * range);
BulletTrail.SetPosition(1, PlayerCharacter.PlayerRoot.transform.position);
}
}
}
void Reload()
{
if (ReloadTime > 0.0f)
{
Anim.SetBool("Reload", true);
ReloadTime -= 0.1f;
CanIReload = true;
}
if (ReloadTime <= 0.0f)
{
Anim.SetBool("Reload", false);
CurrentAmmo = Ammo;
CanIReload = false;
ReloadTime = 14.0f;
}
}
void shoot()
{
GameObject bullet = Instantiate(Bullet, MuzzleFlash_Postion.position, MuzzleFlash_Postion.rotation);
Rigidbody rb = bullet.GetComponent<Rigidbody>();
rb.AddForce(MuzzleFlash_Postion.up * bulletForce,ForceMode.Impulse);
bullet.transform.LookAt(PlayerCharacter.PlayerRoot.transform.position);
}
/// <summary>
/// ///////////////////////
/// </summary>
void SeePlayer()
{
// Debug.Log("Seeking...");
RaycastHit hit;
float range = 1000f;
Vector3 fromPosition = Pos.transform.position;
Vector3 toPosition = new Vector3(PlayerCharacter.PlayerRoot.transform.position.x, PlayerCharacter.PlayerRoot.transform.position.y + 1, PlayerCharacter.PlayerRoot.transform.position.z);
Vector3 direction = toPosition - fromPosition;
Debug.DrawRay(Pos.position, direction, Color.cyan);
if (Physics.Raycast(Pos.position, direction, out hit, range))
{
// Debug.Log($"My raycast hit an object : {hit.transform.gameObject.name}");
if (hit.transform.gameObject.name.Contains("PlayerRoot"))
{
// If the hit GameObject has an MLPlayer component
LineOne = true;
// Debug.Log("I can see the player (Line One)");
}
else
{
// If the hit GameObject does not have an MLPlayer component
LineOne = false;
}
if (hit.transform.gameObject.name.Contains("PlayerRoot"))
{
// If the hit GameObject has an MLPlayer component
CanIShoot = true;
// Debug.Log("I can see the player");
}
else
{
// If the hit GameObject does not have an MLPlayer component
CanIShoot = false;
}
}
}
///////////////*******************////////////////////////////////////
void SeePlayerTwo()
{
RaycastHit hit;
float range = 1000f;
Vector3 fromPosition = Pos1.transform.position;
Vector3 toPosition = new Vector3(PlayerCharacter.PlayerRoot.transform.position.x, PlayerCharacter.PlayerRoot.transform.position.y + 1, PlayerCharacter.PlayerRoot.transform.position.z);
Vector3 direction = toPosition - fromPosition;
Debug.DrawRay(Pos.position, direction, Color.red);
if (Physics.Raycast(Pos1.position, direction, out hit, range))
{
if (hit.transform.gameObject.name == PlayerName)
{
LineTwo = true;
}
if (hit.transform.gameObject.name != PlayerName)
{
LineTwo = false;
}
/*
if (hit.transform.gameObject.name == PlayerName)
{
CanIShoot = true;
}
if (hit.transform.gameObject.name != PlayerName)
{
CanIShoot = false;
}
*/
}
}
//// LookAtTarget ///
///
void LookAtTarget()
{
var rotation = Quaternion.LookRotation(PlayerCharacter.PlayerRoot.transform.position - HealthBarUI.gameObject.transform.position);
rotation.x = 0; //This is for limiting the rotation to the y axis. I needed this for my project so just
rotation.z = 0; // delete or add the lines you need to have it behave the way you want.
HealthBarUI.gameObject.transform.rotation = Quaternion.Slerp(HealthBarUI.gameObject.transform.rotation, rotation, Time.deltaTime * 100.0f);
}
void LookAtNotSing()
{
var rotation = Quaternion.LookRotation(PlayerCharacter.PlayerRoot.transform.position - notSign.gameObject.transform.position);
rotation.x = 0; //This is for limiting the rotation to the y axis. I needed this for my project so just
rotation.z = 0; // delete or add the lines you need to have it behave the way you want.
notSign.gameObject.transform.rotation = Quaternion.Slerp(notSign.gameObject.transform.rotation, rotation, Time.deltaTime * 100.0f);
}
//// LookAtTarget ///
///
void LookAtToPlayer()
{
var rotation = Quaternion.LookRotation(PlayerCharacter.PlayerRoot.transform.position - transform.position);
rotation.x = 0; //This is for limiting the rotation to the y axis. I needed this for my project so just
rotation.z = 0; // delete or add the lines you need to have it behave the way you want.
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * 1500.0f);
}
/// <summary>
/// //
/// </summary>
/// <returns></returns>
Vector3 GetTargetPosition()
{
if (TargetTransform == null || aimTransform == null)
{
Debug.LogError("TargetTransform or aimTransform is not assigned!");
return PlayerCharacter.PlayerRoot.transform.position;
}
Vector3 targetDirection = TargetTransform.position - aimTransform.position;
Vector3 aimDirection = aimTransform.forward;
if (targetDirection == Vector3.zero || aimDirection == Vector3.zero)
{
Debug.LogError("TargetDirection or AimDirection is zero!");
return Vector3.zero;
}
float blendOut = 0.0f;
float targetAngle = Vector3.Angle(targetDirection, aimDirection);
if (targetAngle > angleLimit)
{
blendOut += (targetAngle - angleLimit) / 50.0f;
}
Vector3 direction = Vector3.Slerp(targetDirection, aimDirection, blendOut);
return aimTransform.position + direction;
}
void LateUpdate()
{
if (PlayerCharacter == null) return;
if (Check && !Death)
{
if (TargetTransform == null || aimTransform == null)
{
// Debug.LogError("TargetTransform or aimTransform is null in LateUpdate!");
TargetTransform = PlayerCharacter.PlayerRoot.transform;
aimTransform = Pos;
PlayerName = PlayerCharacter.NickName;
}
Vector3 targetPosition = GetTargetPosition();
// Debug.Log($"Target Position: {targetPosition}");
AimAtTarget(bone, targetPosition);
}
}
private void AimAtTarget(Transform bone, Vector3 targetPosition)
{
Vector3 aimDirction = aimTransform.forward;
Vector3 targetDirction = targetPosition - aimTransform.position;
Quaternion aimTowards = Quaternion.FromToRotation(aimDirction, targetDirction);
bone.rotation = aimTowards * bone.rotation;
}
/////////////////// ////////////////////////////////////////////////
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, Loudness);
}
void HearingRange()
{
Collider[] hitColliders = Physics.OverlapSphere(transform.position, Loudness);
foreach (Collider hitCollider in hitColliders)
{
///////////////////////***************///////////////////////////////////////////
///
if (hitCollider.gameObject.name == PlayerName)
{
// Debug.Log(hitCollider.gameObject.name);
ReadyToHear = true;
}
////////////////////***************/////////////////////////////////////////////
MakeNoise MakeNoiseCOL = (MakeNoise) hitCollider.gameObject.GetComponent(typeof(MakeNoise));
if (MakeNoiseCOL != null)
{
if (MakeNoiseCOL.NoiseTime > 0.0f && Distance <= 0.5f)
{
MakeNoiseCOL.NoiseTime -= Time.deltaTime;
}
// target.position = MakeNoiseCOL.VectorTarget;
if (IHeardSmothing == true)
{
// agent.destination = MakeNoiseCOL.VectorTarget;
Vector3ToStone = MakeNoiseCOL.VectorTarget;
}
// agent.SetDestination(PlayerCharacter.position);
// Target.position = MakeNoiseCOL.VectorTarget;
if (MakeNoiseCOL.DoOnce == true && Check == false)
{
if (VoiceActing_Clips.Length > 0)
{
audioSource.PlayOneShot(VoiceActing_Clips[Random.Range(0, VoiceActing_Clips.Length)], 0.7f);
}
}
IHeardSmothing = true;
IHeardSmothingTime = 10.0f;
// Debug.Log(hitCollider.gameObject.name);
notSign.gameObject.SetActive(true);
// Target = MakeNoiseCOL.NoiseTarget;
if (MakeNoiseCOL.NoiseTime <= 0.0f)
{
if (PatrolPoint == WayPoints.Random)
{
Target = PatrolPoints[Random.Range(0, PatrolPoints.Length)];
}
if (PatrolPoint == WayPoints.Arranged)
{
Target = PatrolPoints[ArrayNumber];
}
if (Target == null)
{
Target = PatrolPoints[0];
}
// Destroy(MakeNoiseCOL);
// Destroy(MakeNoiseCOL.gameObject);
}
Ready = true;
}
if (MakeNoiseCOL == null)
{
Ready = false;
}
if (Ready == true && MakeNoiseCOL.Noise == true)
{
Check = true;
}
EnemyAi OtherEnemyAi = (EnemyAi)hitCollider.gameObject.GetComponent(typeof(EnemyAi));
if (OtherEnemyAi != null)
{
if (OtherEnemyAi.Check == true)
{
// Debug.Log("IhearYou");
if (Suspicion <= 100)
{
Suspicion += 3.0f;
}
// OtherEnemyAi.Check = true;
}
}
}
}
//TODO : the enemy should target the player that damaged them.
public void EnemyDamage(int Damage, string DamageType, bool isHeadShot, string FromWho)
{
// Instantiate the damage number prefab at the HealthBarUI position
// if (MassiveLoopClient.IsMasterClient)
// {
if (MassiveLoopClient.IsMasterClient)
{
this.InvokeNetwork(EVENT_ENEMY_DIE, EventTarget.All, null, Damage);
}
// this.InvokeNetwork(EVENT_ENEMY_DIE, EventTarget.Others, null, Damage, DamageType, isHeadShot, this.gameObject.name);
GameObject damageTextObject = Instantiate(DamageNumber, HealthBarUI.transform.position, Quaternion.identity);
// Debug.Log($"Damage type : {DamageType}");
// Set the damage number text
TextMeshPro damageText = damageTextObject.GetComponent<TextMeshPro>();
if (damageText != null)
{
/* This is for the Enums but that can't be used yet.
switch (DamageType)
{
case ElementalType.Normal:
damageText.color = Color.white;
break;
case ElementalType.Fire:
damageText.color = Color.yellow;
break;
case ElementalType.Ice:
damageText.color = Color.cyan;
break;
case ElementalType.Lightning:
damageText.color = Color.HSVToRGB(0.75f, 1f, 1f); // Purple in HSV
break;
case ElementalType.Poison:
damageText.color = Color.green;
break;
default:
Debug.LogWarning($"Unhandled damage type: {DamageType}");
damageText.color = Color.white; // Default color fallback
break;
}
*/
switch (DamageType)
{
case "Normal":
damageText.color = Color.white;
break;
case "Fire":
damageText.color = Color.yellow;
break;
case "Ice":
damageText.color = Color.cyan;
break;
case "Lightning":
damageText.color = Color.HSVToRGB(0.75f, 1f, 1f); // Purple in HSV
break;
case "Poison":
damageText.color = Color.green;
break;
default:
Debug.LogWarning($"Unhandled damage type: {DamageType}");
damageText.color = Color.white; // Default color fallback
break;
}
if (isHeadShot)
{
damageText.color = Color.red; // Default color fallback
hasbeenHeadshot = true;
}
damageText.text = MostRecentDamageNumber.ToString();
// Debug.Log($"Damage displayed: {damageText.text}");
}
else
{
Debug.LogWarning("DamageNumber prefab does not have a TextMeshPro component.");
}
// Now apply the damage to the enemy
Health -= MostRecentDamageNumber;
AssignPlayerCharacter(MassiveLoopRoom.FindPlayerByName(FromWho));
Debug.Log($"Enemy targeting player that attacked me. {(FromWho)}");
Check = true;
// Debug.Log($"Damage dealt to enemy: {Damage}");
// }
}
void DeathFunction()
{
if (NumberDestroy == 0)
{
StartCoroutine(TimeToDestroy());
}
}
IEnumerator TimeToDestroy()
{
yield return new WaitForSeconds(RandomDestroy);
if (MassiveLoopClient.IsMasterClient)
{
Destroy(gameObject);
}
else { this.gameObject.SetActive(false); }
}
}
}