/// <summary>
        /// Adds an Ice Spike status animation linked to the Entity's position.
        /// </summary>
        /// <param name="statusAnims">The Entity's list of Status Animations.</param>
        /// <param name="pos">The Entity's position.</param>
        private void HandleFreezeEffect(CStatusAnimations statusAnims, CPosition pos)
        {
            CStatusAnimation newStatusAnim;
            Bitmap           bmp;
            Animation        anim;
            AnimationScript  animScript;
            float            xOffset;
            float            yOffset;

            if (pos.Width <= 21)
            {
                bmp = SwinGame.BitmapNamed("SmallIceSpike");
            }
            else
            {
                bmp = SwinGame.BitmapNamed("BigIceSpike");
            }

            xOffset = (pos.Width / 2) - (bmp.CellWidth / 2);
            yOffset = pos.Height - bmp.CellHeight;

            anim       = SwinGame.CreateAnimation("Freeze", SwinGame.AnimationScriptNamed("IceSpikeAnim"));
            animScript = SwinGame.AnimationScriptNamed("IceSpikeAnim");

            newStatusAnim = new CStatusAnimation(typeof(CFrozen), xOffset, yOffset, bmp, anim, animScript);

            statusAnims.Anims.Add(newStatusAnim);
        }
        /// <summary>
        /// Adds a Poison Cloud status animation linked to the Entity's position.
        /// </summary>
        /// <param name="statusAnims">The Entity's list of Status Animations.</param>
        /// <param name="pos">The Entity's position.</param>
        private void HandlePoisonEffect(CStatusAnimations statusAnims, CPosition pos)
        {
            CStatusAnimation newStatusAnim;
            Bitmap           bmp;
            Animation        anim;
            AnimationScript  animScript;
            float            xOffset;
            float            yOffset;

            if (pos.Width <= 21)
            {
                bmp = SwinGame.BitmapNamed("SmallPoisonCloud");
            }
            else
            {
                bmp = SwinGame.BitmapNamed("BigPoisonCloud");
            }

            xOffset = (pos.Width / 2) - (bmp.CellWidth / 2);
            yOffset = 0;

            anim       = SwinGame.CreateAnimation("Poison", SwinGame.AnimationScriptNamed("PoisonZoneAnim"));
            animScript = SwinGame.AnimationScriptNamed("PoisonZoneAnim");

            newStatusAnim = new CStatusAnimation(typeof(CPoison), xOffset, yOffset, bmp, anim, animScript);

            statusAnims.Anims.Add(newStatusAnim);
        }
        /// <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);
        }
        /// <summary>
        /// Creates an Entity with all Components of a Freeze Zone and adds it to the World.
        /// This Entity represents the Freeze Zone created when a Freezing Bullet reaches its target.
        /// </summary>
        /// <param name="pos">The position the Freeze Zone occupies.</param>
        public static void CreateFreezeZone(CPosition pos)
        {
            //Create Entity and add to world.
            ulong newEntity = _world.NextEntityID;

            /// <summary>
            /// Adjust position for Sprite size so Freeze Zone spawns at centre of bullet.
            /// </summary>
            float atX = pos.X - (FREEZE_ZONE_SIZE / 2);
            float atY = pos.Y - (FREEZE_ZONE_SIZE / 2);

            /// <summary>
            /// Creates a new Entity with just an Animation component to be processed by the Animation Rendering System.
            /// </summary>
            Bitmap          bmp        = SwinGame.BitmapNamed("FreezingBulletSplash");
            Animation       anim       = SwinGame.CreateAnimation("Splash", SwinGame.AnimationScriptNamed("FreezingBulletSplashAnim"));
            AnimationScript animScript = SwinGame.AnimationScriptNamed("FreezingBulletSplashAnim");

            CreateAnimationEntity(atX, atY, anim, bmp, animScript);

            //Create components and pass to world to send to Systems
            List <Component> components = new List <Component>();

            components.Add(new CPlayerTeam());
            components.Add(new CPosition(pos.Centre.X - (FREEZE_ZONE_SIZE / 2), pos.Centre.Y - (FREEZE_ZONE_SIZE / 2), FREEZE_ZONE_SIZE));
            components.Add(new CCollidable());
            components.Add(new CAppliesDebuff());
            components.Add(new CFrozen(FREEZING_BULLET_FREEZE_DURATION, 0));

            _world.AddEntity(newEntity, components);
        }
        /// <summary>
        /// Adds the passed in Entity to each Spatial Hash Player cell it resides in.
        /// </summary>
        /// <param name="entID">The Entity to add to Player cells.</param>
        private void AddEntityToCells(ulong entID, Dictionary <int, List <ulong> > cells)
        {
            CPosition  pos = World.GetComponent <CPosition>(entID);
            List <int> cellsEntityIsIn;

            if (pos.Width > _cellSize || pos.Height > _cellSize)
            {
                cellsEntityIsIn = GetCellsBigEntityIsIn(pos);
            }
            else
            {
                cellsEntityIsIn = GetCellsNormalSizeEntityIsIn(pos);
            }

            foreach (int i in cellsEntityIsIn)
            {
                if (i >= 0 && i < _numCells)
                {
                    if (!cells[i].Contains(entID))
                    {
                        cells[i].Add(entID);
                    }
                }
            }
        }
        /// <summary>
        /// Attemps to create a Freezing Bullet heading towards the passed in point.
        /// This will only occur if the Ability is off cooldown.
        /// </summary>
        /// <param name="pt">The point the Freezing Bullet will head towards.</param>
        public void CastFreezingBullet(Point2D pt)
        {
            CPlayer player = World.GetComponent <CPlayer>(PLAYER_ENTITY_ID);

            if (AbilityIsReady(player.TimeOfLastFreezingBullet, FREEZING_BULLET_COOLDOWN))
            {
                CPosition playerPos = World.GetComponent <CPosition>(PLAYER_ENTITY_ID);
                EntityFactory.CreateFreezingBullet(playerPos.Centre.X, playerPos.Centre.Y, pt.X, pt.Y);
                player.TimeOfLastFreezingBullet = World.GameTime;
            }
        }
        /// <summary>
        /// Checks each corner of the passed in Position Component and adds the corresponding
        /// cell ID to a List of cell IDs the Entity resides in.
        /// </summary>
        /// <returns>A List of cell IDs the Entity resides in.</returns>
        /// <param name="pos">The Position Component of the Entity.</param>
        private List <int> GetCellsNormalSizeEntityIsIn(CPosition pos)
        {
            List <int> result = new List <int>();

            result.Add(CellAt(pos.X, pos.Y));                          //Top Left
            result.Add(CellAt(pos.X + pos.Width, pos.Y));              //Top Right
            result.Add(CellAt(pos.X, pos.Y + pos.Height));             //Bottom Left
            result.Add(CellAt(pos.X + pos.Width, pos.Y + pos.Height)); //Bottom Right

            return(result);
        }
