public Collision(CollisionBox mybox, CollisionBox target, CollisionComponent tgtComp) { myBox = mybox; targetBox = target; targetColl = tgtComp; }
/// <summary> /// Get the hitboxes that the calling box can target /// </summary> private IEnumerable<CollisionBox> TargetBoxes(CollisionBox hitbox) { if (!cacheTargetBoxes.ContainsKey(hitbox.ID)) { cacheTargetBoxes[hitbox.ID] = new List<CollisionBox>(hitboxes .Where(box => box.Groups.Intersect(hitbox.Hits).Any())); } foreach (CollisionBox box in cacheTargetBoxes[hitbox.ID]) { box.SetParent(this); } return cacheTargetBoxes[hitbox.ID].Where(box => enabledBoxes.Contains(box.ID)); }
private void Touch(CollisionBox targetbox, CollisionBox mybox) { foreach (var group in targetbox.Groups) { touchedBy.Add(group); foreach (var mygroup in mybox.Groups) { if (!touchedAt.ContainsKey(mygroup)) { touchedAt[mygroup] = new HashSet<string>(); } touchedAt[mygroup].Add(group); } } }
private void CollideWith(IEntity entity, CollisionBox myBox, CollisionBox targetBox) { float mult = targetBox.DamageMultiplier(Parent.Name); float damage = myBox.ContactDamage * mult; IGameMessage dmgmsg; if (damage > 0) dmgmsg = new DamageMessage(Parent, damage); else dmgmsg = new HealMessage(Parent, damage * -1); float prevhealth = damage; HealthComponent comp = entity.GetComponent<HealthComponent>(); if (comp != null) prevhealth = comp.Health; entity.SendMessage(dmgmsg); DamageDealt = Math.Min(damage, prevhealth); }
private void ReactForHitbox(List<MapSquare> hitSquares, HashSet<TileProperties> hitTypes, CollisionBox hitbox) { hitbox.SetParent(this); RectangleF boundBox = hitbox.BoxAt(PositionSrc.Position); if (hitbox.Environment) { foreach (MapSquare tile in hitSquares) { RectangleF tileBox = tile.BlockBox; bool downonly = (!Parent.Container.IsGravityFlipped && tile.Tile.Properties.Climbable); bool uponly = (Parent.Container.IsGravityFlipped && tile.Tile.Properties.Climbable); bool hit = (tile.BlockBox != RectangleF.Empty) ? BlockByIntersection(boundBox, tileBox, uponly, downonly) : boundBox.IntersectsWith(tile.BoundBox); if (hitbox.PushAway && (hit || boundBox.IntersectsWith(tile.BoundBox))) // the environment touched me! { hitTypes.Add(tile.Tile.Properties); } } } // but for entities, we can go ahead and be active aggressors - // inflict our effects on the target entity, not the other way around foreach (var entity in Parent.Entities.GetAll()) { if (entity == Parent) continue; CollisionComponent coll = entity.GetComponent<CollisionComponent>(); if (coll == null) continue; foreach (CollisionBox targetBox in coll.TargetBoxes(hitbox)) { boundBox = CheckTargetBox(hitbox, boundBox, entity, coll, targetBox); } } }
private void CheckEnvironmentTile(List<MapSquare> hitSquares, CollisionBox hitbox, RectangleF hitRect, MapSquare tile, ref PointF offset) { if (hitbox.EnvironmentCollisions(PositionSrc.Position, tile, ref offset)) { hitSquares.Add(tile); if (hitbox.PushAway) PositionSrc.Offset(offset.X, offset.Y); } else if (hitRect.IntersectsWith(tile.BoundBox)) { hitSquares.Add(tile); } }
/// <summary> /// See return value. Fills hitBlockEntities with all/solid (see param solidOnly) entities hit /// </summary> /// <param name="box">Box for which to check collisions</param> /// <param name="property">Property to check for</param> /// <param name="solidOnly">Only checks for solid entities</param> /// <param name="pushAway">Solve collisions</param> /// <returns>True if an entity solid/not (see param solidOnly) is hit</returns> private bool CollisionWithAllEntities_RealTime(CollisionBox box, string property, bool solidOnly = true, bool pushAway = false) { box.SetParent(this); RectangleF boundbox = box.BoxAt(PositionSrc.Position); //calculate boundbox absolute coordinate hitBlockEntities_RealTime = new List<Collision>(); boundbox = CheckEntityCollisions(hitBlockEntities_RealTime, box, boundbox, pushAway, solidOnly); return CheckIfOneEntityHitContainProperty_RealTime(property); }
private RectangleF CheckEntityCollisions(List<Collision> blockEntities, CollisionBox hitbox, RectangleF boundbox) { foreach (var entity in Parent.Entities.GetAll()) { if (entity == Parent) continue; CollisionComponent coll = entity.GetComponent<CollisionComponent>(); if (coll == null) continue; foreach (CollisionBox targetBox in coll.HitByBoxes(hitbox).Where(box => box.Properties.Blocking)) { // 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) { 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 CheckEnvironment(List<MapSquare> hitSquares, CollisionBox hitbox) { PointF offset = new PointF(0, 0); RectangleF hitRect = hitbox.BoxAt(PositionSrc.Position); // this bounds checking prevents needlessly checking collisions way too far away // it's a very effective optimization (brings busy time from ~60% down to 45%!) int size = Parent.Screen.TileSize; for (float y = hitRect.Top - size; y < hitRect.Bottom; y += size) { for (float x = hitRect.Left - size; x < hitRect.Right; x += size) { var tile = Parent.Screen.SquareAt(x, y); if (tile == null) continue; CheckEnvironmentTile(hitSquares, hitbox, hitRect, tile, ref offset); } var rightEdge = Parent.Screen.SquareAt(hitRect.Right, y); if (rightEdge != null) { CheckEnvironmentTile(hitSquares, hitbox, hitRect, rightEdge, ref offset); } } for (float x = hitRect.Left - size; x < hitRect.Right; x += size) { var tile = Parent.Screen.SquareAt(x, hitRect.Bottom); if (tile == null) continue; CheckEnvironmentTile(hitSquares, hitbox, hitRect, tile, ref offset); } var lastCorner = Parent.Screen.SquareAt(hitRect.Right, hitRect.Bottom); if (lastCorner != null) { CheckEnvironmentTile(hitSquares, hitbox, hitRect, lastCorner, ref offset); } }
public override void LoadXml(XElement xml) { foreach (XElement boxnode in xml.Elements("Hitbox")) { CollisionBox box = new CollisionBox(boxnode); box.SetParent(this); AddBox(box); } Enabled = xml.TryAttribute<bool>("Enabled"); }
public void AddBox(CollisionBox box) { hitboxes.Add(box); if (box.Name != null) boxIDsByName.Add(box.Name, box.ID); }
/// <summary> /// See return value. Fills hitSquaresForFunctionThatChecksCollisions with blocks hit /// </summary> /// <param name="box">Box for which to check collisions</param> /// <param name="property">Property to check for</param> /// <param name="pushAway">Solve collisions</param> /// <returns>True if a solid block is hit</returns> private bool CollisionWithTiles_RealTime(CollisionBox box, string property, bool pushAway = false) { hitSquares_RealTime = new List<MapSquare>(); // hitSquares: those touching box.SetParent(this); CheckEnvironment(hitSquares_RealTime, box, pushAway); return CheckIfOneTileHitContainProperty_RealTime(property); }
private void ReactForHitbox(List <MapSquare> hitSquares, HashSet <TileProperties> hitTypes, CollisionBox hitbox) { hitbox.SetParent(this); var boundBox = hitbox.BoxAt(PositionSrc.Position); if (hitbox.Environment) { foreach (MapSquare tile in hitSquares) { var tileBox = tile.BlockBox; bool downonly = (!Parent.Container.IsGravityFlipped && tile.Tile.Properties.Climbable); bool uponly = (Parent.Container.IsGravityFlipped && tile.Tile.Properties.Climbable); bool hit = (tile.BlockBox != Rectangle.Empty) ? BlockByIntersection(boundBox, tileBox, uponly, downonly) : boundBox.IntersectsWith(tile.BoundBox); if (hitbox.PushAway && (hit || boundBox.IntersectsWith(tile.BoundBox))) // the environment touched me! { hitTypes.Add(tile.Tile.Properties); } } } // but for entities, we can go ahead and be active aggressors - // inflict our effects on the target entity, not the other way around foreach (var entity in Parent.Entities.GetAll()) { if (entity == Parent) { continue; } CollisionComponent coll = entity.GetComponent <CollisionComponent>(); if (coll == null) { continue; } foreach (CollisionBox targetBox in coll.TargetBoxes(hitbox)) { boundBox = CheckTargetBox(hitbox, boundBox, entity, coll, targetBox); } } }
private RectangleF CheckTargetBox(CollisionBox hitbox, RectangleF boundBox, IEntity entity, CollisionComponent coll, CollisionBox targetBox) { RectangleF rect = targetBox.BoxAt(coll.PositionSrc.Position); if (boundBox.IntersectsWith(rect)) { coll.Touch(hitbox, targetBox); Touch(targetBox, hitbox); CollideWith(entity, hitbox, targetBox); } return boundBox; }
private Rectangle CheckTargetBox(CollisionBox hitbox, Rectangle boundBox, IEntity entity, CollisionComponent coll, CollisionBox targetBox) { var rect = targetBox.BoxAt(coll.PositionSrc.Position); if (boundBox.IntersectsWith(rect)) { coll.Touch(hitbox, targetBox); Touch(targetBox, hitbox); CollideWith(entity, hitbox, targetBox); } return(boundBox); }
internal void Loadinfo(CollisionComponentInfo info) { Enabled = info.Enabled; foreach (var box in info.HitBoxes) { var coll = new CollisionBox(box); coll.SetParent(this); AddBox(coll); } }