update 1.2.5

This commit is contained in:
2025-07-20 10:18:13 +08:00
parent 5396d3e4b8
commit 9d22e1c192
17 changed files with 313 additions and 115 deletions
@@ -15,12 +15,13 @@ namespace EmeraldAI.SoundDetection
#region Sound Detector Variables
public GameObject DetectedAttractModifier;
public ThreatLevels CurrentThreatLevel = ThreatLevels.Unaware;
public LayerMask DetectableLayers = 1;
public float CurrentThreatAmount;
public float CheckIncrement = 0.25f;
public float MinVelocityThreshold = 0.5f;
public float AttentionRate = 0.1f;
public float MinVelocityThreshold = 0.5f;
public float TargetVelocityFactor = 0.3f;
public float DistanceFactor = 0.1f;
public float AttentionFalloff = 0.05f;
public float FalloffDealy = 3f;
public float DelayUnawareSeconds = 5f;
public float AttractModifierCooldown = 5;
public bool MovingTargetDetected;
@@ -48,15 +49,16 @@ namespace EmeraldAI.SoundDetection
//Private variables
float DelayUnawareTimer = 0;
float CheckIncrementTimer = 0;
EmeraldSystem EmeraldComponent;
EmeraldDetection EmeraldDetection;
EmeraldMovement EmeraldMovement;
bool ArrivedAtDestination;
Coroutine CurrentReactionCoroutine;
Coroutine CalculateMovementCoroutine;
Coroutine RotateTowardsCoroutine;
float TimeSinceLastAttractModifier;
bool SoundDetectorEnabled = true;
float FalloffDelayTimer;
[SerializeField]
public List<TargetDataClass> CurrentTargetData = new List<TargetDataClass>();
@@ -78,6 +80,7 @@ namespace EmeraldAI.SoundDetection
NoiseLevel = m_NoiseLevel;
}
}
#endregion
#region Editor Variables
@@ -89,6 +92,14 @@ namespace EmeraldAI.SoundDetection
#endregion
void Start()
{
InitializeSoundDetector();
}
/// <summary>
/// Initializes the Sound Detector script.
/// </summary>
void InitializeSoundDetector ()
{
CurrentThreatAmount = 0;
TimeSinceLastAttractModifier = AttractModifierCooldown;
@@ -126,24 +137,18 @@ namespace EmeraldAI.SoundDetection
return;
}
CheckIncrementTimer += Time.deltaTime;
if (CheckIncrementTimer >= CheckIncrement)
//Add each target from LineOfSightTargets to CurrentTargetData, given that it hasn't already been added and it has the EmeraldComponent.PlayerTag.
for (int i = 0; i < EmeraldDetection.LineOfSightTargets.Count; i++)
{
//Add each target from LineOfSightTargets to CurrentTargetData, given that it hasn't already been added and it has the EmeraldComponent.PlayerTag.
for (int i = 0; i < EmeraldDetection.LineOfSightTargets.Count; i++)
if (!CurrentTargetData.Exists(x => x.Target == EmeraldDetection.LineOfSightTargets[i].transform))
{
if (!CurrentTargetData.Exists(x => x.Target == EmeraldDetection.LineOfSightTargets[i].transform))
{
if (!EmeraldDetection.LineOfSightTargets[i].gameObject.CompareTag(EmeraldDetection.PlayerTag)) continue; //Skip non-player targets
float DistanceFromTarget = Vector3.Distance(transform.position, EmeraldDetection.LineOfSightTargets[i].transform.position);
CurrentTargetData.Add(new TargetDataClass(EmeraldDetection.LineOfSightTargets[i].transform, EmeraldDetection.LineOfSightTargets[i].transform.position, MinVelocityThreshold, DistanceFromTarget, 0));
}
if (!EmeraldDetection.LineOfSightTargets[i].gameObject.CompareTag(EmeraldDetection.PlayerTag)) continue; //Skip non-player targets
float DistanceFromTarget = Vector3.Distance(transform.position, EmeraldDetection.LineOfSightTargets[i].transform.position);
CurrentTargetData.Add(new TargetDataClass(EmeraldDetection.LineOfSightTargets[i].transform, EmeraldDetection.LineOfSightTargets[i].transform.position, MinVelocityThreshold, DistanceFromTarget, 0));
}
UpdateTargetData();
CheckIncrementTimer = 0;
}
UpdateTargetData();
}
private void Update()
@@ -153,11 +158,32 @@ namespace EmeraldAI.SoundDetection
if (!EmeraldComponent.AnimationComponent.IsDead && SoundDetectorEnabled)
{
TimeSinceLastAttractModifier += Time.deltaTime;
if (EmeraldDetection.LineOfSightTargets.Count > 0 || CurrentThreatLevel != ThreatLevels.Unaware)
if (EmeraldDetection.LineOfSightTargets.Count > 0)
{
CheckForSounds();
CheckEvents();
CalculateThreatLevel();
}
if (CurrentThreatAmount > 0 && EmeraldDetection.LineOfSightTargets.Count == 0)
{
if (CurrentTargetData.Count > 0)
{
SuspiciousTriggered = false;
AwareTriggered = false;
CurrentTargetData.Clear();
}
FalloffDelayTimer += Time.deltaTime; //Allow a brief resting period between when a moving target is detected and when it's not.
if (FalloffDelayTimer > FalloffDealy) CurrentThreatAmount = Mathf.MoveTowards(CurrentThreatAmount, 0, AttentionFalloff * Time.deltaTime);
CurrentThreatAmount = Mathf.Clamp(CurrentThreatAmount, 0f, 1f);
if (CurrentThreatAmount < 0.001f)
{
InvokeReactionList(UnawareReaction);
UnawareEvent.Invoke();
DelayUnawareTimer = 0;
ClearThreats();
}
}
}
}
@@ -169,20 +195,25 @@ namespace EmeraldAI.SoundDetection
{
for (int i = 0; i < CurrentTargetData.Count; i++)
{
//Calculate the velocity of each target by storing its previous distance and comparing it to its current distance (with each CheckIncrement).
float DistanceFromTarget = Vector3.Distance(transform.position, CurrentTargetData[i].Target.position);
float TargetVelocity = (CurrentTargetData[i].Target.position - CurrentTargetData[i].LastPosition).magnitude;
//float DistanceVariable = (EmeraldComponent.AttackDistance / DistanceFromTarget);
CurrentTargetData[i].LastPosition = CurrentTargetData[i].Target.position;
CurrentTargetData[i].NoiseLevel = TargetVelocity;
if (CurrentTargetData[i].Target != null)
{
//Calculate the velocity of each target by storing its previous distance and comparing it to its current distance (with each CheckIncrement).
float DistanceFromTarget = Vector3.Distance(transform.position, CurrentTargetData[i].Target.position);
float TargetVelocity = (CurrentTargetData[i].Target.position - CurrentTargetData[i].LastPosition).magnitude / Time.deltaTime;
float MitigationValue = (1f - Mathf.Clamp01(DistanceFromTarget / EmeraldComponent.DetectionComponent.DetectionRadius));
if (TargetVelocity >= MinVelocityThreshold)
{
MovingTargetDetected = true;
}
else if (CurrentThreatAmount > 0 && TargetVelocity < MinVelocityThreshold)
{
MovingTargetDetected = false;
CurrentTargetData[i].LastPosition = CurrentTargetData[i].Target.position;
CurrentTargetData[i].NoiseLevel = TargetVelocity;
CalculateThreatLevel(TargetVelocity, MitigationValue);
if (TargetVelocity > MinVelocityThreshold)
{
MovingTargetDetected = true;
}
else if (CurrentThreatAmount > 0 && TargetVelocity <= MinVelocityThreshold)
{
MovingTargetDetected = false;
}
}
}
}
@@ -190,15 +221,20 @@ namespace EmeraldAI.SoundDetection
/// <summary>
/// Simply increases or descreases the CurrentThreatLevel depending on whether or not detected targets are moving.
/// </summary>
void CalculateThreatLevel ()
void CalculateThreatLevel (float CurrentTargetVelocity, float MitigationValue)
{
if (MovingTargetDetected)
{
CurrentThreatAmount += Time.deltaTime * AttentionRate;
FalloffDelayTimer = 0;
float attentionEffect = AttentionRate * Time.deltaTime;
attentionEffect += (TargetVelocityFactor * CurrentTargetVelocity * 0.01f) * Time.deltaTime;
attentionEffect += (DistanceFactor * MitigationValue) * Time.deltaTime;
CurrentThreatAmount = Mathf.MoveTowards(CurrentThreatAmount, 1, attentionEffect);
}
else
{
CurrentThreatAmount -= Time.deltaTime * AttentionFalloff;
FalloffDelayTimer += Time.deltaTime; //Allow a brief resting period between when a moving target is detected and when it's not.
if (FalloffDelayTimer > FalloffDealy) CurrentThreatAmount = Mathf.MoveTowards(CurrentThreatAmount, 0, AttentionFalloff * Time.deltaTime);
}
CurrentThreatAmount = Mathf.Clamp(CurrentThreatAmount, 0f, 1f);
@@ -209,7 +245,11 @@ namespace EmeraldAI.SoundDetection
/// </summary>
void CancelAll ()
{
StopAllCoroutines();
if (CurrentReactionCoroutine != null) StopCoroutine(CurrentReactionCoroutine);
if (CalculateMovementCoroutine != null) StopCoroutine(CalculateMovementCoroutine);
if (RotateTowardsCoroutine != null) StopCoroutine(RotateTowardsCoroutine);
EmeraldComponent.MovementComponent.RotateTowardsTarget = false;
EmeraldComponent.m_NavMeshAgent.isStopped = false;
CurrentTargetData.Clear();
EmeraldComponent.MovementComponent.ChangeWanderType((EmeraldMovement.WanderTypes)EmeraldMovement.StartingWanderingType);
}
@@ -314,7 +354,7 @@ namespace EmeraldAI.SoundDetection
//Ensure the AI is using its Starting WanderType.
EmeraldComponent.MovementComponent.ChangeWanderType((EmeraldMovement.WanderTypes)EmeraldMovement.StartingWanderingType);
if (CurrentReactionCoroutine != null) { StopAllCoroutines(); }
if (CurrentReactionCoroutine != null) { StopCoroutine(CurrentReactionCoroutine); }
CurrentReactionCoroutine = StartCoroutine(InvokeReactionListInternal(SentReactionObject, SentByAttractModifier));
}
@@ -354,6 +394,11 @@ namespace EmeraldAI.SoundDetection
else if (SentReactionObject.ReactionList[i].ReactionType == ReactionTypes.LookAtLoudestTarget)
{
LookAtLoudestTarget();
yield return new WaitForSeconds(SentReactionObject.ReactionList[i].IntValue1);
}
else if (SentReactionObject.ReactionList[i].ReactionType == ReactionTypes.SetLoudestTargetAsCombatTarget)
{
SetLoudestTargetAsCombatTarget();
}
else if (SentReactionObject.ReactionList[i].ReactionType == ReactionTypes.ReturnToStartingPosition)
{
@@ -486,7 +531,16 @@ namespace EmeraldAI.SoundDetection
if (CurrentTargetData.Count == 0)
return;
EmeraldComponent.LookAtTarget = GetLoudestTarget(); //Assign the loudest detected target as the Look At Target.
if (RotateTowardsCoroutine != null) StopCoroutine(RotateTowardsCoroutine);
RotateTowardsCoroutine = StartCoroutine(RotateTowardsPosition(GetLoudestTarget().position)); //Have the AI rotate towards the loudest position
}
/// <summary>
/// Sets the loudest target as the AI's current target.
/// </summary>
public void SetLoudestTargetAsCombatTarget()
{
EmeraldAPI.Combat.SetCombatTarget(EmeraldComponent, GetLoudestTarget());
}
/// <summary>
@@ -659,6 +713,27 @@ namespace EmeraldAI.SoundDetection
EmeraldComponent.MovementComponent.ChangeWanderType((EmeraldMovement.WanderTypes)EmeraldMovement.StartingWanderingType);
}
IEnumerator RotateTowardsPosition(Vector3 TargetPosition)
{
if (EmeraldComponent.MovementComponent.RotateTowardsTarget) yield break; //Don't allow the AI to rotate towards the TargetPosition if it's already doing so
EmeraldComponent.MovementComponent.RotateTowardsTarget = true; //Stops certain functionality while in this state
EmeraldComponent.MovementComponent.LockTurning = false; //This is used for preventing an AI from getting stuck between two turn animations
EmeraldComponent.m_NavMeshAgent.isStopped = true; //Stop the AI's NavMesh
yield return new WaitForSeconds(0.1f); //Add a delay so the changes above aren't missed
while (!EmeraldComponent.MovementComponent.LockTurning)
{
Vector3 Direction = new Vector3(TargetPosition.x, 0, TargetPosition.z) - new Vector3(EmeraldComponent.transform.position.x, 0, EmeraldComponent.transform.position.z);
EmeraldComponent.MovementComponent.UpdateRotations(Direction);
EmeraldComponent.AnimationComponent.CalculateTurnAnimations(true);
yield return null;
}
EmeraldComponent.MovementComponent.RotateTowardsTarget = false;
EmeraldComponent.m_NavMeshAgent.isStopped = false;
}
/// <summary>
/// Sets the AI's flee target as the loudest detected target. (Cautious Coward AI Only)
/// </summary>