private static bool ShouldMob(Entity self, EntityBeliefs ent) { var trace = new TraceLine(self.World); trace.Origin = ent.LastPos; trace.HitGeometry = true; trace.HitEntities = false; trace.HullSize = self.GetComponent<Collision>().Size; int survivors = 1; int zombies = 1; var it = new NearbyEntityEnumerator(self.World, ent.LastPos, MobRadius); while (it.MoveNext()) { var cur = it.Current; if (cur == self || cur == ent.Entity) continue; if (!cur.HasComponent<Human>() || !cur.HasComponent<Health>()) continue; if (!cur.GetComponent<Health>().IsAlive) continue; trace.Target = cur.Position2D; if (trace.GetResult().Hit) continue; if (cur.HasComponent<Survivor>()) { survivors += cur.GetComponent<Health>().Value; } else { zombies += cur.GetComponent<Health>().Value; } } return zombies <= MaxMobRatio * survivors; }
public override IEnumerable<Action> GetActions() { yield return new DropItemAction(3f); var diff = Entity.World.Difference(Entity.Position2D, Target.LastPos); var trace = new TraceLine(World); trace.Origin = Target.LastPos; trace.HitGeometry = true; trace.HitEntities = false; trace.HullSize = Entity.GetComponent<Collision>().Size; bool closest = true; var it = new NearbyEntityEnumerator(World, Target.LastPos, diff.Length); while (it.MoveNext()) { var cur = it.Current; if (cur == Entity || !cur.HasComponent<Human>() || !cur.GetComponent<Health>().IsAlive) continue; trace.Target = cur.Position2D; if (trace.GetResult().Hit) continue; closest = false; break; } if (!closest) { yield return new MovementAction(diff.Normalized() * 128f); } if (diff.LengthSquared < 1.5f) { yield return new AttackAction(Target.Entity); } }
private Entity EntityTrace(ref Vector2 vec) { NearbyEntityEnumerator it = new NearbyEntityEnumerator( World, Origin + vec / 2.0f, vec.Length / 2.0f + 2.0f); float ratio = 1.0f; float dydx = vec.Y / vec.X; float dxdy = vec.X / vec.Y; Entity hitEnt = null; while (it.MoveNext()) { Entity ent = it.Current; if (ent.HasComponent<Collision>()) { Collision col = ent.GetComponent<Collision>(); if (col.Model != CollisionModel.None && (HitEntityPredicate == null || HitEntityPredicate(ent))) { Vector2 diff = World.Difference(Origin, ent.Position2D); float lt = diff.X + col.Offset.X; float rt = lt + col.Size.X; float tp = diff.Y + col.Offset.Y; float bt = tp + col.Size.Y; if (lt < 0f && rt > 0f && tp < 0f && bt > 0f) { hitEnt = ent; ratio = 0f; break; } if (vec.X != 0.0f) { float dx = 0.0f; bool hit = false; if (vec.X > 0.0f && lt >= 0.0f && vec.X * ratio > lt) { dx = lt; hit = true; } else if (vec.X < 0.0f && rt <= 0.0f && vec.X * ratio < rt) { dx = rt; hit = true; } if (hit) { float y = dydx * dx; if (y > tp && y < bt) { ratio = dx / vec.X; hitEnt = ent; } } } if (vec.Y != 0.0f) { float dy = 0.0f; bool hit = false; if (vec.Y > 0.0f && tp >= 0.0f && vec.Y * ratio > tp) { dy = tp; hit = true; } else if (vec.Y < 0.0f && bt <= 0.0f && vec.Y * ratio < bt) { dy = bt; hit = true; } if (hit) { float x = dxdy * dy; if (x > lt && x < rt) { ratio = dy / vec.Y; hitEnt = ent; } } } } } } if (hitEnt != null) vec *= ratio; return hitEnt; }
public Vector2 TryMove(Vector2 move) { if (Model == CollisionModel.None) return Position2D + move; if (Model.HasFlag(CollisionModel.Entity)) { NearbyEntityEnumerator iter = new NearbyEntityEnumerator(Entity.World, new Vector2(Position2D.X, Position2D.Y), 2.0f + move.Length); while (iter.MoveNext()) move = TryMove(iter.Current, move); } float xm = Position2D.X + move.X, ym = Position2D.Y + move.Y; float error = 1.0f / 32.0f; if (move.X != 0.0f) { float dydx = move.Y / move.X; float startX = move.X > 0.0f ? Right : Left; int startIX = (int) (move.X > 0.0f ? Math.Ceiling(startX) : Math.Floor(startX)); float y = Position.Z + (startIX - startX) * dydx; int xa = Math.Sign(move.X); int wxa = (move.X > 0.0f ? -1 : 0); int sxa = (move.X > 0.0f ? 0 : -1); int xe = (int) (move.X > 0.0f ? Math.Ceiling(startX + move.X) : Math.Floor(startX + move.X)); Face face = move.X > 0.0f ? Face.East : Face.West; Block blk = null; for (int ix = startIX; ix != xe; ix += xa, y += xa * dydx) { int wx = (ix + wxa) - (int) Math.Floor((double) (ix + wxa) / World.Width) * World.Width; int sx = (ix + sxa) - (int) Math.Floor((double) (ix + sxa) / World.Width) * World.Width; int minY = (int) Math.Floor(y + Offset.Y + error); int maxY = (int) Math.Floor(y + Offset.Y + Size.Y - error); for (int iy = minY; iy <= maxY; ++iy) { int wy = iy - (int) Math.Floor((double) iy / World.Height) * World.Height; if (blk == null || wx < blk.X || wy < blk.Y || wx >= blk.X + blk.Width || wy >= blk.Y + blk.Height) blk = World.GetBlock(wx, wy); bool hit = false; Tile tw = blk[wx, wy]; hit = tw.IsWallSolid(face); if (!hit) { if (sx < blk.X || wy < blk.Y || sx >= blk.X + blk.Width || wy >= blk.Y + blk.Height) blk = World.GetBlock(sx, wy); Tile ts = blk[sx, wy]; hit = (iy > minY && ts.IsWallSolid(Face.North) && !tw.IsWallSolid(Face.North)) || (iy < maxY && ts.IsWallSolid(Face.South) && !tw.IsWallSolid(Face.South)); } if (hit) { xm = move.X > 0 ? ix - Offset.X - Size.X : ix - Offset.X; ix = xe - xa; break; } } } } if (move.Y != 0.0f) { float dxdy = move.X / move.Y; float startY = move.Y > 0.0f ? Bottom : Top; int startIY = (int) (move.Y > 0.0f ? Math.Ceiling(startY) : Math.Floor(startY)); float x = Position.X + (startIY - startY) * dxdy; int ya = Math.Sign(move.Y); int wya = (move.Y > 0.0f ? -1 : 0); int sya = (move.Y > 0.0f ? 0 : -1); int ye = (int) (move.Y > 0.0f ? Math.Ceiling(startY + move.Y) : Math.Floor(startY + move.Y)); Face face = move.Y > 0.0f ? Face.South : Face.North; Block blk = null; for (int iy = startIY; iy != ye; iy += ya, x += ya * dxdy) { int wy = (iy + wya) - (int) Math.Floor((double) (iy + wya) / World.Height) * World.Height; int sy = (iy + sya) - (int) Math.Floor((double) (iy + sya) / World.Height) * World.Height; int minX = (int) Math.Floor(x + Offset.X + error); int maxX = (int) Math.Floor(x + Offset.X + Size.X - error); for (int ix = minX; ix <= maxX; ++ix) { int wx = ix - (int) Math.Floor((double) ix / World.Width) * World.Width; if (blk == null || wx < blk.X || wy < blk.Y || wx >= blk.X + blk.Width || wy >= blk.Y + blk.Height) blk = World.GetBlock(wx, wy); bool hit = false; Tile tw = blk[wx, wy]; hit = tw.IsWallSolid(face); if (!hit) { if (wx < blk.X || sy < blk.Y || wx >= blk.X + blk.Width || sy >= blk.Y + blk.Height) blk = World.GetBlock(wx, sy); Tile ts = blk[wx, sy]; hit = (ix > minX && ts.IsWallSolid(Face.West) && !tw.IsWallSolid(Face.West)) || (ix < maxX && ts.IsWallSolid(Face.East) && !tw.IsWallSolid(Face.East)); } if (hit) { ym = move.Y > 0 ? iy - Offset.Y - Size.Y : iy - Offset.Y; iy = ye - ya; break; } } } } return new Vector2(xm, ym); }
public void Repel(Movement movement, double dt) { NearbyEntityEnumerator iter = new NearbyEntityEnumerator(Entity.World, new Vector2(Position2D.X, Position2D.Y), 2.0f); while (iter.MoveNext()) { var obstacle = iter.Current; if (obstacle == Entity || !obstacle.HasComponent<Collision>()) continue; var that = obstacle.GetComponent<Collision>(); if (!that.Model.HasFlag(CollisionModel.Entity | CollisionModel.Repel)) continue; Vector2 diff = World.Difference(Position2D, that.Position2D); float ar = (float) Math.Sqrt(this.Size.X * this.Size.X * 0.25 + this.Size.Y * this.Size.Y * 0.25); float br = (float) Math.Sqrt(that.Size.X * that.Size.X * 0.25 + that.Size.Y * that.Size.Y * 0.25); if (ar + br < diff.Length) continue; float mag = Math.Min(1f, (float) ((ar + br) * dt) / diff.LengthSquared); movement.Velocity -= diff.Normalized() * mag; } }