public List <CollisionTile> GetCollidingTiles(Rectangle rectangle, TileInfo.SideType direction) { TileUnit firstPrimary = Units.GameToTile(rectangle.Side(TileInfo.OppositeSide(direction))); TileUnit lastPrimary = Units.GameToTile(rectangle.Side(direction)); int primaryIncr = TileInfo.IsMax(direction) ? 1 : -1; bool horizontal = TileInfo.Horizontal(direction); TileUnit sMin = Units.GameToTile(horizontal ? rectangle.Top : rectangle.Left); TileUnit sMid = Units.GameToTile(horizontal ? rectangle.Center.Y : rectangle.Center.X); TileUnit sMax = Units.GameToTile(horizontal ? rectangle.Bottom : rectangle.Right); bool sPositive = sMid - sMin < sMax - sMid; int secondaryIncr = sPositive ? 1 : -1; TileUnit firstSecondary = sPositive ? sMin : sMax; TileUnit lastSecondary = sPositive ? sMin : sMax; List <CollisionTile> collisionTiles = new List <CollisionTile>(); for (TileUnit primary = firstPrimary; primary != lastPrimary + primaryIncr; primary = Convert.ToUInt32(Convert.ToInt32(primary) + primaryIncr)) { for (TileUnit secondary = firstSecondary; secondary != lastSecondary + secondaryIncr; secondary = Convert.ToUInt32(Convert.ToInt32(secondary) + secondaryIncr)) { TileUnit row = !horizontal ? primary : secondary; TileUnit col = horizontal ? primary : secondary; collisionTiles.Add(new CollisionTile(row, col, tiles[Convert.ToInt32(row)][Convert.ToInt32(col)].tileType)); } } return(collisionTiles); }
protected override void OnCollision(TileInfo.SideType side, bool isDeltaDirection, BitArray tileType) { switch (side) { case TileInfo.SideType.TopSide: if (isDeltaDirection) { kinematicsY.velocity = 0; particleTools.FrontSystem.AddNewParticle(new HeadBumpParticle(particleTools.Content, CenterX, kinematicsY.position + collisionRectangle.BoundingBox.Top)); } break; case TileInfo.SideType.BottomSide: maybeGroundTile = tileType; if (isDeltaDirection) { kinematicsY.velocity = 0; } break; case TileInfo.SideType.LeftSide: if (isDeltaDirection) { kinematicsX.velocity = 0; } break; case TileInfo.SideType.RightSide: if (isDeltaDirection) { kinematicsX.velocity = 0; } break; } }
/// <summary> /// Returns true if projectile is still alive /// </summary> /// <param name="gameTime"></param> /// <returns>True if projectile is still alive</returns> public bool Update(GameTime gameTime, Map map, ParticleTools particleTools) { offset += (float)gameTime.ElapsedGameTime.TotalMilliseconds * ProjectileSpeed; TileInfo.SideType direction = TileInfo.FromFacing(horizontalDirection, verticalDirection); Rectangle rectangle = CollisionRectangle; List <CollisionTile> collidingTiles = map.GetCollidingTiles(rectangle, direction); for (int i = 0; i < collidingTiles.Count; i++) { TileInfo.SideType side = TileInfo.OppositeSide(direction); GameUnit perpendicularPosition = TileInfo.Vertical(side) ? rectangle.Center.X : rectangle.Center.Y; GameUnit leadingPosition = rectangle.Side(direction); bool shouldTestSlopes = true; TestCollisionInfo testInfo = collidingTiles[i].TestCollision(side, perpendicularPosition, leadingPosition, shouldTestSlopes); if (testInfo.isColliding) { GameUnit collisionX; if (TileInfo.Vertical(side)) { collisionX = perpendicularPosition; } else { collisionX = testInfo.position; } GameUnit collisionY; if (TileInfo.Vertical(side)) { collisionY = testInfo.position; } else { collisionY = perpendicularPosition; } particleTools.FrontSystem.AddNewParticle(ProjectileWallParticle.Create(particleTools.Content, collisionX - Units.HalfTile, collisionY - Units.HalfTile)); return(false); } } if (!alive) { return(false); } else if (offset >= ProjectileMaxOffsets[gunLevel - 1]) { particleTools.FrontSystem.AddNewParticle(ProjectileStarParticle.Create(particleTools.Content, X, Y)); return(false); } else { return(true); } }
private void Update(ICollisionRectangle collisionRectangle, IAccelerator accelerator, Kinematics kinematicsX, Kinematics kinematicsY, GameTime gameTime, Map map, BitArray maybeGroundTile, Kinematics kinematics, AxisType axis) { Func <Map, Rectangle, TileInfo.SideType, BitArray, CollisionInfo?> testMapCollisionFunc; if (collisionType == CollisionType.BouncingCollision) { testMapCollisionFunc = TestMapBouncingCollision; } else { testMapCollisionFunc = TestMapStickyCollision; } accelerator.UpdateVelocity(kinematics, gameTime); GameUnit delta = kinematics.velocity * (float)gameTime.ElapsedGameTime.TotalMilliseconds; TileInfo.SideType direction = axis == AxisType.XAxis ? (delta > 0 ? TileInfo.SideType.RightSide : TileInfo.SideType.LeftSide) : (delta > 0 ? TileInfo.SideType.BottomSide : TileInfo.SideType.TopSide); CollisionInfo?maybeInfo = testMapCollisionFunc(map, collisionRectangle.Collision(direction, kinematicsX.position, kinematicsY.position, delta), direction, maybeGroundTile); if (maybeInfo.HasValue) { kinematics.position = maybeInfo.Value.position - collisionRectangle.BoundingBox.Side(direction); debugCollidingTiles.Add(maybeInfo.Value.tilePosition); OnCollision(direction, true, maybeInfo.Value.tileType); } else { kinematics.position += delta; OnDelta(direction); } maybeInfo = null; TileInfo.SideType oppositeDirection = TileInfo.OppositeSide(direction); maybeInfo = testMapCollisionFunc(map, collisionRectangle.Collision(oppositeDirection, kinematicsX.position, kinematicsY.position, 0), oppositeDirection, null); if (maybeInfo.HasValue) { kinematics.position = maybeInfo.Value.position - collisionRectangle.BoundingBox.Side(oppositeDirection); debugOppositeCollidingTiles.Add(maybeInfo.Value.tilePosition); OnCollision(oppositeDirection, false, maybeInfo.Value.tileType); } }
protected override void OnCollision(TileInfo.SideType side, bool isDeltaDirection, BitArray tileType) { if (side == TileInfo.SideType.TopSide) { kinematicsY.velocity = 0; } else if (side == TileInfo.SideType.BottomSide) { kinematicsY.velocity = -BounceSpeed; } else { kinematicsX.velocity *= -1; } }
public Rectangle Collision(TileInfo.SideType side, GameUnit x, GameUnit y, GameUnit delta) { if (side == TileInfo.SideType.LeftSide) { return(LeftCollision(x, y, delta)); } if (side == TileInfo.SideType.RightSide) { return(RightCollision(x, y, delta)); } if (side == TileInfo.SideType.TopSide) { return(TopCollision(x, y, delta)); } return(BottomCollision(x, y, delta)); }
public static int Side(this Rectangle rectangle, TileInfo.SideType side) { if (side == TileInfo.SideType.LeftSide) { return(rectangle.Left); } if (side == TileInfo.SideType.RightSide) { return(rectangle.Right); } if (side == TileInfo.SideType.TopSide) { return(rectangle.Top); } return(rectangle.Bottom); }
protected override void OnDelta(TileInfo.SideType side) { switch (side) { case TileInfo.SideType.TopSide: case TileInfo.SideType.BottomSide: maybeGroundTile = null; break; case TileInfo.SideType.LeftSide: break; case TileInfo.SideType.RightSide: break; } }
/// <summary> /// /// </summary> /// <param name="side">The side of the tile that is being collided with</param> /// <param name="perpendicularPosition">The position on the tile on the opposite axis of side</param> /// <param name="leadingPosition">Position of the leading edge of the colliding entity</param> /// <param name="shouldTestSlopes">whether slopes should be considered for collision</param> /// <returns> /// isColliding is true if there was a collision /// Returns the position of the collision on the same axis of side /// </returns> public TestCollisionInfo TestCollision(TileInfo.SideType side, GameUnit perpendicularPosition, GameUnit leadingPosition, bool shouldTestSlopes) { TestCollisionInfo info = new TestCollisionInfo(false, leadingPosition); if (tileType[(int)TileInfo.TileFlag.Wall]) { info.isColliding = true; if (side == TileInfo.SideType.TopSide) { info.position = Units.TileToGame(row); } else if (side == TileInfo.SideType.BottomSide) { info.position = Units.TileToGame(row + 1); } else if (side == TileInfo.SideType.LeftSide) { info.position = Units.TileToGame(col); } else { info.position = Units.TileToGame(col + 1); } } else if (shouldTestSlopes && tileType[(int)TileInfo.TileFlag.Slope] && !tileType[(int)TileInfo.SlopeFlagFromSide(side)]) { GameUnit row = Units.TileToGame(this.row); GameUnit col = Units.TileToGame(this.col); float slope = GetSlope(tileType); GameUnit offset = GetOffset(tileType); GameUnit calculatedPosition = TileInfo.Vertical(side) ? slope * (perpendicularPosition - col) + offset + row : (perpendicularPosition - row - offset) / slope + col; bool isColliding = TileInfo.IsMax(side) ? leadingPosition <= calculatedPosition : leadingPosition >= calculatedPosition; info.isColliding = isColliding; info.position = calculatedPosition; } return(info); }
CollisionInfo?TestMapStickyCollision(Map map, Rectangle rectangle, TileInfo.SideType direction, BitArray maybeGroundTile) { List <CollisionTile> tiles = map.GetCollidingTiles(rectangle, direction); for (int i = 0; i < tiles.Count; i++) { TileInfo.SideType side = TileInfo.OppositeSide(direction); GameUnit perpendicularPosition; if (TileInfo.Vertical(side)) { perpendicularPosition = rectangle.Center.X; } else { perpendicularPosition = rectangle.Center.Y; } GameUnit leadingPosition = rectangle.Side(direction); bool shouldTestSlopes = TileInfo.Vertical(side); TestCollisionInfo testInfo = tiles[i].TestCollision(side, perpendicularPosition, leadingPosition, shouldTestSlopes); if (testInfo.isColliding) { CollisionInfo info = new CollisionInfo(testInfo.position, tiles[i].Position, tiles[i].TileType); return(info); } else if (maybeGroundTile != null && direction == TileInfo.SideType.BottomSide) { BitArray tallSlope = TileInfo.CreateTileType(); tallSlope.Set((int)TileInfo.TileFlag.Slope, true); tallSlope.Set((int)TileInfo.TileFlag.TallSlope, true); if ((maybeGroundTile[(int)TileInfo.TileFlag.Slope] && tiles[i].TileType[(int)TileInfo.TileFlag.Slope]) || (maybeGroundTile[(int)TileInfo.TileFlag.Wall] && (tallSlope.And(tiles[i].TileType).Equals(tallSlope)))) { CollisionInfo info = new CollisionInfo(testInfo.position, tiles[i].Position, tiles[i].TileType); return(info); } } } return(null); }
CollisionInfo?TestMapBouncingCollision(Map map, Rectangle rectangle, TileInfo.SideType direction, BitArray maybeGroundTile) { List <CollisionTile> tiles = map.GetCollidingTiles(rectangle, direction); CollisionInfo? result = null; for (int i = 0; i < tiles.Count; i++) { TileInfo.SideType side = TileInfo.OppositeSide(direction); GameUnit perpendicularPosition; if (TileInfo.Vertical(side)) { perpendicularPosition = rectangle.Center.X; } else { perpendicularPosition = rectangle.Center.Y; } GameUnit leadingPosition = rectangle.Side(direction); bool shouldTestSlopes = TileInfo.Vertical(side); TestCollisionInfo testInfo = tiles[i].TestCollision(side, perpendicularPosition, leadingPosition, shouldTestSlopes); if (testInfo.isColliding) { bool shouldReplaceResult = true; if (result.HasValue) { shouldReplaceResult = TileInfo.IsMin(side) ? testInfo.position <result.Value.position : testInfo.position> result.Value.position; } if (shouldReplaceResult) { CollisionInfo info = new CollisionInfo(testInfo.position, tiles[i].Position, tiles[i].TileType); result = info; } } } return(result); }
protected override void OnDelta(TileInfo.SideType side) { }
protected abstract void OnDelta(TileInfo.SideType side);
protected abstract void OnCollision(TileInfo.SideType side, bool isDeltaDirection, BitArray tileType);