private void checkEnemies()
        {
            // If the sight range is negative, do nothing.
            if (SightRange <= 0)
            {
                return;
            }

            // Add the passed time to the time since the last check.
            timeSinceLastSightCheck += Time.fixedDeltaTime;

            if (timeSinceLastSightCheck >= TimeBetweenSightChecks)
            {
                // Finds all creature colliders in the area around this creature.
                int seenCreaturesCount = Physics.OverlapSphereNonAlloc(eyeOrigin.position, SightRange, seenColliders, 1 << LayerMask.NameToLayer("Creatures"));

                // Clear the seen enemies list and fill it with all enemies in the colliders collection.
                seenEnemies.Clear();
                for (int i = 0; i < seenCreaturesCount; i++)
                {
                    if (seenColliders[i] != null && seenColliders[i].TryGetComponent(out Creature creature) && creature.Player != Creature.Player)
                    {
                        seenEnemies.Add(new CreatureTarget()
                        {
                            Target             = creature,
                            TargetRigidbody    = creature.GetComponent <Rigidbody>(),
                            TargetCollider     = seenColliders[i],
                            NormalisedDistance = NeuralNetworkHelper.ExpandRangeToNegative(Vector3.Distance(eyeOrigin.position, seenColliders[i].ClosestPoint(eyeOrigin.position)) / SightRange),
                            NormalisedHealth   = NeuralNetworkHelper.ExpandRangeToNegative(creature.Health / maxHealth)
                        });
                    }
                }

                // Sort the enemies based on the score using the mutated filters.
                seenEnemies.Sort((firstEnemy, secondEnemy) =>
                {
                    // Calculate the scores for both enemies.
                    float firstScore  = (float)Math.Tanh(Bias + firstEnemy.NormalisedHealth * HealthWeight + firstEnemy.NormalisedDistance * DistanceWeight);
                    float secondScore = (float)Math.Tanh(Bias + secondEnemy.NormalisedHealth * HealthWeight + secondEnemy.NormalisedDistance * DistanceWeight);

                    // Return the result of the compare function.
                    return(firstScore.CompareTo(secondScore));
                });

                // Set the max concurrent seen creatures if the number of seen creatures is higher than the old value.
                setLifetimeStat("MaxConcurrentSeenCreatures", (uint)Math.Max(LifetimeStats["MaxConcurrentSeenCreatures"], seenEnemies.Count));

                // If enemies were seen, take the last one (the one with the highest score) and set the current target to it, otherwise set the current target to null.
                CurrentTarget = (seenEnemies.Count > 0) ? seenEnemies[seenEnemies.Count - 1] : (CreatureTarget?)null;

                if (seenCreaturesCount == seenColliders.Length)
                {
                    Array.Resize(ref seenColliders, seenColliders.Length + 10);
                }

                // Reset the timer.
                timeSinceLastSightCheck = 0;
            }
        }
Example #2
0
        private void handleAttackLogic()
        {
            // Add the elapsed time to the attack timer.
            timeSinceLastAttack += Time.fixedDeltaTime;

            // If the creature has a target, attempt to move towards it.
            if (targetingBehaviour.HasCurrentTarget)
            {
                CreatureTarget creatureTarget = targetingBehaviour.CurrentTarget.Value;

                // Stop moving.
                movementBehaviour.StopMoving();

                // Face the target.
                transform.LookAt(creatureTarget.Transform);

                // If it has been long enough since the last attack, attack again.
                if (timeSinceLastAttack >= AttackInterval && creatureTarget.Target.IsAlive)
                {
                    // Calculate the power of the throw.
                    float power = Mathf.Clamp01(PowerBias + creatureTarget.NormalisedHealth * PowerHealthWeight + creatureTarget.NormalisedDistance * PowerDistanceWeight);

                    // Calculate the pitch of the throw.
                    float pitch = Mathf.Clamp(PitchBias + creatureTarget.NormalisedDistance * PitchDistanceWeight + NeuralNetworkHelper.ExpandRangeToNegative(creatureTarget.TargetRigidbody.velocity.magnitude / 1000) * PitchSpeedWeight
                                              + power * PitchPowerWeight, -1, 1);

                    // Calculate the yaw of the throw.
                    float yaw = Mathf.Clamp(YawBias + creatureTarget.NormalisedDistance * YawDistanceWeight + power * YawPowerWeight
                                            + NeuralNetworkHelper.ExpandRangeToNegative(creatureTarget.TargetRigidbody.velocity.magnitude / 1000) * YawSpeedWeight, -1, 1);

                    // Calcualte the normalised direction to the target, then the angles (in degrees) from that.
                    Vector3 direction = Quaternion.LookRotation((creatureTarget.Transform.position - transform.position).normalized).eulerAngles;
                    direction.y += yaw * Mathf.Clamp(YawDeviation, 0, 180);
                    direction.x += pitch * Mathf.Clamp(PitchDeviation, 0, 180);

                    // Create a new spear.
                    GameObject spearObject = Instantiate(projectilePrefab.gameObject, heldWeapon.position, Quaternion.Euler(direction), Creature.ProjectileContainer);

                    //spearObject.transform.position = heldWeapon.position;
                    spearObject.transform.localScale = Vector3.Scale(heldWeapon.localScale, transform.localScale);

                    // Get the projectile component from the created spear.
                    Projectile spearProjectile = spearObject.GetComponent <Projectile>();

                    spearProjectile.InitialiseProjectile(onProjectileHitEnemy, Creature, creatureTarget.Target, creatureTarget.Transform.position, spearObject.transform.position);

                    // Add the force to the spear.
                    spearProjectile.Rigidbody.AddForce(spearObject.transform.forward * (power + 1) * MaxPower, ForceMode.Impulse);

                    // Increment the thrown shots counter.
                    thrownShots++;

                    // Reset the attack timer.
                    timeSinceLastAttack = 0;
                }
            }
            // Otherwise, just move towards the goal.
            else
            {
                movementBehaviour.SetTarget(Creature.GoalObject);
                movementBehaviour.StoppingDistance = 0;
            }
        }