/// <summary> /// sets the tile and updates its tileset /// </summary> /// <returns>The tile.</returns> /// <param name="tile">Tile.</param> public TiledTile SetTile(TiledTile tile) { Tiles[tile.X + tile.Y * Width] = tile; tile.Tileset = TiledMap.GetTilesetForTileId(tile.Id); return(tile); }
public static Edge getNearestEdge(this TiledTile self, int worldPosition) { var tileWidth = self.tilesetTile.tiledMap.tileWidth; var tileMiddleWorldPosition = self.x * tileWidth + tileWidth / 2; return(worldPosition < tileMiddleWorldPosition ? Edge.Left : Edge.Right); }
private static TiledTileLayer readTileLayer(ContentReader reader, TiledMap tileMap, string layerName) { var tileDataCount = reader.ReadInt32(); var tileData = new TiledTile[tileDataCount]; for (var d = 0; d < tileDataCount; d++) { var tileId = reader.ReadInt32(); var flippedHorizonally = reader.ReadBoolean(); var flippedVertically = reader.ReadBoolean(); var flippedDiagonally = reader.ReadBoolean(); // dont add null tiles if (tileId != 0) { tileData[d] = new TiledTile(tileId) { flippedHorizonally = flippedHorizonally, flippedVertically = flippedVertically, flippedDiagonally = flippedDiagonally }; } else { tileData[d] = null; } } return(tileMap.createTileLayer( name: layerName, width: reader.ReadInt32(), height: reader.ReadInt32(), data: tileData)); }
/// <summary> /// sets the tile and updates its tileset /// </summary> /// <returns>The tile.</returns> /// <param name="tile">Tile.</param> public TiledTile setTile(TiledTile tile) { tiles[tile.x + tile.y * width] = tile; tile.tileset = tiledMap.getTilesetForTileId(tile.id); return(tile); }
/// <summary> /// returns the bounds Rectangle of the passed in tile /// </summary> /// <returns>The bounds for tile.</returns> /// <param name="tile">Tile.</param> /// <param name="tilemap">Tilemap.</param> public static Rectangle getBoundsForTile(TiledTile tile, TiledMap tilemap) { return(new Rectangle( tile.x * tilemap.tileWidth, tile.y * tilemap.tileHeight, tilemap.tileWidth, tilemap.tileHeight)); }
void renderOrthogonal(Batcher batcher, TiledTile tile, Subtexture region) { // not exactly sure why we need to compensate 1 pixel here. Could be a bug in MonoGame? var tx = tile.x * tiledMap.tileWidth; var ty = tile.y * (tiledMap.tileHeight - 1); batcher.draw(region.texture2D, new Rectangle(tx, ty, region.sourceRect.Width, region.sourceRect.Height), region.sourceRect, color); }
public static Edge getHighestSlopeEdge(this TiledTile 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); }
void renderOrthogonal(SpriteBatch spriteBatch, TiledTile tile, Subtexture region) { // not exactly sure why we need to compensate 1 pixel here. Could be a bug in MonoGame? var tx = tile.x * tilemap.tileWidth; var ty = tile.y * (tilemap.tileHeight - 1); spriteBatch.Draw(region.texture2D, new Rectangle(tx, ty, region.sourceRect.Width, region.sourceRect.Height), region.sourceRect, Color.White); //spriteBatch.Draw( region, new Rectangle( tx, ty, region.bounds.Width, region.bounds.Height ), Color.White ); }
static TiledLayer readTileLayer(ContentReader reader, TiledMap tileMap, string layerName) { var tileCount = reader.ReadInt32(); var tiles = new TiledTile[tileCount]; for (var i = 0; i < tileCount; i++) { var tileId = reader.ReadInt32(); var flippedHorizonally = reader.ReadBoolean(); var flippedVertically = reader.ReadBoolean(); var flippedDiagonally = reader.ReadBoolean(); // dont add null tiles if (tileId != 0) { var tilesetTile = tileMap.getTilesetTile(tileId); if (tilesetTile != null && tilesetTile.animationFrames != null) { if (tilesetTile.animationFrames.Count > 0) { tiles[i] = new TiledAnimatedTile(tileId, tilesetTile) { flippedHorizonally = flippedHorizonally, flippedVertically = flippedVertically, flippedDiagonally = flippedDiagonally }; tileMap._animatedTiles.Add(tiles[i] as TiledAnimatedTile); } } else { tiles[i] = new TiledTile(tileId) { flippedHorizonally = flippedHorizonally, flippedVertically = flippedVertically, flippedDiagonally = flippedDiagonally }; } tiles[i].tileset = tileMap.getTilesetForTileId(tileId); } else { tiles[i] = null; } } return(tileMap.createTileLayer( name: layerName, width: reader.ReadInt32(), height: reader.ReadInt32(), tiles: tiles)); }
public TiledTileLayer( TiledMap map, string name, int width, int height, TiledTile[] tiles ) : base(name) { this.width = width; this.height = height; this.tiles = tiles; tiledMap = map; tiles = populateTilePositions(); }
public static Edge getHighestSlopeEdge(this TiledTile self) { var left = self.getSlopeTopLeft(); var right = self.getSlopeTopRight(); if (self.flippedVertically) { return(right > left ? Edge.Right : Edge.Left); } return(right > left ? Edge.Left : Edge.Right); }
bool testMapCollision(Rectangle collisionRect, Edge direction, out int collisionResponse) { collisionResponse = 0; var side = direction.oppositeEdge(); var perpindicularPosition = side.isVertical() ? collisionRect.Center.X : collisionRect.Center.Y; var leadingPosition = collisionRect.getSide(direction); var shouldTestSlopes = side.isVertical(); populateCollidingTiles(collisionRect, direction); for (var i = 0; i < _collidingTiles.Count; i++) { if (_collidingTiles[i] == null) { continue; } // TODO: is this necessary? seems to work without it // disregard horizontal collisions if the last tile we were grounded on was a slope // this is not a fantastic solution if (direction.isHorizontal() && _lastGroundTile != null && _lastGroundTile.isSlope()) { continue; } if (testTileCollision(_collidingTiles[i], side, perpindicularPosition, leadingPosition, shouldTestSlopes, out collisionResponse)) { // store off our last ground tile if we collided below if (direction == Edge.Bottom) { _lastGroundTile = _collidingTiles[i]; } return(true); } // special case for sloped ground tiles if (_lastGroundTile != null && direction == Edge.Bottom) { // if grounded on a slope and intersecting a slope or if grounded on a wall and intersecting a tall slope we go sticky // tall slope here means one where the the slopeTopLeft/Right is 0, i.e. it connects to a wall if ((_lastGroundTile.isSlope() && _collidingTiles[i].isSlope()) || (!_lastGroundTile.isSlope() && _collidingTiles[i].isSlope() /* should be tall slope check */)) { // store off our last ground tile if we collided below _lastGroundTile = _collidingTiles[i]; return(true); } } } return(false); }
void renderIsometric(Batcher batcher, TiledTile tile, Subtexture region) { var tx = (tile.x * (tiledMap.tileWidth / 2)) - (tile.y * (tiledMap.tileWidth / 2)) //Center + (tiledMap.width * (tiledMap.tileWidth / 2)) //Compensate Bug? - (tiledMap.tileWidth / 2); var ty = (tile.y * (tiledMap.tileHeight / 2)) + (tile.x * (tiledMap.tileHeight / 2)) //Compensate Bug? - (tiledMap.tileWidth + tiledMap.tileHeight); batcher.draw(region.texture2D, new Rectangle(tx, ty, region.sourceRect.Width, region.sourceRect.Height), region.sourceRect, color); }
void renderIsometric(SpriteBatch spriteBatch, TiledTile tile, Subtexture region) { var tx = (tile.x * (tilemap.tileWidth / 2)) - (tile.y * (tilemap.tileWidth / 2)) //Center + (tilemap.width * (tilemap.tileWidth / 2)) //Compensate Bug? - (tilemap.tileWidth / 2); var ty = (tile.y * (tilemap.tileHeight / 2)) + (tile.x * (tilemap.tileHeight / 2)) //Compensate Bug? - (tilemap.tileWidth + tilemap.tileHeight); spriteBatch.Draw(region.texture2D, new Rectangle(tx, ty, region.sourceRect.Width, region.sourceRect.Height), region.sourceRect, Color.White); //spriteBatch.Draw( region, new Rectangle( tx, ty, region.bounds.Width, region.bounds.Height ), Color.White ); }
void renderLayer(Batcher batcher, TiledMap map, TiledTile tile, Subtexture region) { switch (map.orientation) { case TiledMapOrientation.Orthogonal: renderOrthogonal(batcher, tile, region); break; case TiledMapOrientation.Isometric: renderIsometric(batcher, tile, region); break; case TiledMapOrientation.Staggered: throw new NotImplementedException("Staggered maps are currently not supported"); } }
public static int getSlopeTopRight(this TiledTile self) { if (self.flippedHorizonally && self.flippedVertically) { return(self.tilesetTile.slopeTopRight); } if (self.flippedHorizonally) { return(self.tilesetTile.slopeTopLeft); } if (self.flippedVertically) { return(self.tilesetTile.tiledMap.tileWidth - self.tilesetTile.slopeTopRight); } return(self.tilesetTile.slopeTopRight); }
public static float getSlope(this TiledTile self) { var tileSize = self.tilesetTile.tiledMap.tileWidth; // flip our slopes sign if the tile is flipped horizontally or vertically if (self.flippedHorizonally) { tileSize *= -1; } if (self.flippedVertically) { tileSize *= -1; } // rise over run return(((float)self.tilesetTile.slopeTopRight - (float)self.tilesetTile.slopeTopLeft) / (float)tileSize); }
/// <summary> /// moves the Entity taking into account the tiled map /// </summary> /// <param name="motion">Motion.</param> /// <param name="deltaTime">Delta time.</param> public void move( Vector2 motion, float deltaTime ) { // save off our current grounded state which we will use for wasGroundedLastFrame and becameGroundedThisFrame collisionState.wasGroundedLastFrame = collisionState.below; // reset our collisions state collisionState.reset(); // deal with subpixel movement, storing off any non-integar remainder for the next frame _movementRemainderX += motion.X; var motionX = Mathf.truncateToInt( _movementRemainderX ); _movementRemainderX -= motionX; motion.X = motionX; _movementRemainderY += motion.Y; var motionY = Mathf.truncateToInt( _movementRemainderY ); _movementRemainderY -= motionY; motion.Y = motionY; // store off the bounds so we can move it around without affecting the actual Transform position var colliderBounds = _collider.bounds; // first, check movement in the horizontal dir { var direction = motionX > 0 ? Edge.Right : Edge.Left; var sweptBounds = collisionRectForSide( direction, motionX ); int collisionResponse; if( testMapCollision( sweptBounds, direction, out collisionResponse ) ) { // react to collision. get the distance between our leading edge and what we collided with motion.X = collisionResponse - colliderBounds.getSide( direction ); collisionState.left = direction == Edge.Left; collisionState.right = direction == Edge.Right; } else { collisionState.left = false; collisionState.right = false; } } // next, check movement in the vertical dir { // HACK: when motionY is 0 we shouldnt check anything and we should retain collision state if( motionY == 0 ) motionY = 1; var direction = motionY > 0 ? Edge.Bottom : Edge.Top; var sweptBounds = collisionRectForSide( direction, motionY ); sweptBounds.X += (int)motion.X; int collisionResponse; if( testMapCollision( sweptBounds, direction, out collisionResponse ) ) { // react to collision. get the distance between our leading edge and what we collided with motion.Y = collisionResponse - colliderBounds.getSide( direction ); collisionState.above = direction == Edge.Top; collisionState.below = direction == Edge.Bottom; } else { collisionState.above = false; collisionState.below = false; _lastGroundTile = null; } // when moving down we also check for collisions in the opposite direction if( direction == Edge.Bottom ) { direction = direction.oppositeEdge(); sweptBounds = collisionRectForSide( direction, 0 ); sweptBounds.X += (int)motion.X; sweptBounds.Y += (int)motion.Y; if( testMapCollision( sweptBounds, direction, out collisionResponse ) ) { // react to collision. get the distance between our leading edge and what we collided with motion.Y = collisionResponse - colliderBounds.getSide( direction ); // if we collide here this is an overlap of a slope above us. this small bump down will prevent hitches when hitting // our head on a slope that connects to a solid tile. It puts us below the slope when the normal response would put us // above it motion.Y += 2; collisionState.above = true; } } } // move then update our state _collider.unregisterColliderWithPhysicsSystem(); transform.position += motion; _collider.registerColliderWithPhysicsSystem(); // only calculate velocity if we have a non-zero deltaTime if( deltaTime > 0f ) velocity = motion / deltaTime; if( collisionState.below || collisionState.above ) { _movementRemainderY = 0; velocity.Y = 0; } if( collisionState.right || collisionState.left ) { _movementRemainderX = 0; velocity.X = 0; } // set our becameGrounded state based on the previous and current collision state if( !collisionState.wasGroundedLastFrame && collisionState.below ) collisionState.becameGroundedThisFrame = true; }
/// <summary> /// returns the bounds Rectangle of the passed in tile /// </summary> /// <returns>The bounds for tile.</returns> /// <param name="tile">Tile.</param> /// <param name="tilemap">Tilemap.</param> public static Rectangle getBoundsForTile( TiledTile tile, TiledMap tilemap ) { return new Rectangle( tile.x * tilemap.tileWidth, tile.y * tilemap.tileHeight, tilemap.tileWidth, tilemap.tileHeight ); }
public static bool isOneWayPlatform(this TiledTile self) { return(self.tilesetTile != null && self.tilesetTile.isOneWayPlatform); }
public void clearLastGroundTile() { _lastGroundTile = null; }
public static bool isSlope(this TiledTile self) { return(self.tilesetTile != null && self.tilesetTile.isSlope); }
public static float getSlopeOffset(this TiledTile self) { return((float)self.getSlopeTopLeft()); }
bool testMapCollision( Rectangle collisionRect, Edge direction, out int collisionResponse ) { collisionResponse = 0; var side = direction.oppositeEdge(); var perpindicularPosition = side.isVertical() ? collisionRect.Center.X : collisionRect.Center.Y; var leadingPosition = collisionRect.getSide( direction ); var shouldTestSlopes = side.isVertical(); populateCollidingTiles( collisionRect, direction ); for( var i = 0; i < _collidingTiles.Count; i++ ) { if( _collidingTiles[i] == null ) continue; // TODO: is this necessary? seems to work without it // disregard horizontal collisions if the last tile we were grounded on was a slope // this is not a fantastic solution if( direction.isHorizontal() && _lastGroundTile != null && _lastGroundTile.isSlope() ) continue; if( testTileCollision( _collidingTiles[i], side, perpindicularPosition, leadingPosition, shouldTestSlopes, out collisionResponse ) ) { // store off our last ground tile if we collided below if( direction == Edge.Bottom ) _lastGroundTile = _collidingTiles[i]; return true; } // special case for sloped ground tiles if( _lastGroundTile != null && direction == Edge.Bottom ) { // if grounded on a slope and intersecting a slope or if grounded on a wall and intersecting a tall slope we go sticky // tall slope here means one where the the slopeTopLeft/Right is 0, i.e. it connects to a wall if( ( _lastGroundTile.isSlope() && _collidingTiles[i].isSlope() ) || ( !_lastGroundTile.isSlope() && _collidingTiles[i].isSlope() /* should be tall slope check */ ) ) { // store off our last ground tile if we collided below _lastGroundTile = _collidingTiles[i]; return true; } } } return false; }
/// <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(TiledTile 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); }
/// <summary> /// moves the Entity taking into account the tiled map /// </summary> /// <param name="motion">Motion.</param> /// <param name="deltaTime">Delta time.</param> public void move(Vector2 motion, float deltaTime) { // save off our current grounded state which we will use for wasGroundedLastFrame and becameGroundedThisFrame collisionState.wasGroundedLastFrame = collisionState.below; // reset our collisions state collisionState.reset(); // deal with subpixel movement, storing off any non-integar remainder for the next frame _movementRemainderX += motion.X; var motionX = Mathf.truncateToInt(_movementRemainderX); _movementRemainderX -= motionX; motion.X = motionX; _movementRemainderY += motion.Y; var motionY = Mathf.truncateToInt(_movementRemainderY); _movementRemainderY -= motionY; motion.Y = motionY; // store off the bounds so we can move it around without affecting the actual Transform position var colliderBounds = _collider.bounds; // first, check movement in the horizontal dir { var direction = motionX > 0 ? Edge.Right : Edge.Left; var sweptBounds = collisionRectForSide(direction, motionX); int collisionResponse; if (testMapCollision(sweptBounds, direction, out collisionResponse)) { // react to collision. get the distance between our leading edge and what we collided with motion.X = collisionResponse - colliderBounds.getSide(direction); collisionState.left = direction == Edge.Left; collisionState.right = direction == Edge.Right; } else { collisionState.left = false; collisionState.right = false; } } // next, check movement in the vertical dir { // HACK: when motionY is 0 we shouldnt check anything and we should retain collision state if (motionY == 0) { motionY = 1; } var direction = motionY > 0 ? Edge.Bottom : Edge.Top; var sweptBounds = collisionRectForSide(direction, motionY); sweptBounds.X += (int)motion.X; int collisionResponse; if (testMapCollision(sweptBounds, direction, out collisionResponse)) { // react to collision. get the distance between our leading edge and what we collided with motion.Y = collisionResponse - colliderBounds.getSide(direction); collisionState.above = direction == Edge.Top; collisionState.below = direction == Edge.Bottom; } else { collisionState.above = false; collisionState.below = false; _lastGroundTile = null; } // when moving down we also check for collisions in the opposite direction if (direction == Edge.Bottom) { direction = direction.oppositeEdge(); sweptBounds = collisionRectForSide(direction, 0); sweptBounds.X += (int)motion.X; sweptBounds.Y += (int)motion.Y; if (testMapCollision(sweptBounds, direction, out collisionResponse)) { // react to collision. get the distance between our leading edge and what we collided with motion.Y = collisionResponse - colliderBounds.getSide(direction); // if we collide here this is an overlap of a slope above us. this small bump down will prevent hitches when hitting // our head on a slope that connects to a solid tile. It puts us below the slope when the normal response would put us // above it motion.Y += 2; collisionState.above = true; } } } // move then update our state _collider.unregisterColliderWithPhysicsSystem(); transform.position += motion; _collider.registerColliderWithPhysicsSystem(); // only calculate velocity if we have a non-zero deltaTime if (deltaTime > 0f) { velocity = motion / deltaTime; } if (collisionState.below || collisionState.above) { _movementRemainderY = 0; velocity.Y = 0; } if (collisionState.right || collisionState.left) { _movementRemainderX = 0; velocity.X = 0; } // set our becameGrounded state based on the previous and current collision state if (!collisionState.wasGroundedLastFrame && collisionState.below) { collisionState.becameGroundedThisFrame = true; } }
/// <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( TiledTile 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; }