Esempio n. 8
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>
        /// Creates an Entity with all Components of an Arrow and adds it to the World.
        /// This Entity represents the Arrows used by Archers of both teams.
        /// </summary>
        /// <param name="x">The x coordinate where the Entity will be created.</param>
        /// <param name="y">The y coordinate where the Entity will be created.</param>
        /// <param name="bow">The bow determining speed and damage of the Arrow.</param>
        /// <param name="targetPos">The position of the Entity the Arrow is heading towards.</param>
        /// <typeparam name="T">The team the Arrow belongs to</typeparam>
        public static void CreateArrow <T>(float x, float y, CBow bow, CPosition targetPos) where T : CTeam
        {
            //Create Entity and add to world
            ulong newEntity = _world.NextEntityID;

            //Create components and pass to world to send to Systems
            List <Component> components = new List <Component>();

            components.Add(new CPosition(x, y, ARROW_SIZE));
            components.Add(new CDamage(bow.ArrowDamage));
            components.Add(new CCollidable());
            components.Add(new CProjectile());
            components.Add(new CDamagesOnImpact(true));

            //Calculate the centre of the passed in position to be the Arrow's target.
            float targetCentreX = targetPos.X + (targetPos.Width / 2);
            float targetCentreY = targetPos.Y + (targetPos.Height / 2);

            //Calculate appropriate velocities for Arrow to reach target.
            Vector velocity = Utils.GetVectorBetweenPoints(x, y, targetCentreX, targetCentreY, bow.ArrowSpeed);

            components.Add(new CVelocity(velocity.X, velocity.Y, bow.ArrowSpeed));

            if (typeof(T) == typeof(CPlayerTeam))
            {
                components.Add(new CPlayerTeam());
                components.Add(new CRenderable(SwinGame.BitmapNamed("PlayerArrow")));
            }
            else if (typeof(T) == typeof(CEnemyTeam))
            {
                components.Add(new CEnemyTeam());
                components.Add(new CRenderable(SwinGame.BitmapNamed("Arrow")));
            }

            _world.AddEntity(newEntity, components);
        }
        /// <summary>
        /// Checks the Entity in chunks equal to _cellSize and adds the corresponding
        /// cell ID to a list of cell IDs the Entity resides in.
        /// </summary>
        /// <returns>The cells the Entity is in.</returns>
        /// <param name="pos">The position of the Entity.</param>
        private List <int> GetCellsBigEntityIsIn(CPosition pos)
        {
            List <int> result = new List <int>();
            float      x;
            float      y;
            int        numXCells = (int)Math.Ceiling((double)pos.Width / _cellSize);
            int        numYCells = (int)Math.Ceiling((double)pos.Height / _cellSize);

            for (int i = 0; i < numXCells; i++)
            {
                //If not checking final X-Axis cell
                if (i < numXCells - 1)
                {
                    x = pos.X + (i * _cellSize);
                }
                else
                {
                    x = pos.X + pos.Width; //Check right edge
                }
                for (int j = 0; j < numYCells; j++)
                {
                    //If not checking final Y-Axis cell
                    if (j < numYCells - 1)
                    {
                        y = pos.Y + (j * _cellSize);
                    }
                    else
                    {
                        y = pos.Y + pos.Height; //Check bottom edge
                    }
                    result.Add(CellAt(x, y));
                }
            }

            return(result);
        }
 /// <summary>
 /// Specifies whether or not the Freezing Bullet has reached its target.
 /// </summary>
 /// <returns><c>true</c> if the Freezing Bullet has reached its target, <c>false</c> otherwise.</returns>
 /// <param name="bulletPos">The position of the Freezing Bullet.</param>
 /// <param name="bullet">The Freezing Bullet component, contains target coordinates.</param>
 private bool ReachedTarget(CPosition bulletPos, CFreezingBullet bullet)
 {
     return(SwinGame.PointInRect(bullet.TargetX, bullet.TargetY, bulletPos.Rect));
 }
 /// <summary>
 /// Specifies whether or not the projectile is within the boundaries of the screen.
 /// </summary>
 /// <returns><c>true</c>, if the projectile is on the screen, <c>false</c> otherwise.</returns>
 /// <param name="pos">The projectile's position.</param>
 protected bool ProjectileOnScreen(CPosition pos)
 {
     return(SwinGame.RectOnScreen(pos.Rect));
 }
 /// <summary>
 /// Indicates whether or not two Entities are colliding, according to their Position Components.
 /// </summary>
 /// <returns><c>true</c> if the Entities are colliding, <c>false</c> otherwise.</returns>
 /// <param name="p1">The first Entity's Position Component.</param>
 /// <param name="p2">The second Entity's Position Component.</param>
 private bool AreColliding(CPosition p1, CPosition p2)
 {
     return(SwinGame.RectanglesIntersect(p1.Rect, p2.Rect));
 }