private static void HandleCollision( Ecs.Registry registry, Queue <Entity> toRemove, Entity entity, Comps.Solid solidComp, Comps.Position positionComp, Comps.Shapes.Rectangle rectangleComp, PhysicalVector2 tilePosition, Rectangle tileRectangle ) { if (solidComp.ephemeral) { toRemove.Enqueue(entity); } else { PhysicalVector2 correction = GetMinCorrection( rectangleComp.data, positionComp.data, tileRectangle, tilePosition ); positionComp.data += correction; } }
public static void Run(Ecs.Registry registry) { // To avoid performance costs from doing list intersections, only // query for entities with `Solid` components. // // However, we can assume that all entities with a `Solid` component // also have these components: // - `Position` // - `Shape.Rectangle` List <Entity> entities1 = registry.GetEntitiesList(typeof(Comps.Solid)); // Use a `HashSet` to make removing entities O(1) var entities2 = new HashSet <Entity>(entities1); // Queue entities to remove so we aren't removing entities while // iterating over them Queue <Entity> toRemove = new Queue <Entity>(); foreach (Ecs.Entity entity1 in entities1) { var entity1Pos = registry.GetComponentUnsafe <Comps.Position>(entity1); foreach (Ecs.Entity entity2 in entities2) { var entity2Pos = registry.GetComponentUnsafe <Comps.Position>(entity2); if (!IsCollisionPossible(entity1Pos.data, entity2Pos.data) || entity1.Equals(entity2) ) { continue; } var entity1Rect = registry.GetComponentUnsafe <Comps.Shapes.Rectangle>(entity1); var entity2Rect = registry.GetComponentUnsafe <Comps.Shapes.Rectangle>(entity2); if (!entity1.Equals(entity2) && CheckCollision( entity1Rect.data, entity1Pos.data, entity2Rect.data, entity2Pos.data ) ) { var entity1Solid = registry.GetComponentUnsafe <Comps.Solid>(entity1); var entity2Solid = registry.GetComponentUnsafe <Comps.Solid>(entity2); HandleCollision( registry, toRemove, entity1, entity1Solid, entity1Pos, entity1Rect, entity2, entity2Solid, entity2Pos, entity2Rect ); } } entities2.Remove(entity1); } ProcessRemoves(toRemove, registry); }
public static void Run( Ecs.Registry registry, IMap map ) { // To avoid performance costs from doing list intersections, only // query for entities with `Solid` components. // // However, we can assume that all entities with a `Solid` component // also have these components: // - `Position` // - `Shape.Rectangle` List <Entity> entities = registry.GetEntitiesList(typeof(Comps.Solid)); // Queue entities to remove so we aren't removing entities while // iterating over them Queue <Entity> toRemove = new Queue <Entity>(); foreach (Ecs.Entity entity in entities) { var entityRect = registry.GetComponentUnsafe <Comps.Shapes.Rectangle>(entity); var entityPos = registry.GetComponentUnsafe <Comps.Position>(entity); var entityPosRect = new PosRectangle(entityPos.data, entityRect.data); // Check every tile that the rectangle is touching. foreach (int index in OverlappingTiles(map, entityPosRect)) { var gameTile = (GameTile)map.GameLayer.tiles[index]; switch (gameTile.kind) { case GameTile.Kind.Solid: var tilePos = GetTilePosition(map, index); var tileRect = new Rectangle( map.TileWidth, map.TileHeight ); if (CheckCollision( entityRect.data, entityPos.data, tileRect, tilePos )) { var entitySolid = registry.GetComponentUnsafe <Comps.Solid>(entity); HandleCollision( registry, toRemove, entity, entitySolid, entityPos, entityRect, tilePos, tileRect ); } break; } } } ProcessRemoves(toRemove, registry); }
public static void Run(Ecs.Registry registry) { // To avoid performance costs from doing list intersections, only // query for entities with `Projectile` and `Door` components. // // However, we can assume that these entities also have these // components: // - `Position` // - `Shape.Rectangle` List <Entity> projectileEntities = registry.GetEntitiesList(typeof(Comps.Projectile)); List <Entity> doorEntities = registry.GetEntitiesList(typeof(Comps.Door)); // Queue entities to remove so we aren't removing entities while // iterating over them Queue <Entity> toRemove = new Queue <Entity>(); foreach (Ecs.Entity projectileEntity in projectileEntities) { var projectilePosition = registry.GetComponentUnsafe <Comps.Position>(projectileEntity); foreach (Ecs.Entity doorEntity in doorEntities) { var doorPosition = registry.GetComponentUnsafe <Comps.Position>(doorEntity); if (!IsCollisionPossible(projectilePosition.data, doorPosition.data) || projectileEntity.Equals(doorEntity) ) { continue; } var projectileRectangle = registry.GetComponentUnsafe <Comps.Shapes.Rectangle>(projectileEntity); var projectile = registry.GetComponentUnsafe <Comps.Projectile>(projectileEntity); var doorRectangle = registry.GetComponentUnsafe <Comps.Shapes.Rectangle>(doorEntity); var door = registry.GetComponentUnsafe <Comps.Door>(doorEntity); if (CanUnlock(projectile.kind, door.kind) && CheckCollision( doorRectangle.data, doorPosition.data, projectileRectangle.data, projectilePosition.data ) ) { toRemove.Enqueue(doorEntity); Console.WriteLine( "The {0} door has been opened", door.kind ); } } } ProcessRemoves(toRemove, registry); }
public static void ProcessRemoves( Queue <Entity> toRemove, Ecs.Registry registry ) { while (toRemove.Count > 0) { Entity entity = toRemove.Dequeue(); registry.Remove(entity); } }
private static void HandleCollision( Ecs.Registry registry, Queue <Entity> toRemove, Entity entity1, Comps.Solid entity1Solid, Comps.Position entity1Pos, Comps.Shapes.Rectangle entity1Rect, Entity entity2, Comps.Solid entity2Solid, Comps.Position entity2Pos, Comps.Shapes.Rectangle entity2Rect ) { if (entity1Solid.ephemeral) { toRemove.Enqueue(entity1); return; } if (entity2Solid.ephemeral) { toRemove.Enqueue(entity2); return; } Vector2 correction = GetMinCorrection( entity1Rect.data, entity1Pos.data, entity2Rect.data, entity2Pos.data ); // Ignore the case where both are unmovable if (entity1Solid.unmovable) { entity2Pos.data -= correction; } else if (entity2Solid.unmovable) { entity1Pos.data += correction; } else { entity1Pos.data += correction / 2f; entity2Pos.data -= correction / 2f; } }
public static void Run(Ecs.Registry registry) { // To avoid performance costs from doing list intersections, only // query for entities with `Damaging` and `Inventory` components. // // However, we can assume that these entities also have these // components: // - `Position` // - `Shape.Rectangle` List <Entity> hitEntities = registry.GetEntitiesList(typeof(Comps.Damaging)); List <Entity> hurtEntities = registry.GetEntitiesList(typeof(Comps.Inventory)); foreach (Ecs.Entity hitEntity in hitEntities) { var hitPosition = registry.GetComponentUnsafe <Comps.Position>(hitEntity); foreach (Ecs.Entity hurtEntity in hurtEntities) { var hurtPosition = registry.GetComponentUnsafe <Comps.Position>(hurtEntity); if (!IsCollisionPossible(hitPosition.data, hurtPosition.data) || hitEntity.Equals(hurtEntity) ) { continue; } var hitRectangle = registry.GetComponentUnsafe <Comps.Shapes.Rectangle>(hitEntity); var hitDamage = registry.GetComponentUnsafe <Comps.Damaging>(hitEntity); var hurtRectangle = registry.GetComponentUnsafe <Comps.Shapes.Rectangle>(hurtEntity); // Only check for collision if the entity isn't being hit by // its own attack (unless it has self damage on). bool canDamage = (hurtEntity.id != hitDamage.attackerId || hitDamage.selfDamage); if (canDamage && CheckCollision( hurtRectangle.data, hurtPosition.data, hitRectangle.data, hitPosition.data ) ) { var hurtInventory = registry.GetComponentUnsafe <Comps.Inventory>(hurtEntity); bool isInvulnerable = true; // TODO if (isInvulnerable) { // Deal damage hurtInventory.data[Comps.Item.Kind.Heart].Count--; // TODO: give invulnerability ticks registry.AssignComponent( hurtEntity, new Comps.Damaged { damage = hitDamage.damage, damagerId = hitEntity.id } ); Console.WriteLine( "Entity {0} now at {1} HP (damaged by Entity {2})", hurtEntity.id, hurtInventory.data[Comps.Item.Kind.Heart].Count, hitDamage.attackerId ); } } } } }