private RectangleF CheckEntityCollisions(List <Collision> blockEntities, CollisionBox hitbox, RectangleF boundbox, bool pushAway = true, bool solidOnly = true) { foreach (var entity in Parent.Entities.GetAll()) { if (entity == Parent) { continue; } CollisionComponent coll = entity.GetComponent <CollisionComponent>(); if (coll == null) { continue; } IEnumerable <CollisionBox> collToCheck = (solidOnly) ? coll.HitByBoxes(hitbox).Where(box => box.Properties.Blocking) : coll.HitByBoxes(hitbox); foreach (CollisionBox targetBox in collToCheck) { // if he's blocking, check for collision and maybe push me away RectangleF rect = targetBox.BoxAt(coll.PositionSrc.Position); RectangleF adjustrect = rect; adjustrect.X -= Const.PixelEpsilon; adjustrect.Y -= Const.PixelEpsilon; adjustrect.Width += 2 * Const.PixelEpsilon; adjustrect.Height += 2 - Const.PixelEpsilon; RectangleF intersection = RectangleF.Intersect(boundbox, adjustrect); if (intersection.Width != 0 || intersection.Height != 0) { blockEntities.Add(new Collision(hitbox, targetBox, coll)); if (hitbox.PushAway && pushAway) { float vx, vy; MovementComponent mov = entity.GetComponent <MovementComponent>(); vx = MovementSrc.VelocityX; vy = MovementSrc.VelocityY; if (mov != null) { vx -= mov.VelocityX; vy -= mov.VelocityY; } PointF offset = hitbox.GetIntersectionOffset(rect, boundbox, vx, vy, false, false); if (offset.X != 0 || offset.Y != 0) { PositionSrc.Offset(offset.X, offset.Y); boundbox.Offset(offset.X, offset.Y); } } } } } return(boundbox); }
private void CheckEnvironmentTile(List <MapSquare> hitSquares, CollisionBox hitbox, Rectangle hitRect, MapSquare tile, ref Point offset, bool pushAway) { if (hitbox.EnvironmentCollisions(PositionSrc.Position, tile, ref offset)) { hitSquares.Add(tile); if (hitbox.PushAway && pushAway) { PositionSrc.Offset(offset.X, offset.Y); } } else if (hitRect.IntersectsWith(tile.BoundBox)) { hitSquares.Add(tile); } }
private void ReactToTileEffect(TileProperties properties) { if (MovementSrc != null) { MovementSrc.PushX(properties.PushX); MovementSrc.PushY(properties.PushY); MovementSrc.ResistX(properties.ResistX); MovementSrc.ResistY(properties.ResistY); MovementSrc.DragX(properties.DragX); MovementSrc.DragY(properties.DragY); if (properties.Sinking > 0) { if (Parent.Container.IsGravityFlipped) { if (MovementSrc.VelocityY <= 0) { BlockTop = true; PositionSrc.Offset(0, -1 * properties.Sinking); // don't let gravity accumulate like in MM1 MovementSrc.VelocityY = 0; } } else { if (MovementSrc.VelocityY >= 0) { BlockBottom = true; PositionSrc.Offset(0, properties.Sinking); MovementSrc.VelocityY = 0; } } } } // don't just kill, it needs to be conditional on invincibility if (properties.Lethal && Parent.Name == "Player") { Parent.SendMessage(new DamageMessage(null, float.PositiveInfinity)); } }
protected override void Update() { hitSquares = hitSquares_RealTime = null; DamageDealt = 0; BlockTop = BlockRight = BlockLeft = BlockBottom = false; blockBottomMin = blockLeftMin = blockRightMin = blockTopMin = float.PositiveInfinity; blockBottomMax = blockTopMax = blockLeftMax = blockRightMax = float.NegativeInfinity; if (PositionSrc == null) { return; } if (!Enabled) { return; } // first run through, resolve intersections only hitSquares = new List <MapSquare>(); foreach (CollisionBox hitbox in hitboxes) { if (!enabledBoxes.Contains(hitbox.ID)) { continue; } hitbox.SetParent(this); if (hitbox.Environment) // check collision with environment { CheckEnvironment(hitSquares, hitbox); } Rectangle boundbox = hitbox.BoxAt(PositionSrc.Position); hitBlockEntities = new List <Collision>(); // now check with entity blocks if (MovementSrc != null) { boundbox = CheckEntityCollisions(hitBlockEntities, hitbox, boundbox); } } // this stores the types of tile we're touching HashSet <TileProperties> hitTypes = new HashSet <TileProperties>(); // first, as an aside, if i'm still touching a blocking entity, i need to react to that foreach (Collision collision in hitBlockEntities) { Rectangle boundBox = collision.myBox.BoxAt(PositionSrc.Position); Rectangle rect = collision.targetBox.BoxAt(collision.targetColl.PositionSrc.Position); if (BlockByIntersection(boundBox, rect, false, false)) { collision.targetColl.Touch(collision.myBox, collision.targetBox); Touch(collision.targetBox, collision.myBox); // for now, entities can only be normal type hitTypes.Add(collision.targetBox.Properties); // now cause friction on the x, a la moving platforms if (collision.targetColl.MovementSrc != null && collision.myBox.PushAway) { PositionSrc.Offset(collision.targetColl.MovementSrc.VelocityX, 0); } } } // now determine who i'm still touching, the resulting effects // notice - there's really no one to speak on behalf of the environment, // so we need to inflict the effects upon ourself foreach (CollisionBox hitbox in hitboxes) { if (!enabledBoxes.Contains(hitbox.ID)) { continue; } ReactForHitbox(hitSquares, hitTypes, hitbox); } if (MovementSrc != null) { if (BlockTop && MovementSrc.VelocityY < 0) { MovementSrc.VelocityY = 0; } if (BlockBottom && MovementSrc.VelocityY > 0) { MovementSrc.VelocityY = 0; } } // react to tile effects foreach (TileProperties tileprops in hitTypes) { ReactToTileEffect(tileprops); } }