/// <summary>
        /// Creates a Circle to represent the attack radius of the AI. If the Position Component of the
        /// AI's target is within this Circle, then the AI is in range.
        /// </summary>
        /// <param name="entID">The Entity to check range for.</param>
        /// <param name="AI">AI component of the Entity to check range for.</param>
        /// <param name="pos">Position component of the Entity to check range for.</param>
        protected void CheckRange(ulong entID, CAI AI, CPosition pos)
        {
            Circle    attackRadius = SwinGame.CreateCircle(pos.Centre.X, pos.Centre.Y, AI.Range + (pos.Width / 2));
            CPosition targetPos    = World.GetComponent <CPosition>(AI.TargetID);

            AI.IsInRange = SwinGame.CircleRectCollision(attackRadius, targetPos.Rect);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Evaluates the Player AI's current position against the positions of each Enemy Entity.
        /// The Enemy which is closest to the Player AI becomes the Player AI's target.
        /// </summary>
        /// <param name="playerAI">The Player AI Entity's AI Component.</param>
        /// <param name="playerPos">The Player AI Entity's Position Component.</param>
        private void GetClosestTarget(CAI playerAI, CPosition playerPos)
        {
            /// <summary>
            /// How far away the Enemy Entity is on the x-axis.
            /// </summary>
            float xOffset;

            /// <summary>
            /// How far away the Enemy Entity is on the y-axis.
            /// </summary>
            float yOffset;

            /// <summary>
            /// The direct diagonal distance from the Enemy Entity.
            /// </summary>
            float distance;

            /// <summary>
            /// The Enemy Entity closest to the Player AI. This will become the AI's target.
            /// </summary>
            ulong closestTarget;

            /// <summary>
            /// Represents the Entities to be considered as targets and their distance from the Player AI.
            /// </summary>
            Dictionary <ulong, float> _targetDistances = new Dictionary <ulong, float>();

            foreach (KeyValuePair <ulong, Point2D> enemy in _enemyPositions)
            {
                xOffset  = enemy.Value.X - playerPos.X;
                yOffset  = enemy.Value.Y - playerPos.Y;
                distance = (float)Math.Sqrt((xOffset * xOffset) + (yOffset * yOffset));

                //Only consider Entities which are in range for the AI to attack.
                if (distance <= playerAI.Range)
                {
                    _targetDistances.Add(enemy.Key, distance);
                }
            }

            //If there are targets to consider.
            if (_targetDistances.Count > 0)
            {
                /// <summary>
                /// Returns the corresponding key for the smallest value in the dictionary.
                /// </summary>
                closestTarget = _targetDistances.Aggregate((l, r) => l.Value < r.Value ? l : r).Key;

                playerAI.TargetID  = closestTarget;
                playerAI.HasTarget = true;
            }
        }
        /// <summary>
        /// Checks the Game Time against the last time the AI attacked. If the time difference is greater
        /// than the attack cooldown of the AI, then the AI is ready to attack and their Attack animation begins.
        /// </summary>
        /// <param name="entID">Ent identifier.</param>
        protected void CheckCooldown(ulong entID)
        {
            CAI AI = World.GetComponent <CAI>(entID);

            AI.AttackIsReady = World.GameTime - AI.LastAttackTime >= AI.Cooldown;

            if (AI.AttackIsReady)
            {
                /// <summary>
                /// Begin the Attack animation for the AI
                /// </summary>
                CAnimation anim = World.GetComponent <CAnimation>(entID);
                SwinGame.AssignAnimation(anim.Anim, "Attack", anim.AnimScript);
            }
        }
        /// <summary>
        /// Performs an Attack for the specified Entity. The Entity's
        /// attack Type is evaluated and the appropriate attack is performed.
        /// </summary>
        /// <param name="entID">The Attacking Entity.</param>
        /// <typeparam name="T">The Team the Entity belongs to.</typeparam>
        protected void Attack <T>(ulong entID) where T : CTeam
        {
            CAI       AI = World.GetComponent <CAI>(entID);
            CDamage   damage;
            CPosition pos;
            CPosition targetPos;

            /// <summary>
            /// The AI has just attacked, so its cooldown is started.
            /// </summary>
            AI.LastAttackTime = World.GameTime;
            AI.AttackIsReady  = false;

            /// <summary>
            /// If the Attack Type is Melee, register an attack with the Damage System.
            /// If the Attack Type is Gun, create an Arrow Entity to travel towards the Target.
            /// </summary>
            switch (AI.AttackType)
            {
            case AttackType.Melee:
            {
                /// <summary>
                /// The System where Attacks are registered.
                /// </summary>
                DamageSystem damageSystem = World.GetSystem <DamageSystem>();

                damage = World.GetComponent <CDamage>(entID);
                damageSystem.RegisterAttack(AI.TargetID, damage.Damage);
                break;
            }

            case AttackType.Bow:
            {
                pos = World.GetComponent <CPosition>(entID);
                CBow bow = World.GetComponent <CBow>(entID);

                targetPos = World.GetComponent <CPosition>(AI.TargetID);

                EntityFactory.CreateArrow <T>(pos.Centre.X, pos.Centre.Y, bow, targetPos);
                break;
            }
            }
        }