/// <summary> /// Processes all Attacks against each Entity. After each attack, the Entity's health is checked. /// If the Entity is out of health, it is removed from the World. /// </summary> public override void Process() { CHealth health; /// <summary> /// For each Entity in the System. /// </summary> for (int i = Entities.Count - 1; i >= 0; i--) { health = World.GetComponent <CHealth>(Entities[i]); /// <summary> /// For each attack registered against the Entity. /// </summary> foreach (int damage in _attacks[Entities[i]]) { health.Damage += damage; if (health.OutOfHealth) { World.RemoveEntity(Entities[i]); break; //Stop when the Entity is out of health to prevent overkill. } } } /// <summary> /// Remove all Attacks ready for the next frame. /// </summary> for (int i = 0; i < Entities.Count; i++) { _attacks[Entities[i]].Clear(); } }
/// <summary> /// Loops through each animation, updating and drawing them. /// If an animation has ended, the Animation Component is removed from the Entity. /// If the Entity has no other Components, it is removed from the World. /// </summary> public override void Process() { CAnimation anim; CPosition pos; /// <summary> /// This loop represents each Entity with an Animation Component. /// Backwards loop to allow Entities to be removed from the World while looping. /// </summary> for (int i = Entities.Count - 1; i >= 0; i--) { anim = World.GetComponent <CAnimation>(Entities[i]); pos = World.GetComponent <CPosition>(Entities[i]); if (SwinGame.AnimationEnded(anim.Anim)) { if (World.GetAllComponentsOfEntity(Entities[i]).Count == 1) { World.RemoveEntity(Entities[i]); } } else { SwinGame.DrawAnimation(anim.Anim, anim.Img, pos.X, pos.Y); SwinGame.UpdateAnimation(anim.Anim); } } }
/// <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> /// Registers a collision between two passed in Entities by adding a /// reference to the other Entity in its Collision Component. If the Entity /// does not have a Collision Component, one is added. /// </summary> /// <param name="entOne">The first Entity in the collision.</param> /// <param name="entTwo">The second Entity in the collision..</param> private void RegisterCollision(ulong entOne, ulong entTwo) { CCollision entOneCollision; CCollision entTwoCollision; //Handle collision for the first Entity if (!World.EntityHasComponent(entOne, typeof(CCollision))) { World.AddComponent(entOne, new CCollision(entTwo)); } else { entOneCollision = World.GetComponent <CCollision>(entOne); entOneCollision.AddCollision(entTwo); } //Handle collision for the second Entity if (!World.EntityHasComponent(entTwo, typeof(CCollision))) { World.AddComponent(entTwo, new CCollision(entOne)); } else { entTwoCollision = World.GetComponent <CCollision>(entTwo); entTwoCollision.AddCollision(entOne); } }
/// <summary> /// Loops through each Poisoned Entity and applies poison damage. If the poison has expired, then /// the Poison Component is removed from the Entity. /// </summary> public override void Process() { /// <summary> /// The System where Attacks are registered. /// </summary> DamageSystem damageSystem = World.GetSystem <DamageSystem>(); if (ReadyToApplyPoison(_lastTick, _tickInterval)) { _lastTick = World.GameTime; CPoison poison; for (int i = 0; i < Entities.Count; i++) { poison = World.GetComponent <CPoison>(Entities[i]); if (!Utils.DurationReached(poison.TimeApplied, poison.Duration)) { damageSystem.RegisterAttack(Entities[i], poison.Strength); } else { World.RemoveComponent <CPoison>(Entities[i]); } } } }
/// <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> /// Evaluates the state of each Explosion Man. Two key events occur with Explosion Men: /// -When the Spawn Animation finishes, the explosion is created. /// -When the Explosion Animation finishes, the Entity is removed. /// This System checks the state and animation of each Explosion Man. /// </summary> public override void Process() { CExplosionMan explosion; CAnimation anim; CPosition pos; for (int i = Entities.Count - 1; i >= 0; i--) { anim = World.GetComponent <CAnimation>(Entities[i]); /// <summary> /// If one of the two key events are happening. /// </summary> if (SwinGame.AnimationEnded(anim.Anim)) { explosion = World.GetComponent <CExplosionMan>(Entities[i]); /// <summary> /// If not ready to explode, the Spawn animation has just finished. /// Therefore, create the explosion. /// </summary> if (!explosion.ReadyToExplode) { explosion.ReadyToExplode = true; pos = World.GetComponent <CPosition>(Entities[i]); /// <summary> /// Update size details as the Entity is now an Explosion. /// </summary> pos.Width = EntityFactory.EXPLOSION_SIZE; pos.Height = EntityFactory.EXPLOSION_SIZE; /// <summary> /// Adjust position details so explosion is in centre of the cell. /// </summary> CollisionCheckSystem collisions = World.GetSystem <CollisionCheckSystem>(); Point2D cellPos = collisions.CentreOfCell(explosion.TargetCell); pos.X = cellPos.X - (pos.Width / 2); pos.Y = cellPos.Y - (pos.Height / 2); /// <summary> /// Create explosion animation. /// </summary> anim.Img = SwinGame.BitmapNamed("Explosion"); SwinGame.AssignAnimation(anim.Anim, "Explode", anim.AnimScript); /// <summary> /// Add new components to the Entity. /// </summary> World.AddComponent(Entities[i], new CDamagesOnImpact(false)); World.AddComponent(Entities[i], new CDamage(EntityFactory.EXPLOSION_DAMAGE)); World.AddComponent(Entities[i], new CCollidable()); } else //If ready to explode, the Explode animation has just finished. Therefore, remove the Entity. { World.RemoveEntity(Entities[i]); } } } }
/// <summary> /// Checks collisions. If a collision is detected, a Collision Component is added to both /// of the colliding Entities. If these Entities already have a Collision Component, a new /// EntityID is added to the list of collisions inside the Collision Component. /// </summary> public override void Process() { CPosition playerPos; CPosition enemyPos; /// <summary> /// Empty the Spatial Hash cell details from last frame /// and populate them with the new positions. /// </summary> ClearCells(); PopulateCells(); /// <summary> /// For each Spatial Hash cell, check collisions against Entities on the /// other team in the same Spatial Hash cell. /// </summary> for (int i = 0; i < _numCells; i++) { foreach (ulong playerEnt in _playerCells[i]) { playerPos = World.GetComponent <CPosition>(playerEnt); foreach (ulong enemyEnt in _enemyCells[i]) { enemyPos = World.GetComponent <CPosition>(enemyEnt); if (AreColliding(playerPos, enemyPos)) { RegisterCollision(playerEnt, enemyEnt); } } } } }
/// <summary> /// Evaluates the GotStatusEffect Components of each Entity to determine which type of status effect it has received. /// The corresponding Status Animation is then created and the GotStatusEffect Component is removed. /// </summary> public override void Process() { CGotStatusEffect statusEffects; CStatusAnimations statusAnims; CPosition pos; for (int i = 0; i < Entities.Count; i++) { statusEffects = World.GetComponent <CGotStatusEffect>(Entities[i]); statusAnims = World.GetComponent <CStatusAnimations>(Entities[i]); pos = World.GetComponent <CPosition>(Entities[i]); if (statusEffects.Contains(typeof(CFrozen))) { HandleFreezeEffect(statusAnims, pos); } if (statusEffects.Contains(typeof(CPoison))) { HandlePoisonEffect(statusAnims, pos); } } /// <summary> /// Remove GotStatusEffect Components from each Entity. /// Backwards looping is used to avoid errors caused when modifying a collection while looping over it. /// </summary> for (int i = Entities.Count - 1; i >= 0; i--) { World.RemoveComponent <CGotStatusEffect>(Entities[i]); } }
/// <summary> /// Process this instance. /// </summary> public override void Process() { /// <summary> /// Represents how many pixels wide the Health Bar should be for each point of HP the Entity has. /// </summary> int barWidthPerHP; CHealth health; CPosition pos; for (int i = 0; i < Entities.Count; i++) { health = World.GetComponent <CHealth>(Entities[i]); pos = World.GetComponent <CPosition>(Entities[i]); barWidthPerHP = pos.Width / health.Health; /// <summary> /// Renders the Green Health Bar. /// </summary> SwinGame.FillRectangle(Color.DarkGreen, pos.X, pos.Y - 4, pos.Width, 3); /// <summary> /// Renders the Red Damage Bar if the Entity has been damaged. /// </summary> if (health.Damage > 0) { SwinGame.FillRectangle(Color.Red, pos.X, pos.Y - 4, (barWidthPerHP * health.Damage), 3); //Draw damage bar } } }
/// <summary> /// Purchases an Explosion Man for the Player if they have enough gold. Lowers the Player's gold /// and spawns an Explosion Man at the centre of the most populated Hash cell on the field. /// </summary> public void BuyExplosionMan() { CPlayer player = World.GetComponent <CPlayer>(PLAYER_ENTITY_ID); if (player.Gold >= EXPLOSION_MAN_COST) { EntityFactory.CreateExplosionMan(); player.Gold -= EXPLOSION_MAN_COST; } }
/// <summary> /// Attempts to create a Poison Zone at the passed in point. /// This will only occur if the Ability is off cooldown. /// </summary> /// <param name="pt">Point.</param> public void CastPoisonZone(Point2D pt) { CPlayer player = World.GetComponent <CPlayer>(PLAYER_ENTITY_ID); if (AbilityIsReady(player.TimeOfLastPoisonZone, POISON_ZONE_COOLDOWN)) { EntityFactory.CreatePoisonZone(pt.X, pt.Y); player.TimeOfLastPoisonZone = World.GameTime; } }
/// <summary> /// Renders everything related to the Player, including UI elements. /// </summary> public override void Process() { CRenderable renderable = World.GetComponent <CRenderable>(PlayerSystem.PLAYER_ENTITY_ID); CHealth health = World.GetComponent <CHealth>(PlayerSystem.PLAYER_ENTITY_ID); CPlayer player = World.GetComponent <CPlayer>(PlayerSystem.PLAYER_ENTITY_ID); RenderCooldowns(player); RenderShop(player); RenderHealthBar(health); }
/// <summary> /// Checks if the Entity is within the System. If it is, its loot component is extracted /// and its contents sent to the fetched Player Gold System. /// </summary> /// <param name="entID">The Entity to remove.</param> public override void Remove(ulong entID) { if (HasEntity(entID)) { CLoot lootToGive = World.GetComponent <CLoot>(entID); PlayerSystem playerSystem = World.GetSystem <PlayerSystem>(); playerSystem.GiveLoot(lootToGive); } base.Remove(entID); }
public override void Process() { CCollision collision; CFrozen freezeZoneFrozen; CFrozen collidedFrozen; List <int> deadFreezeEffects = new List <int>(); /// <summary> /// This loop represents each Freeze Zone. /// Backwards loop to allow Entities to be removed while looping. /// </summary> for (int i = Entities.Count - 1; i >= 0; i--) { freezeZoneFrozen = World.GetComponent <CFrozen>(Entities[i]); collision = World.GetComponent <CCollision>(Entities[i]); /// <summary> /// This loop represents each Entity colliding with the Freeze Zone. /// </summary> for (int j = 0; j < collision.Count; j++) { //If not already Frozen, add a Frozen Component. if (!World.EntityHasComponent(collision[j], typeof(CFrozen))) { //Don't freeze projectiles if (!World.EntityHasComponent(collision[j], typeof(CProjectile))) { World.AddComponent(collision[j], new CFrozen(freezeZoneFrozen.Duration, World.GameTime)); } if (!World.EntityHasComponent(collision[j], typeof(CGotStatusEffect))) { World.AddComponent(collision[j], new CGotStatusEffect(typeof(CFrozen))); } else { CGotStatusEffect statusEffects = World.GetComponent <CGotStatusEffect>(collision[j]); statusEffects.AddEffect(typeof(CFrozen)); } } else //If already Frozen, refresh the duration. { collidedFrozen = World.GetComponent <CFrozen>(collision[i]); collidedFrozen.TimeApplied = World.GameTime; } } /// <summary> /// Freeze Zone only lasts for one frame to apply Frozen Components. /// Each Freeze Zone is removed from the World once its collisions are processed. /// </summary> World.RemoveEntity(Entities[i]); } }
/// <summary> /// Populates the Enemy Positions dictionary with the current positions of each Enemy Entity. /// </summary> private void GetEnemyPositions() { _enemyPositions.Clear(); CPosition enemyPos; foreach (ulong enemyID in _enemies.Entities) { enemyPos = World.GetComponent <CPosition>(enemyID); _enemyPositions.Add(enemyID, SwinGame.PointAt(enemyPos.Centre.X, enemyPos.Centre.Y)); } }
/// <summary> /// Purchases an Archer for the Player if they have enough gold. Lowers the Player's gold, increments the /// Archer count and spawns an Archer at a random y coordinate inside the Castle. /// </summary> public void BuyArcher() { CPlayer player = World.GetComponent <CPlayer>(PLAYER_ENTITY_ID); if (player.Gold >= ARCHER_COST) { EntityFactory.CreatePlayerArcher(_spawnAtX, _spawnAtY.Next(20, 550)); player.Gold -= ARCHER_COST; ARCHER_COUNT++; } }
/// <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> /// Renders the Bitmap in each Entity's Renderable Component at the x and y coordinates /// in the Entity's Position Component. /// </summary> public override void Process() { CRenderable render; CPosition pos; for (int i = 0; i < Entities.Count; i++) { render = World.GetComponent <CRenderable>(Entities[i]); pos = World.GetComponent <CPosition>(Entities[i]); SwinGame.DrawBitmap(render.Img, pos.X, pos.Y); } }
/// <summary> /// Updates the Position Components of each Entity according to the velocities in their Velocity Components. /// </summary> public override void Process() { CPosition pos; CVelocity vel; for (int i = 0; i < Entities.Count; i++) { pos = World.GetComponent <CPosition>(Entities[i]); vel = World.GetComponent <CVelocity>(Entities[i]); pos.X += vel.DX; pos.Y += vel.DY; } }
/// <summary> /// Fetches the Frozen Component of each Entity. If the effect has expired, /// the Frozen Component is removed from the Entity. /// </summary> public override void Process() { CFrozen frozen; for (int i = 0; i < Entities.Count; i++) { frozen = World.GetComponent <CFrozen>(Entities[i]); if (FreezeExpired(frozen.TimeApplied, frozen.Duration)) { World.RemoveComponent <CFrozen>(Entities[i]); } } }
/// <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> /// Determines if each Entity has left the bounds of the screen. If it has, /// then it is removed from the World. /// </summary> public override void Process() { CPosition pos; /// <summary> /// Backwards loop to allow Entities to be removed from the World while looping. /// </summary> for (int i = Entities.Count - 1; i >= 0; i--) { pos = World.GetComponent <CPosition>(Entities[i]); if (!ProjectileOnScreen(pos)) { World.RemoveEntity(Entities[i]); } } }
public override void Process() { CAI AI; CPosition pos; CAnimation anim; /// <summary> /// For each Enemy AI Entity. /// </summary> for (int i = 0; i < Entities.Count; i++) { AI = World.GetComponent <CAI>(Entities[i]); pos = World.GetComponent <CPosition>(Entities[i]); if (!AI.IsInRange) { CheckRange(Entities[i], AI, pos); /// If the AI is now in range, stop moving and begin attacking. if (AI.IsInRange) { World.RemoveComponent <CVelocity>(Entities[i]); } } else if (!AI.AttackIsReady) { CheckCooldown(Entities[i]); } else { anim = World.GetComponent <CAnimation>(Entities[i]); /// <summary> /// Attack will be carried out when the Attack animation has ended. /// </summary> if (SwinGame.AnimationEnded(anim.Anim)) { Attack <CEnemyTeam>(Entities[i]); ///If the Entity has attacked, stand still during the cooldown period. SwinGame.AssignAnimation(anim.Anim, "Still", anim.AnimScript); } } } }
/// <summary> /// Checks the Lifetime of each Entity. If their Lifetime has passed, /// the Entity is removed from the World. /// </summary> public override void Process() { CLifetime lifetime; /// <summary> /// This loop represents each Entity with a Lifetime. /// Backwards loop to allow Entities to be removed from the World while looping. /// </summary> for (int i = Entities.Count - 1; i >= 0; i--) { lifetime = World.GetComponent <CLifetime>(Entities[i]); if (TimeLimitReached(lifetime.CreatedAt, lifetime.Lifetime)) { World.RemoveEntity(Entities[i]); } } }
/// <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; } } }
/// <summary> /// Checks the collisions of each Entity which deals damage on impact. If it has collided with something containing a Health Component, /// an Attack is registered with the Damage System. /// </summary> public override void Process() { /// <summary> /// The System where Attacks are registered. /// </summary> DamageSystem damageSystem = World.GetSystem <DamageSystem>(); for (int i = Entities.Count - 1; i >= 0; i--) { CDamage damage; CCollision collision; CDamagesOnImpact dmgOnImp; collision = World.GetComponent <CCollision>(Entities[i]); /// <summary> /// Apply damage to the first Entity the Entity has collided with that still exists in /// the World and also has a Health Component. If none are found, the Arrow remains live. /// </summary> for (int j = 0; j < collision.Count; j++) { if (World.HasEntity(collision[j])) { if (World.EntityHasComponent(collision[j], typeof(CHealth))) { damage = World.GetComponent <CDamage>(Entities[i]); damageSystem.RegisterAttack(collision[j], damage.Damage); } } } /// <summary> /// If the Entity is set to die after impact, remove it from the World. /// </summary> dmgOnImp = World.GetComponent <CDamagesOnImpact>(Entities[i]); if (dmgOnImp.DiesAfterImpact) { World.RemoveEntity(Entities[i]); } } }
/// <summary> /// Checks each Entity colliding with each Poison Zone. If the Entity does not have /// a Poison Component, then a Poison Component and a GotStatusEffect Component are added. /// Otherwise, the Entity's Poison Component duration is refreshed. /// </summary> public override void Process() { CPoison poisonEffect; CPoison targetPoisonEffect; CCollision collision; /// <summary> /// This loop represents each Poison Zone. /// </summary> for (int i = 0; i < Entities.Count; i++) { poisonEffect = World.GetComponent <CPoison>(Entities[i]); collision = World.GetComponent <CCollision>(Entities[i]); /// <summary> /// This loop represents each Entity colliding with the Poison Zone. /// </summary> for (int j = 0; j < collision.Count; j++) { if (!World.EntityHasComponent(collision[j], typeof(CPoison))) { World.AddComponent(collision[j], new CPoison(poisonEffect.Strength, poisonEffect.Duration, World.GameTime)); if (!World.EntityHasComponent(collision[j], typeof(CGotStatusEffect))) { World.AddComponent(collision[j], new CGotStatusEffect(typeof(CPoison))); } else { CGotStatusEffect statusEffects = World.GetComponent <CGotStatusEffect>(collision[j]); statusEffects.AddEffect(typeof(CPoison)); } } else //If entity already has a Poison Component, refresh its duration. { targetPoisonEffect = World.GetComponent <CPoison>(collision[j]); targetPoisonEffect.TimeApplied = World.GameTime; } } } }
/// <summary> /// Loops through all Freezing Bullet entities and checks if they've reached their destination. /// If they have, the Bullet is removed and a Freeze Zone is created at the bullet's location. /// </summary> public override void Process() { CFreezingBullet freezingBullet; CPosition pos; /// <summary> /// This loop represents each Freezing Bullet. /// Backwards loop to allow Enities to be removed from the World while looping. /// </summary> for (int i = Entities.Count - 1; i >= 0; i--) { freezingBullet = World.GetComponent <CFreezingBullet>(Entities[i]); pos = World.GetComponent <CPosition>(Entities[i]); if (ReachedTarget(pos, freezingBullet)) { EntityFactory.CreateFreezeZone(pos); World.RemoveEntity(Entities[i]); } } }
/// <summary> /// Updates and Draws each Animation in each Entity's StatusAnimation Component. /// If an Entity no longer has the required Component for the StatusAnimation, it /// is removed from the StatusAnimations Component. /// </summary> public override void Process() { CStatusAnimations statusAnims; CStatusAnimation anim; CPosition pos; /// <summary> /// This loop represents each Entity with a Status Animations Component. /// </summary> for (int i = 0; i < Entities.Count; i++) { statusAnims = World.GetComponent <CStatusAnimations>(Entities[i]); pos = World.GetComponent <CPosition>(Entities[i]); /// <summary> /// This loop represents each Status Animation inside the Status Animations Component. /// Backwards loop to allow Status Animations to be removed while looping. /// </summary> for (int j = statusAnims.Anims.Count - 1; j >= 0; j--) { anim = statusAnims[j]; if (World.EntityHasComponent(Entities[i], anim.LinkedComponent)) { float x = pos.X + anim.XOffset; float y = pos.Y + anim.YOffset; SwinGame.DrawAnimation(anim.Anim, anim.Img, x, y); SwinGame.UpdateAnimation(anim.Anim); } else { statusAnims.Anims.RemoveAt(j); } } } }