internal static FormState Load(XElement a_node) { if (a_node.Name != XML_FORMSTATE) { throw new Exception(); } return(new FormState() { m_window_state = (FormWindowState)Enum.Parse( typeof(FormWindowState), a_node.Element(XML_WINDOWSTATE).Value), m_bounds = RectangleExtensions.FromXml(a_node.Element(XML_BOUNDS)) }); }
/// <summary> /// Move this object on it's X-coordinate. /// </summary> /// <param name="value">Value for this object to move.</param> public void MoveX(int value) { //Padded boundary for safe collision checks on smaller movements. var territoryBoundary = new Rectangle((int)X, (int)Y, Boundary.Width + 2, Boundary.Height + 2); //Determine if this movement can or cannot be made. bool canMoveRight = true; bool canMoveLeft = true; //Checks if this object will be prevented by any solid game object neighbors. foreach (var no in NeighboringObjects.ToList()) { if (territoryBoundary.Intersects(no.Boundary)) { var depth = RectangleExtensions.GetIntersectionDepth(territoryBoundary, no.Boundary); if (depth.Y < -8 || depth.Y > 8) { if (depth.X < 0 && depth.X > -8) { canMoveRight = false; OnRightCollided(no, new CollisionEventArgs() { Depth = depth }); } if (depth.X > 0 && depth.X < 8) { canMoveLeft = false; OnLeftCollided(no, new CollisionEventArgs() { Depth = depth }); } } } } if (value > 0 && canMoveRight) { X += value; } if (value < 0 && canMoveLeft) { X += value; } VelocityX = value; }
/// <param name="celAlphaMasks">Fill with masks created from Cels</param> /// <param name="allMasks">Fill with all created masks</param> public void RegenerateAlphaMask() { masks.TryRemoveBaseFallBack(); // <- it is about to be regenerated // If this frame has a single sprite-containing Cel, generate it directly if (firstLayer != null && firstLayer.next == null) { Mask mask = new Mask { data = firstLayer.spriteRef.ResolveRequire().GetAlphaMask(), isGeneratedAlphaMask = true, }; masks.Add(new TagSet(), mask); } else // ... Otherwise, try to create a mask merged from the frame's layers { List <MaskData> layerMasks = new List <MaskData>(); foreach (var cel in layers) { MaskData maskData = cel.spriteRef.ResolveRequire().GetAlphaMask(); if (maskData.Width != 0 && maskData.Height != 0) { layerMasks.Add(maskData); } } Rectangle maxBounds = Rectangle.Empty; foreach (var maskData in layerMasks) { maxBounds = RectangleExtensions.UnionIgnoreEmpty(maxBounds, maskData.Bounds); } Mask mask = new Mask() { isGeneratedAlphaMask = true }; mask.data = new MaskData(maxBounds); foreach (var layerMask in layerMasks) { Debug.Assert(!Asserts.enabled || mask.data.Bounds.Contains(layerMask.Bounds)); mask.data.SetBitwiseOrFrom(layerMask); } masks.Add(new TagSet(), mask); } }
public WorldArea(XmlElement area, XmlNamespaceManager xnm) { this.Area = RectangleExtensions.GetRectangleFromDefinition(area); string worldStart = area.GetAttribute("WorldStart"); this.IsInitialArea = !string.IsNullOrWhiteSpace(worldStart) && bool.Parse(worldStart); var startPos = (XmlElement)area.SelectSingleNode("ns:PlayerStartState", xnm); if (startPos != null) { var pss = PlayerStartState.FromXml(startPos); if (!this.Area.ContainsTile(pss.Position)) { throw new InvalidOperationException("Invalid player start position - co-ordinate is not within the area."); } this.PlayerStartState = pss; } var tileDefinitions = area.SelectNodes("ns:TileDefinitions/ns:*", xnm); if (tileDefinitions != null) { var td = TileDefinitionCollection.FromXml(tileDefinitions); td.Area = this.Area; this.TileDefinitionCollection = td; } var fruitPopulation = area.SelectNodes("ns:FruitDefinitions/ns:FruitDef", xnm); if (fruitPopulation != null) { var fd = RandomFruitDistribution.FromXml(fruitPopulation); fd.Area = this.Area; this.FruitDefinitions = fd; } var randomMonsterDistribution = (XmlElement)area.SelectSingleNode("ns:RandomMonsterDistribution", xnm); if (randomMonsterDistribution != null) { var md = RandomMonsterDistribution.FromXml(randomMonsterDistribution, xnm); md.Area = this.Area; this.RandomMonsterDistribution = md; } }
/// <summary>EDITOR ONLY!</summary> public Rectangle GetSoftRenderBounds() { Rectangle output = Rectangle.Empty; foreach (var cel in layers) { if (cel.shadowReceiver != null) { continue; // Skip shadow receivers } Sprite sprite = cel.spriteRef.ResolveRequire(); Rectangle bounds = new Rectangle(-sprite.origin.X, -sprite.origin.Y, sprite.sourceRectangle.Width, sprite.sourceRectangle.Height); output = RectangleExtensions.UnionIgnoreEmpty(output, bounds); } return(output); }
/// <summary> /// Updates neighbor collection and checks for colision. /// </summary> private void UpdateNeighbors() { foreach (var gameObject in NeighboringObjects.ToList()) { if (ValidateAsNeighbor(gameObject)) { var depth = RectangleExtensions.GetIntersectionDepth(Boundary, gameObject.Boundary); var collisionArgs = new CollisionEventArgs() { Depth = depth }; OnCollisionDetected(gameObject, collisionArgs); CheckCollision(gameObject, collisionArgs); } } }
public void Draw(GameTime time, Matrix parent, Rectangle scissor) { Matrix transform = this.Transform * parent; Rectangle newScissor = scissor; if (this.EnableScissor) { newScissor = scissor.Intersect(RectangleExtensions.Create(Vector2.Transform(Vector2.Zero, transform), Vector2.Transform(this.Size, transform))); } if (newScissor.Width > 0 && newScissor.Height > 0) { if (this.EnableScissor) { this.renderer.Batch.End(); this.renderer.Batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, this.renderer.RasterizerState, null, Matrix.Identity); this.main.GraphicsDevice.ScissorRectangle = newScissor; } this.draw(time, parent, transform); for (int i = 0; i < this.Children.Count; i++) { UIComponent child = this.Children[i]; if (child.Visible) { if (this.main.GraphicsDevice.ScissorRectangle != newScissor || child.requiresNewBatch) { this.renderer.Batch.End(); this.renderer.Batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, this.renderer.RasterizerState, null, Matrix.Identity); this.main.GraphicsDevice.ScissorRectangle = newScissor; } child.Draw(time, transform, newScissor); } } } if (this.EnableScissor) { // Restore original scissor this.renderer.Batch.End(); this.renderer.Batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, this.renderer.RasterizerState, null, Matrix.Identity); this.main.GraphicsDevice.ScissorRectangle = scissor; } }
public Rectangle PutNextRectangle(Size rectangleSize) { if (rectangleSize.Width <= 0 || rectangleSize.Height <= 0) { throw new ArgumentException("Width and height of the rectangle must be positive"); } Rectangle rectangle; do { var possiblePoint = _spiral.GetNextPoint(); rectangle = RectangleExtensions.CreateRectangleFromMiddlePointAndSize(possiblePoint, rectangleSize); } while (rectangle.IntersectsWith(_rectangles)); var result = MoveToCanvasCenter(rectangle); _rectangles.Add(result); return(result); }
/// <summary> /// Used for the movable platforms to push player /// </summary> /// <param name="bounds"></param> /// <param name="collision"></param> /// <param name="tileBounds"></param> /// <returns></returns> private Rectangle HandleCollision(Rectangle bounds, TileCollision collision, Rectangle tileBounds, Character character) { Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds); if (depth != Vector2.Zero) { float absDepthX = Math.Abs(depth.X); float absDepthY = Math.Abs(depth.Y); // Resolve the collision along the shallow axis. if (absDepthY < absDepthX || collision == TileCollision.Platform) { // If we crossed the top of a tile, we are on the ground. if (character.previousBottom <= tileBounds.Top) { character.IsOnGround = true; } // Ignore platforms, unless we are on the ground. if (collision == TileCollision.Impassable || character.IsOnGround) { // Resolve the collision along the Y axis. character.Position = new Vector2(character.Position.X, character.Position.Y + depth.Y); // Perform further collisions with the new bounds. bounds = character.BoundingRectangle; } } else if (collision == TileCollision.Impassable) // Ignore platforms. { // Resolve the collision along the X axis. character.Position = new Vector2(character.Position.X + depth.X, character.Position.Y); // Perform further collisions with the new bounds. bounds = character.BoundingRectangle; } } return(bounds); }
/// <summary>EDITOR ONLY!</summary> public Rectangle GetSoftRenderBounds(bool accountForGameplayMotion) { Rectangle output = Rectangle.Empty; Position accumulatedMotion = Position.Zero; foreach (var frame in Frames) { Rectangle bounds = frame.GetSoftRenderBounds(); if (accountForGameplayMotion) { accumulatedMotion += frame.positionDelta; Point offset = accumulatedMotion.ToWorldZero().FlipY(); // Flip because we're outputting in texture space bounds.X += offset.X; bounds.Y += offset.Y; } output = RectangleExtensions.UnionIgnoreEmpty(output, bounds); } return(output); }
public virtual void HandleCollisions(CVGameTime gameTime) { if (this.WorldPosition.Y > Game.iScreenModelWidth && IsDying == false) { Die(gameTime); } Rectangle actorbounds = this.BoundingBox(); bool wasonground = this.IsOnGround; // get nearest tile below player. this.IsOnGround = false; int leftTile = (int)Math.Floor((float)actorbounds.Left / CurrentStage.TileWidth); int rightTile = (int)Math.Ceiling(((float)actorbounds.Right / CurrentStage.TileWidth)) - 1; int topTile = (int)Math.Floor((float)actorbounds.Top / CurrentStage.TileHeight); int bottomTile = (int)Math.Ceiling(((float)actorbounds.Bottom / CurrentStage.TileHeight)) - 1; // For each potentially colliding platform tile, for (int y = topTile; y <= bottomTile; ++y) { for (int x = leftTile; x <= rightTile; ++x) { StageTile stageTile = CurrentStage.getStageTileByGridPosition(x, y); if (stageTile != null) { if (stageTile.IsImpassable()) { Rectangle tilebounds = CurrentStage.getTileBoundsByGridPosition(x, y); Vector2 depth = RectangleExtensions.GetIntersectionDepth(actorbounds, tilebounds); if (actorbounds.Intersects(tilebounds)) { WorldPosition = new Vector2(WorldPosition.X + depth.X, WorldPosition.Y); actorbounds = this.BoundingBox(); } } else if (stageTile.IsPlatform() && y == bottomTile) { List <Platform> tileboundsList = CurrentStage.getTilePlatformBoundsByGridPosition(x, bottomTile); foreach (Platform platformbounds in tileboundsList) { Rectangle tilebounds = platformbounds.PlatformBounds; Vector2 depth = RectangleExtensions.GetIntersectionDepth(actorbounds, tilebounds); if (this.PreviousBottom <= tilebounds.Top && Velocity.Y >= 0 && actorbounds.Intersects(tilebounds)) //if (Velocity.Y >= 0 && (depth.Y < 0)) // || this.IgnoreNextPlatform)) { this.IsOnGround = true; this.JumpInProgress = false; //this.Velocity.X = 0f; this.WorldPosition.Y += depth.Y; // perform further collisions with the new bounds actorbounds = this.BoundingBox(); } } } } } } if (wasonground && !IsOnGround) { Velocity.Y = 0; } this.PreviousBottom = actorbounds.Bottom; }
/// <summary> /// Detects and resolves all collisions between the character and his neighboring /// tiles. When a collision is detected, the character is pushed away along one /// axis to prevent overlapping. There is some special logic for the Y axis to /// handle platforms which behave differently depending on direction of movement. /// </summary> public void CharacterAndTiles(Character character) { // Get the player's bounding rectangle and find neighboring tiles. Rectangle bounds = character.BoundingRectangle; int leftTile = (int)Math.Floor((float)bounds.Left / LevelTile.Width); int rightTile = (int)Math.Ceiling(((float)bounds.Right / LevelTile.Width)) - 1; int topTile = (int)Math.Floor((float)bounds.Top / LevelTile.Height); int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / LevelTile.Height)) - 1; // Reset flag to search for ground collision. character.IsOnGround = false; //For each potentially colliding movable tile. foreach (var movableTile in Statics.Level.TileEngine.movableTiles) { // Reset flag to search for movable tile collision. movableTile.PlayerIsOn = false; //check to see if player is on tile. if ((character.BoundingRectangle.Bottom == movableTile.BoundingRectangle.Top + 1) && (character.BoundingRectangle.Left >= movableTile.BoundingRectangle.Left - (character.BoundingRectangle.Width / 2) && character.BoundingRectangle.Right <= movableTile.BoundingRectangle.Right + (character.BoundingRectangle.Width / 2))) { movableTile.PlayerIsOn = true; } bounds = HandleCollision(bounds, movableTile.Collision, movableTile.BoundingRectangle, character); } // For each potentially colliding tile, for (int y = topTile; y <= bottomTile; ++y) { for (int x = leftTile; x <= rightTile; ++x) { // If this tile is collidable, TileCollision collision = Statics.Level.TileEngine.GetCollision(x, y); if (collision != TileCollision.Passable) { // Determine collision depth (with direction) and magnitude. Rectangle tileBounds = Statics.Level.TileEngine.GetBounds(x, y); Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds); if (collision == TileCollision.Spike) { character.Health--; } if (depth != Vector2.Zero) { float absDepthX = Math.Abs(depth.X); float absDepthY = Math.Abs(depth.Y); // Resolve the collision along the shallow axis. if (absDepthY < absDepthX || collision == TileCollision.Platform) { // If we crossed the top of a tile, we are on the ground. if (character.previousBottom <= tileBounds.Top) { character.IsOnGround = true; } // Ignore platforms, unless we are on the ground. if (collision == TileCollision.Impassable || character.IsOnGround) { // Resolve the collision along the Y axis. character.Position = new Vector2(character.Position.X, character.Position.Y + depth.Y); // Perform further collisions with the new bounds. bounds = character.BoundingRectangle; } } else if (collision == TileCollision.Impassable || collision == TileCollision.Spike) // Ignore platforms. { float temp; // Resolve the collision along the X axis. if (character.direction == Enums.FaceDirection.Left && character != Statics.LevelPlayer) { temp = character.Position.X; } else { temp = character.Position.X + depth.X; } character.Position = new Vector2(temp, character.Position.Y); // Perform further collisions with the new bounds. bounds = character.BoundingRectangle; } } } } } // Save the new bounds bottom. character.previousBottom = bounds.Bottom; }
/// <summary> /// Animates each enemy and allow them to kill the player. /// </summary> public void PlayerAndEnemy(LevelPlayer player, Character enemy, GameTime gameTime) { if (player.oneFrame.Intersects(enemy.BoundingRectangle)) { //Enemy will stop walking, if their bounding box intersect with player and they are not doing some speical animation if (enemy.SpecialAnimationDone || enemy == Statics.Level.Boss) { if (enemy.MoveState != Enums.MoveState.Fall && enemy.MoveState != Enums.MoveState.FireFall && enemy.MoveState != Enums.MoveState.FireReaction) { enemy.movement = 0; } } // Resolve the collision along the X axis between player and enemy, player is not allow to go through the enemy. Vector2 depth = RectangleExtensions.GetIntersectionDepth(player.BoundingRectangle, enemy.BoundingRectangle); player.Position = new Vector2(player.Position.X + depth.X, player.Position.Y); if (player.MoveState == Enums.MoveState.SpecialCombo) { if (enemy == Statics.Level.Boss) { enemy.MoveState = Enums.MoveState.Fall; } else { enemy.MoveState = Enums.MoveState.FireFall; } enemy.SpecialAnimationDone = false; if (!player.AttackOnce) { enemy.Health -= player.AttackStrength; player.Health -= 3; player.AttackOnce = true; } player.movement = 0; } if (PerPixel.Collision(player.oneFrame, player.ColorData, enemy.oneFrame, enemy.ColorData)) { //Placing this test outside of the Intersects test ensures the player will be capable of damage from every enemy punch //This resolves the problem of only once damage per time the player entered the bounding Rectangle of the enemy. if (!player.AttackOnce && enemy.MoveState != Enums.MoveState.FinalCombo2 && (player.ComboCount > 0 || player.Health <= 0.2 * player.fullHealth)) { switch (player.MoveState) { case Enums.MoveState.Punch: enemy.MoveState = Enums.MoveState.Reaction; enemy.Health -= player.AttackStrength; enemy.hurtCount++; player.CountActions += 6; player.punchHurtCount++; break; case Enums.MoveState.PunchUp: enemy.MoveState = Enums.MoveState.Fall; enemy.Health -= player.AttackStrength; enemy.hurtCount += 2; player.CountActions += 6; break; case Enums.MoveState.Kick: enemy.MoveState = Enums.MoveState.Reaction; enemy.Health -= player.AttackStrength; enemy.hurtCount++; player.kickHurtCount++; player.CountActions += 10; break; case Enums.MoveState.ComboKick: enemy.MoveState = Enums.MoveState.Fall; enemy.Health -= 2 * player.AttackStrength; enemy.hurtCount += 2; player.CountActions += 20; break; case Enums.MoveState.FirePunch1: enemy.MoveState = Enums.MoveState.FireReaction; enemy.Health -= 2 * player.AttackStrength; player.CountActions += 15; break; case Enums.MoveState.FirePunch2: enemy.MoveState = Enums.MoveState.FireReaction; enemy.Health -= 2 * player.AttackStrength; player.CountActions += 15; break; case Enums.MoveState.FirePunch3: enemy.MoveState = Enums.MoveState.FireFall; enemy.Health -= 2 * player.AttackStrength; player.CountActions += 15; break; case Enums.MoveState.FinalCombo2: enemy.MoveState = Enums.MoveState.FireFall; enemy.Health -= 4 * player.AttackStrength; player.ComboCount--; break; } enemy.hurtSound.Play(); player.AttackOnce = true; enemy.SpecialAnimationDone = false; HitTime = gameTime.TotalRealTime; } if (!enemy.AttackOnce && player.SpecialAnimationDone) { if (enemy == Statics.Level.Boss) { switch (enemy.MoveState) { case Enums.MoveState.Punch: player.MoveState = Enums.MoveState.Fall; player.Health -= enemy.AttackStrength; enemy.hitCount++; break; case Enums.MoveState.FinalCombo2: player.MoveState = Enums.MoveState.Fall; player.Health -= 2 * enemy.AttackStrength; break; } } else { switch (enemy.MoveState) { case Enums.MoveState.FinalCombo1: player.MoveState = Enums.MoveState.Reaction; player.Health -= enemy.AttackStrength; enemy.hitCount++; break; case Enums.MoveState.FinalCombo2: player.MoveState = Enums.MoveState.Fall; player.Health -= 2 * enemy.AttackStrength; break; } } player.SpecialAnimationDone = false; enemy.hurtSound.Play(); enemy.AttackOnce = true; } } } //If no intersection between player rectangle and enemy rectangle frame //Add enemy movement towards player here... else { if (enemy.SpecialAnimationDone) { if (enemy == Statics.Level.Boss) { enemy.movement = 200; } else { enemy.movement = 65f; } enemy.MoveState = Enums.MoveState.Walk; } } }
/// <summary> /// Detects and resolves all collisions between the player and his neighboring /// tiles. When a collision is detected, the player is pushed away along one /// axis to prevent overlapping. There is some special logic for the Y axis to /// handle platforms which behave differently depending on direction of movement. /// </summary> private void HandleCollisions() { // Get the player's bounding rectangle and find neighboring tiles. Rectangle bounds = BoundingRectangle; int leftTile = (int)Math.Floor((float)bounds.Left / Tile.Width); int rightTile = (int)Math.Ceiling(((float)bounds.Right / Tile.Width)) - 1; int topTile = (int)Math.Floor((float)bounds.Top / Tile.Height); int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / Tile.Height)) - 1; // Reset flag to search for ground collision. isOnGround = false; // For each potentially colliding tile, for (int y = topTile; y <= bottomTile; ++y) { for (int x = leftTile; x <= rightTile; ++x) { // If this tile is collidable, TileCollision collision = Level.GetCollision(x, y); if (collision != TileCollision.Passable) { // Determine collision depth (with direction) and magnitude. Rectangle tileBounds = Level.GetBounds(x, y); Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds); if (depth != Vector2.Zero) { float absDepthX = (float)Math.Abs(depth.X); float absDepthY = (float)Math.Abs(depth.Y); // Resolve the collision along the shallow axis. if (absDepthY < absDepthX || collision == TileCollision.Platform) { // If we crossed the top of a tile, we are on the ground. if (previousBottom <= tileBounds.Top) { isOnGround = true; } // Ignore platforms, unless we are on the ground. if (collision == TileCollision.Impassable || IsOnGround) { // Resolve the collision along the Y axis. Position = new Vector2(Position.X, Position.Y + depth.Y); // Perform further collisions with the new bounds. bounds = BoundingRectangle; } } else if (collision == TileCollision.Impassable) // Ignore platforms. { // Resolve the collision along the X axis. Position = new Vector2(Position.X + depth.X, Position.Y); // Perform further collisions with the new bounds. bounds = BoundingRectangle; } } } } } // Save the new bounds bottom. previousBottom = bounds.Bottom; }
/// <summary> /// Instantiates a player, puts him in the level, and remembers where to put him when he is resurrected. /// </summary> private Tile LoadStartTile(int x, int y) { StartLocation = RectangleExtensions.GetBottomCenter(GetBounds(x, y)); return(LoadTile("Exit", new Vector2(x, y) * Tile.Size, TileCollision.Passable)); }