public static Edge GetNearestEdge(this TmxLayerTile self, int worldPosition) { var tileWidth = self.Tileset.Map.TileWidth; var tileMiddleWorldPosition = self.X * tileWidth + tileWidth / 2; return(worldPosition < tileMiddleWorldPosition ? Edge.Left : Edge.Right); }
/// <summary> /// sets the tile and updates its tileset. If you change a tiles gid to one in a different Tileset you must /// call this method or update the TmxLayerTile.tileset manually! /// </summary> /// <returns>The tile.</returns> /// <param name="tile">Tile.</param> public TmxLayerTile SetTile(TmxLayerTile tile) { Tiles[tile.X + tile.Y * Width] = tile; tile.Tileset = Map.GetTilesetForTileGid(tile.Gid); return(tile); }
public static Edge GetHighestSlopeEdge(this TmxLayerTile self) { // left and right already have flipping taken into account. Also remember a lower value means a taller slope since the slope values // are in pixels from the top! var left = self.GetSlopeTopLeft(); var right = self.GetSlopeTopRight(); return(right > left ? Edge.Left : Edge.Right); }
public static int GetSlopeTopRight(this TmxLayerTile self) { if (self.HorizontalFlip && self.VerticalFlip) { return(self.TilesetTile.SlopeTopRight); } if (self.HorizontalFlip) { return(self.TilesetTile.SlopeTopLeft); } if (self.VerticalFlip) { return(self.Tileset.Map.TileWidth - self.TilesetTile.SlopeTopRight); } return(self.TilesetTile.SlopeTopRight); }
public static float GetSlope(this TmxLayerTile self) { var tileSize = self.Tileset.Map.TileWidth; // flip our slopes sign if the tile is flipped horizontally or vertically if (self.HorizontalFlip) { tileSize *= -1; } if (self.VerticalFlip) { tileSize *= -1; } // rise over run return((self.TilesetTile.SlopeTopRight - (float)self.TilesetTile.SlopeTopLeft) / tileSize); }
public static float GetSlopeOffset(this TmxLayerTile self) => self.GetSlopeTopLeft();
public static bool IsOneWayPlatform(this TmxLayerTile self) => self.TilesetTile != null && self.TilesetTile.IsOneWayPlatform;
public static bool IsSlope(this TmxLayerTile self) => self.TilesetTile != null && self.TilesetTile.IsSlope;
public void ClearLastGroundTile() => _lastGroundTile = null;
/// <summary> /// Tests the tile for a collision. Returns via out the position in world space where the collision occured. /// </summary> /// <returns>The tile collision.</returns> /// <param name="tile">Tile.</param> /// <param name="edgeToTest">the opposite side of movement, the side the leading edge will collide with</param> /// <param name="perpindicularPosition">Perpindicular position.</param> /// <param name="leadingPosition">Leading position.</param> /// <param name="shouldTestSlopes">Should test slopes.</param> /// <param name="collisionResponse">Collision response.</param> bool TestTileCollision(TmxLayerTile tile, Edge edgeToTest, int perpindicularPosition, int leadingPosition, bool shouldTestSlopes, out int collisionResponse) { collisionResponse = leadingPosition; // one way platforms are only collideable from the top when the player is already above them if (tile.IsOneWayPlatform()) { // only the top edge of one way platforms are checked for collisions if (edgeToTest != Edge.Top) { return(false); } // our response should be the top of the platform collisionResponse = TiledMap.TileToWorldPositionX(tile.Y); return(_boxColliderBounds.Bottom <= collisionResponse); } var forceSlopedTileCheckAsWall = false; // when moving horizontally the only time a slope is considered for collision testing is when its closest side is the tallest side // and we were not intesecting the tile before moving. // this prevents clipping through a tile when hitting its edge: -> |\ if (edgeToTest.IsHorizontal() && tile.IsSlope() && tile.GetNearestEdge(leadingPosition) == tile.GetHighestSlopeEdge()) { var moveDir = edgeToTest.OppositeEdge(); var leadingPositionPreMovement = _boxColliderBounds.GetSide(moveDir); // we need the tile x position that is on the opposite side of our move direction. Moving right we want the left edge var tileX = moveDir == Edge.Right ? TiledMap.TileToWorldPositionX(tile.X) : TiledMap.TileToWorldPositionX(tile.X + 1); // using the edge before movement, we see if we were colliding before moving. var wasCollidingBeforeMove = moveDir == Edge.Right ? leadingPositionPreMovement > tileX : leadingPositionPreMovement < tileX; // if we were not colliding before moving we need to consider this tile for a collision check as if it were a wall tile forceSlopedTileCheckAsWall = !wasCollidingBeforeMove; } if (forceSlopedTileCheckAsWall || !tile.IsSlope()) { switch (edgeToTest) { case Edge.Top: collisionResponse = TiledMap.TileToWorldPositionY(tile.Y); break; case Edge.Bottom: collisionResponse = TiledMap.TileToWorldPositionY(tile.Y + 1); break; case Edge.Left: collisionResponse = TiledMap.TileToWorldPositionX(tile.X); break; case Edge.Right: collisionResponse = TiledMap.TileToWorldPositionX(tile.X + 1); break; } return(true); } if (shouldTestSlopes) { var tileWorldX = TiledMap.TileToWorldPositionX(tile.X); var tileWorldY = TiledMap.TileToWorldPositionX(tile.Y); var slope = tile.GetSlope(); var offset = tile.GetSlopeOffset(); // calculate the point on the slope at perpindicularPosition collisionResponse = (int)(edgeToTest.IsVertical() ? slope * (perpindicularPosition - tileWorldX) + offset + tileWorldY : (perpindicularPosition - tileWorldY - offset) / slope + tileWorldX); var isColliding = edgeToTest.IsMax() ? leadingPosition <= collisionResponse : leadingPosition >= collisionResponse; // this code ensures that we dont consider collisions on a slope while jumping up that dont intersect our collider. // It also makes sure when testing the bottom edge that the leadingPosition is actually above the collisionResponse. // HACK: It isn't totally perfect but it does the job if (isColliding && edgeToTest == Edge.Bottom && leadingPosition <= collisionResponse) { isColliding = false; } return(isColliding); } return(false); }