Пример #1
0
        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;
        }
Пример #3
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;
            }
        }
Пример #4
0
        /// <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);
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        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();
        }
Пример #7
0
        /// <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);
        }
Пример #8
0
        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);
        }
Пример #9
0
        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);
        }
Пример #10
0
        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;
        }
Пример #11
0
		/// <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;
		}
Пример #12
0
		/// <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;
		}
Пример #13
0
        /// <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;
        }