public void draw(SpriteBatch spriteBatch) { if (chainLinks != null) { foreach (Body chainLink in chainLinks) { foreach (Fixture f in chainLink.FixtureList) { PolygonShape ps = (PolygonShape)f.Shape; Vector2 Edge1; Vector2 Edge2; Vector2 Edge3; Vector2 Edge4; FarseerPhysics.Collision.AABB aabb = ps.Vertices.GetCollisionBox(); Edge1 = new Vector2(aabb.LowerBound.X, aabb.LowerBound.Y); Edge2 = new Vector2(aabb.UpperBound.X, aabb.LowerBound.Y); Edge3 = new Vector2(aabb.UpperBound.X, aabb.UpperBound.Y); Edge4 = new Vector2(aabb.LowerBound.X, aabb.UpperBound.Y); Rectangle destRect = new Rectangle((int)(chainLink.Position.X * Level.PixelPerMeter), (int)(chainLink.Position.Y * Level.PixelPerMeter), (int)(Edge3.X * Level.PixelPerMeter) - (int)(Edge1.X * Level.PixelPerMeter), (int)(Edge3.Y * Level.PixelPerMeter) - (int)(Edge1.Y * Level.PixelPerMeter)); spriteBatch.Draw(ropeText, destRect, null, Color.White, chainLink.Rotation, Vector2.Zero, SpriteEffects.None, 1.0f); } } } }
/// <summary> /// Draws the specified rectangle by the specified color. /// </summary> /// <param name="rectangle">The rectangle to draw.</param> /// <param name="color">The color of the rectangle.</param> /// <param name="z">The z coordinate of the rectangle.</param> public void Draw(FarseerPhysics.Collision.AABB rectangle, Color color, float z) { while (5 > lineVertices.Length) { ExtendBuffer(); } if (lineVerticesCount >= 2) { DrawLines(); } lineVertices[0].Position = new Vector3(rectangle.LowerBound, z); lineVertices[1].Position = new Vector3(rectangle.UpperBound.X, rectangle.LowerBound.Y, z); lineVertices[2].Position = new Vector3(rectangle.UpperBound, z); lineVertices[3].Position = new Vector3(rectangle.LowerBound.X, rectangle.UpperBound.Y, z); lineVertices[4].Position = lineVertices[0].Position; lineVertices[0].Color = lineVertices[1].Color = lineVertices[2].Color = lineVertices[3].Color = lineVertices[4].Color = color; ApplyBasicEffect(); GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineStrip, lineVertices, 0, 4); lineVerticesCount = 0; }
/// <summary> /// Zooms and centers the scene to be able to see the whole scene at the <see cref="SceneScreen"/>, if possible. /// </summary> /// <remarks> /// Does not work for the actors at the parallax layer. /// </remarks> public void Fit() { if (Nodes.Count != 0) { bool starting = true; FarseerPhysics.Collision.AABB sceneRectangle = new FarseerPhysics.Collision.AABB(); foreach (SceneNode sceneNode in GetAllSceneNodes(true)) { if (starting) { sceneRectangle = sceneNode.Rectangle; starting = false; } else { FarseerPhysics.Collision.AABB tempSceneNodeRectangle = sceneNode.Rectangle; sceneRectangle.Combine(ref tempSceneNodeRectangle); } } // no visible scene node if (starting) { return; } float sceneRectangleWidth = sceneRectangle.UpperBound.X - sceneRectangle.LowerBound.X; float sceneRectangleHeight = sceneRectangle.UpperBound.Y - sceneRectangle.LowerBound.Y; float scaleWidth = Width / sceneRectangleWidth; float scaleHeight = Height / sceneRectangleHeight; float scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight; Zoom = scale * 100f; Vector2 position = sceneRectangle.LowerBound; if (Width > sceneRectangleWidth * scale) { position.X -= (Width - sceneRectangleWidth * scale) / 2f * ScaleInversFactor; } else { position.X -= (sceneRectangleWidth * scale - Width) / 2f * ScaleInversFactor; } if (Height > sceneRectangleHeight * scale) { position.Y -= (Height - sceneRectangleHeight * scale) / 2f * ScaleInversFactor; } else { position.Y -= (sceneRectangleHeight * scale - Height) / 2f * ScaleInversFactor; } Position = position; } }
/// <summary> /// Creates an explosion at an arbitary point in Simulation space /// </summary> /// <param name="setPosition">set explosion Position, must have an offset when using Body.Position, else Divide by zero error</param> /// <param name="setStrength">set the Strength of the Explosion</param> /// <returns></returns> public Explosion(Vector2 setPosition, float setStrength) { // Create Axis Aligned Bounding Box, use 1 as X, else a Vehicle near exploding towers will fly away! Vector2 min = setPosition - new Vector2(1, 10); Vector2 max = setPosition + new Vector2(1, 10); FarseerPhysics.Collision.AABB aabb = new FarseerPhysics.Collision.AABB(ref min, ref max); PhysicsGameScreen.World.QueryAABB(fixture => { Vector2 fv = fixture.Body.Position - setPosition; fv.Normalize(); fv *= setStrength; //200;//40; fixture.Body.ApplyLinearImpulse(ref fv); return(true); }, ref aabb); }
/// <summary> /// Finds all <see cref="SceneNode"/> at the specified rectangle defined by two points. /// </summary> /// <param name="firstPoint">The first point of the rectangle.</param> /// <param name="secondPoint">The second point of the retangle.</param> /// <returns>List of found scene nodes.</returns> public List <SceneNode> FindAt(Vector2 firstPoint, Vector2 secondPoint) { List <SceneNode> foundNodes = new List <SceneNode>(); Vector2 min = new Vector2(Math.Min(firstPoint.X, secondPoint.X), Math.Min(firstPoint.Y, secondPoint.Y)); Vector2 max = new Vector2(Math.Max(firstPoint.X, secondPoint.X), Math.Max(firstPoint.Y, secondPoint.Y)); FarseerPhysics.Collision.AABB rectangle = new FarseerPhysics.Collision.AABB(min, max); foreach (SceneNode node in GetAllSceneNodes()) { if (node.Visible && FarseerPhysics.Collision.AABB.TestOverlap(node.Rectangle, rectangle)) { foundNodes.Add(node); } } return(foundNodes); }
public static FixtureCoord[] GetFixtureCircleIntersections(World world, Vector2 point, float radius) { List<Fixture> potentials = new List<Fixture>(); var box = new FarseerPhysics.Collision.AABB(new Xna.Vector2(point.X, point.Y), radius * 2, radius * 2); world.QueryAABB(delegate (Fixture fixture) { potentials.Add(fixture); return false; }, ref box); List<FixtureCoord> collisions = new List<FixtureCoord>(); foreach (Fixture f in potentials) { Xna.Vector2 relativePoint = f.Body.GetLocalPoint(new Xna.Vector2(point.X, point.Y)); switch (f.Shape.ShapeType) { case ShapeType.Polygon: PolygonShape polygon = (PolygonShape)f.Shape; for (int i = 0; i < polygon.Vertices.Count; i++) { int iNext = (i + 1) % polygon.Vertices.Count; LineF edge = new LineF(polygon.Vertices[i], polygon.Vertices[iNext]); IntersectCoord[] intersects = MathExt.LineCircleIntersect(new Vector2(relativePoint.X, relativePoint.Y), radius, edge, true); for (int j = 0; i < intersects.Length; i++) { collisions.Add(new FixtureCoord(f, i, (float)intersects[j].TFirst)); } /*if (intersects.Length > 0) { fixtureCollisions.Add(f); break; }*/ } break; default: throw new NotImplementedException(); } } return collisions.ToArray(); }
/// <summary> /// Performs a global physical AABB query and returns the <see cref="RigidBody">bodies</see> that /// might be roughly contained or intersected by the specified region. /// </summary> /// <param name="worldCoord"></param> /// <param name="size"></param> /// <param name="queriedBodies"> /// A list that will be filled with all bodies that were found. /// The list will not be cleared before adding items. /// </param> /// <returns>Returns whether any new body was found.</returns> public bool QueryRect(Vector2 worldCoord, Vector2 size, List <RigidBody> queriedBodies) { Vector2 fsWorldCoord = PhysicsUnit.LengthToPhysical * worldCoord; FarseerPhysics.Collision.AABB fsWorldAABB = new FarseerPhysics.Collision.AABB(fsWorldCoord, PhysicsUnit.LengthToPhysical * (worldCoord + size)); int oldResultCount = queriedBodies.Count; this.native.QueryAABB(fixture => { ShapeInfo shape = fixture.UserData as ShapeInfo; if (shape != null && shape.Parent != null && shape.Parent.Active) { if (!queriedBodies.Contains(shape.Parent)) { queriedBodies.Add(shape.Parent); } } return(true); }, ref fsWorldAABB); return(queriedBodies.Count > oldResultCount); }
private List <HitscanResult> DoRayCast(Vector2 rayStart, Vector2 rayEnd) { List <HitscanResult> hits = new List <HitscanResult>(); Vector2 dir = rayEnd - rayStart; dir = dir.LengthSquared() < 0.00001f ? Vector2.UnitY : Vector2.Normalize(dir); //do an AABB query first to see if the start of the ray is inside a fixture var aabb = new FarseerPhysics.Collision.AABB(rayStart - Vector2.One * 0.001f, rayStart + Vector2.One * 0.001f); GameMain.World.QueryAABB((fixture) => { //ignore sensors and items if (fixture?.Body == null || fixture.IsSensor) { return(true); } if (fixture.UserData is Item) { return(true); } //ignore everything else than characters, sub walls and level walls if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) && !fixture.CollisionCategories.HasFlag(Physics.CollisionWall) && !fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) { return(true); } fixture.Body.GetTransform(out FarseerPhysics.Common.Transform transform); if (!fixture.Shape.TestPoint(ref transform, ref rayStart)) { return(true); } hits.Add(new HitscanResult(fixture, rayStart, -dir, 0.0f)); return(true); }, ref aabb); GameMain.World.RayCast((fixture, point, normal, fraction) => { //ignore sensors and items if (fixture?.Body == null || fixture.IsSensor) { return(-1); } if (fixture.UserData is Item) { return(-1); } //ignore everything else than characters, sub walls and level walls if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) && !fixture.CollisionCategories.HasFlag(Physics.CollisionWall) && !fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) { return(-1); } hits.Add(new HitscanResult(fixture, point, normal, fraction)); return(hits.Count < 25 ? 1 : 0); }, rayStart, rayEnd); return(hits); }
private List <HitscanResult> DoRayCast(Vector2 rayStart, Vector2 rayEnd, Submarine submarine) { List <HitscanResult> hits = new List <HitscanResult>(); Vector2 dir = rayEnd - rayStart; dir = dir.LengthSquared() < 0.00001f ? Vector2.UnitY : Vector2.Normalize(dir); //do an AABB query first to see if the start of the ray is inside a fixture var aabb = new FarseerPhysics.Collision.AABB(rayStart - Vector2.One * 0.001f, rayStart + Vector2.One * 0.001f); GameMain.World.QueryAABB((fixture) => { //ignore sensors and items if (fixture?.Body == null || fixture.IsSensor) { return(true); } if (fixture.Body.UserData is VineTile) { return(true); } if (fixture.Body.UserData is Item item && (item.GetComponent <Door>() == null && !item.Prefab.DamagedByProjectiles || item.Condition <= 0)) { return(true); } if (fixture.Body.UserData as string == "ruinroom") { return(true); } //if doing the raycast in a submarine's coordinate space, ignore anything that's not in that sub if (submarine != null) { if (fixture.Body.UserData is Entity entity && entity.Submarine != submarine) { return(true); } } //ignore everything else than characters, sub walls and level walls if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) && !fixture.CollisionCategories.HasFlag(Physics.CollisionWall) && !fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) { return(true); } if (fixture.Body.UserData is VoronoiCell && (this.item.Submarine != null || submarine != null)) { return(true); } fixture.Body.GetTransform(out FarseerPhysics.Common.Transform transform); if (!fixture.Shape.TestPoint(ref transform, ref rayStart)) { return(true); } hits.Add(new HitscanResult(fixture, rayStart, -dir, 0.0f)); return(true); }, ref aabb); GameMain.World.RayCast((fixture, point, normal, fraction) => { //ignore sensors and items if (fixture?.Body == null || fixture.IsSensor) { return(-1); } if (fixture.Body.UserData is VineTile) { return(-1); } if (fixture.Body.UserData is Item item && (item.GetComponent <Door>() == null && !item.Prefab.DamagedByProjectiles || item.Condition <= 0)) { return(-1); } if (fixture.Body?.UserData as string == "ruinroom") { return(-1); } //ignore everything else than characters, sub walls and level walls if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) && !fixture.CollisionCategories.HasFlag(Physics.CollisionWall) && !fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) { return(-1); } //if doing the raycast in a submarine's coordinate space, ignore anything that's not in that sub if (submarine != null) { if (fixture.Body.UserData is Entity entity && entity.Submarine != submarine) { return(-1); } } //ignore level cells if the item and the point of impact are inside a sub if (fixture.Body.UserData is VoronoiCell && this.item.Submarine != null) { if (Hull.FindHull(ConvertUnits.ToDisplayUnits(point), this.item.CurrentHull) != null) { return(-1); } } hits.Add(new HitscanResult(fixture, point, normal, fraction)); return(hits.Count < 25 ? 1 : 0); }, rayStart, rayEnd, Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionLevel); return(hits); }
private void UpdateMouse(MouseState mouse) { if (mouse.RightButton == ButtonState.Pressed && player.creature.target as Ward != null && player.wards.Contains((Ward)player.creature.target)) { ((Ward)player.creature.target).MoveToCursor(player); } if (mouse.LeftButton == ButtonState.Pressed && previousMouseState.LeftButton == ButtonState.Released) { List<Body> bodyList = world.BodyList; List<Creature> filteredCreatureList = new List<Creature>(); foreach(Body body in bodyList) { if(body.UserData as Creature != null) { Creature creature = (Creature)body.UserData; if (LocationAnalysis.IsLit(world, creature.GamePosition, player.krypton) && creature.targetable && !filteredCreatureList.Contains(creature)) { float mouseBoxHeight = ConvertUnits.ToSimUnits(100); float mouseBoxWidth = ConvertUnits.ToSimUnits(100); FarseerPhysics.Collision.AABB mouseAABB = new FarseerPhysics.Collision.AABB(LocationAnalysis.GetMouseGamePosition(player.game, player.cam), mouseBoxHeight, mouseBoxWidth); FarseerPhysics.Collision.AABB bodyAABB = new FarseerPhysics.Collision.AABB(creature.GamePosition, ConvertUnits.ToSimUnits(creature.Center.X), ConvertUnits.ToSimUnits(creature.Center.Y)); if ( FarseerPhysics.Collision.AABB.TestOverlap(bodyAABB, mouseAABB)) filteredCreatureList.Add(creature); } } } if(filteredCreatureList.Count != 0) player.creature.target = filteredCreatureList[(int)(new Random().NextDouble() * filteredCreatureList.Count)]; } previousMouseState = mouse; }
/// <summary> /// Performs a physical picking operation and returns the <see cref="ShapeInfo">shapes</see> that /// intersect the specified world coordinate area. /// </summary> /// <param name="worldCoord"></param> /// <param name="size"></param> /// <returns></returns> public List<ShapeInfo> PickShapes(Vector2 worldCoord, Vector2 size) { if (this.body == null) return new List<ShapeInfo>(); Vector2 fsWorldCoord = PhysicsUnit.LengthToPhysical * worldCoord; FarseerPhysics.Collision.AABB fsWorldAABB = new FarseerPhysics.Collision.AABB(fsWorldCoord, PhysicsUnit.LengthToPhysical * (worldCoord + size)); List<ShapeInfo> picked = new List<ShapeInfo>(); for (int i = 0; i < this.body.FixtureList.Count; i++) { Fixture f = this.body.FixtureList[i]; ShapeInfo s = f.UserData as ShapeInfo; FarseerPhysics.Collision.AABB fAABB; FarseerPhysics.Common.Transform transform; this.body.GetTransform(out transform); f.Shape.ComputeAABB(out fAABB, ref transform, 0); if (fsWorldAABB.Contains(ref fAABB)) { picked.Add(s); continue; } else if (!FarseerPhysics.Collision.AABB.TestOverlap(ref fsWorldAABB, ref fAABB)) continue; FarseerPhysics.Collision.AABB fAABBIntersect; fAABBIntersect.LowerBound = Vector2.Max(fAABB.LowerBound, fsWorldAABB.LowerBound); fAABBIntersect.UpperBound = Vector2.Min(fAABB.UpperBound, fsWorldAABB.UpperBound); Vector2 fsWorldCoordStep = PhysicsUnit.LengthToPhysical * (new Vector2(MathF.Max(s.AABB.W, 1.0f), MathF.Max(s.AABB.H, 1.0f)) * 0.05f); Vector2 fsTemp = fAABBIntersect.LowerBound; do { if (f.TestPoint(ref fsTemp)) { picked.Add(s); break; } fsTemp.X += fsWorldCoordStep.X; if (fsTemp.X > fAABBIntersect.UpperBound.X) { fsTemp.X = fAABBIntersect.LowerBound.X; fsTemp.Y += fsWorldCoordStep.Y; } if (fsTemp.Y > fAABBIntersect.UpperBound.Y) break; } while (true); } return picked; }
/// <summary> /// Performs a global physical AABB query and returns the <see cref="RigidBody">bodies</see> that /// might be roughly contained or intersected by the specified region. /// </summary> /// <param name="worldCoord"></param> /// <param name="size"></param> /// <returns></returns> public static List<RigidBody> QueryRectGlobal(Vector2 worldCoord, Vector2 size) { List<RigidBody> bodies = new List<RigidBody>(); Vector2 fsWorldCoord = PhysicsUnit.LengthToPhysical * worldCoord; FarseerPhysics.Collision.AABB fsWorldAABB = new FarseerPhysics.Collision.AABB(fsWorldCoord, PhysicsUnit.LengthToPhysical * (worldCoord + size)); Scene.PhysicsWorld.QueryAABB(fixture => { ShapeInfo shape = fixture.UserData as ShapeInfo; if (shape != null && shape.Parent != null && shape.Parent.Active) { if (!bodies.Contains(shape.Parent)) bodies.Add(shape.Parent); } return true; }, ref fsWorldAABB); return bodies; }
/// <summary> /// Performs a global physical AABB query and returns the <see cref="RigidBody">bodies</see> that /// might be roughly contained or intersected by the specified region. /// </summary> /// <param name="worldCoord"></param> /// <param name="size"></param> /// <returns></returns> public static List<RigidBody> QueryRectGlobal(Vector2 worldCoord, Vector2 size) { List<RigidBody> bodies = new List<RigidBody>(); Vector2 fsWorldCoord = PhysicsConvert.ToPhysicalUnit(worldCoord); FarseerPhysics.Collision.AABB fsWorldAABB = new FarseerPhysics.Collision.AABB(fsWorldCoord, PhysicsConvert.ToPhysicalUnit(size.X), PhysicsConvert.ToPhysicalUnit(size.Y)); Scene.PhysicsWorld.QueryAABB(fixture => { ShapeInfo shape = fixture.UserData as ShapeInfo; if (shape != null && shape.Parent != null && shape.Parent.Active) bodies.Add(shape.Parent); return true; }, ref fsWorldAABB); return bodies; }