/// <summary>
        /// Creates a breakable body. You would want to remove collinear points before using this.
        /// </summary>
        /// <param name="world">The world.</param>
        /// <param name="vertices">The vertices.</param>
        /// <param name="density">The density.</param>
        /// <param name="position">The position.</param>
        /// <returns></returns>
        public static BreakableBody CreateBreakableBody(World world, Vertices vertices, float density, Vector2 position,
                                                        object userData)
        {
            List <Vertices> triangles = EarclipDecomposer.ConvexPartition(vertices);

            BreakableBody breakableBody = new BreakableBody(triangles, world, density, userData);

            breakableBody.MainBody.Position = position;
            world.AddBreakableBody(breakableBody);

            return(breakableBody);
        }
Exemple #2
0
        public static List <Fixture> AttachSolidArc(float density, float radians, int sides, float radius, Vector2 position, float angle, Body body)
        {
            Vertices arc = PolygonTools.CreateArc(radians, sides, radius);

            arc.Rotate((MathHelper.Pi - radians) / 2 + angle);

            arc.Translate(ref position);

            //Close the arc
            arc.Add(arc[0]);

            List <Vertices> triangles = EarclipDecomposer.ConvexPartition(arc);

            return(AttachCompoundPolygon(triangles, density, body));
        }
Exemple #3
0
        public static TexVertOutput TexToVert(World world, Texture2D texture, float mass, bool useCentroid, float scale)
        {
            Vertices      verts;
            TexVertOutput output = new TexVertOutput();

            //  Creates an array for every pixel in the texture
            uint[] data = new uint[texture.Width * texture.Height];

            texture.GetData(data);

            verts = PolygonTools.CreatePolygon(data, texture.Width, false);

            Vector2 centroid = Vector2.Zero;

            //  Origin needs to be altered so it uses the origin of the verts
            //  rather than the texture's centre.
            if (useCentroid)
            {
                centroid = -verts.GetCentroid();
                verts.Translate(ref centroid);
            }
            else
            {
                centroid = ConvertUnits.ToSimUnits(new Vector2(texture.Width, texture.Height) * 0.5f);
            }


            float   simScale = ConvertUnits.ToSimUnits(scale);
            Vector2 Scale    = new Vector2(simScale, simScale);

            verts.Scale(ref Scale);

            verts = SimplifyTools.ReduceByDistance(verts, ConvertUnits.ToSimUnits(4f));

            Body body = BodyFactory.CreateCompoundPolygon(world, EarclipDecomposer.ConvexPartition(verts), mass);

            body.BodyType = BodyType.Dynamic;

            if (!useCentroid)
            {
                body.LocalCenter = centroid;
            }

            output.Body   = body;
            output.Origin = ConvertUnits.ToDisplayUnits(centroid);

            return(output);
        }
        public void NextStep(Vector2 position)
        {
            switch (_step)
            {
            case 0:
                _finished      = false;
                _statusMessage = "Attaching fixture to body. Choose body...";
                _step++;
                break;

            case 1:
                _foundBody = CommonHelpers.FindBody(position, _world);
                if (_foundBody == null)
                {
                    _statusMessage = "Cant find body in this position. Choose Body...";
                    break;
                }
                _statusMessage = "Body has been selected. Choose fixture position...";
                _step++;
                break;

            case 2:
                Vector2  offset             = CommonHelpers.CalculateLocalPoint(position, _foundBody);
                Vertices _tempShapeVertices = new Vertices(_initialShapeVertices);
                _tempShapeVertices.Rotate(-_foundBody.Rotation);
                _tempShapeVertices.Rotate(_prototypeBody.Rotation);
                _tempShapeVertices.Translate(ref offset);

                List <Vertices> decomposedVerts = EarclipDecomposer.ConvexPartition(_tempShapeVertices);
                _resultShapeList = new List <Shape>(decomposedVerts.Count);

                foreach (Vertices vertices in decomposedVerts)
                {
                    if (vertices.Count == 2)
                    {
                        _resultShapeList.Add(new EdgeShape(vertices[0], vertices[1]));
                    }
                    else
                    {
                        _resultShapeList.Add(new PolygonShape(vertices, _prototypeBody.Density == null ? 1f : (float)_prototypeBody.Density));
                    }
                }
                _statusMessage = "Fixture has been created.";
                _finished      = true;
                _step          = 0;
                break;
            }
        }
Exemple #5
0
        public static Body CreateGear(World world, float radius, int numberOfTeeth, float tipPercentage,
                                      float toothHeight, float density, object userData)
        {
            Vertices gearPolygon = PolygonTools.CreateGear(radius, numberOfTeeth, tipPercentage, toothHeight);

            //Gears can in some cases be convex
            if (!gearPolygon.IsConvex())
            {
                //Decompose the gear:
                List <Vertices> list = EarclipDecomposer.ConvexPartition(gearPolygon);

                return(CreateCompoundPolygon(world, list, density, userData));
            }

            return(CreatePolygon(world, gearPolygon, density, userData));
        }
Exemple #6
0
        /// <summary>
        /// Creates a rounded rectangle.
        /// Note: Automatically decomposes the capsule if it contains too many vertices (controlled by Settings.MaxPolygonVertices)
        /// </summary>
        /// <param name="world">The world.</param>
        /// <param name="width">The width.</param>
        /// <param name="height">The height.</param>
        /// <param name="xRadius">The x radius.</param>
        /// <param name="yRadius">The y radius.</param>
        /// <param name="segments">The segments.</param>
        /// <param name="density">The density.</param>
        /// <param name="position">The position.</param>
        /// <returns></returns>
        public static Body CreateRoundedRectangle(World world, float width, float height, float xRadius,
                                                  float yRadius,
                                                  int segments, float density, Vector2 position,
                                                  object userData)
        {
            Vertices verts = PolygonTools.CreateRoundedRectangle(width, height, xRadius, yRadius, segments);

            //There are too many vertices in the capsule. We decompose it.
            if (verts.Count >= Settings.MaxPolygonVertices)
            {
                List <Vertices> vertList = EarclipDecomposer.ConvexPartition(verts);
                Body            body     = CreateCompoundPolygon(world, vertList, density, userData);
                body.Position = position;
                return(body);
            }

            return(CreatePolygon(world, verts, density));
        }
Exemple #7
0
        /// <summary>
        /// Convert a closed path into a polygon.
        /// Convex decomposition is automatically performed.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="body">The body.</param>
        /// <param name="density">The density.</param>
        /// <param name="subdivisions">The subdivisions.</param>
        public static void ConvertPathToPolygon(Path path, FSBody body, float density, int subdivisions)
        {
            if (!path.Closed)
            {
                throw new Exception("The path must be closed to convert to a polygon.");
            }

            List <FVector2> verts = path.GetVertices(subdivisions);

            List <Vertices> decomposedVerts = EarclipDecomposer.ConvexPartition(new Vertices(verts));

            //List<Vertices> decomposedVerts = BayazitDecomposer.ConvexPartition(new Vertices(verts));

            foreach (Vertices item in decomposedVerts)
            {
                body.CreateFixture(new PolygonShape(item, density));
            }
        }
Exemple #8
0
        public void AddShadowForObject(Texture2D texture, Vector2 position)
        {
            uint[] data = new uint[texture.Width * texture.Height];
            texture.GetData <uint>(data);

            foreach (var poly in EarclipDecomposer.ConvexPartition(PolygonTools.CreatePolygon(data, texture.Width)))
            {
                if (poly.Count >= 3)
                {
                    var array = poly.ToArray();

                    var hull = ShadowHull.CreateConvex(ref array);
                    hull.Position = position;

                    _krypton.Hulls.Add(hull);
                }
            }
        }
        protected override MeshCollider Deserialize(IntermediateReader input, Microsoft.Xna.Framework.Content.ContentSerializerAttribute format, MeshCollider existingInstance)
        {
            MeshCollider collider = new MeshCollider();

            ContentSerializerAttribute attr = new ContentSerializerAttribute();

            attr.ElementName = "id";

            // SET ID
            int       id   = input.ReadObject <int>(attr);
            Type      type = typeof(UnityObject);
            FieldInfo fld  = type.GetField("_id", BindingFlags.Instance | BindingFlags.NonPublic);

            fld.SetValue(collider, id);

            attr.ElementName   = "isTrigger";
            collider.isTrigger = input.ReadObject <bool>(attr);

            attr.ElementName = "triangles";
            short[] triangles = input.ReadObject <short[]>(attr);

            attr.ElementName = "vertices";
            Microsoft.Xna.Framework.Vector3[] vertices = input.ReadObject <Microsoft.Xna.Framework.Vector3[]>(attr);

            List <Triangle> tris = new List <Triangle>();

            for (int i = 0; i < triangles.Length; i += 3)
            {
                if (vertices[triangles[i]].Y + vertices[triangles[i + 1]].Y + vertices[triangles[i + 2]].Y > 1)
                {
                    Debug.Log(" Warning: " + ToString() + " has non zero Y in collider");
                }
                Triangle tri = new Triangle(
                    vertices[triangles[i]].X, vertices[triangles[i]].Z,
                    vertices[triangles[i + 2]].X, vertices[triangles[i + 2]].Z,
                    vertices[triangles[i + 1]].X, vertices[triangles[i + 1]].Z
                    );
                tris.Add(tri);
            }

            collider.vertices = EarclipDecomposer.PolygonizeTriangles(tris, int.MaxValue, 0);

            return(collider);
        }
        public static List <Fixture> CreateGear(World world, float radius, int numberOfTeeth, float tipPercentage,
                                                float toothHeight, float density)
        {
            Vertices gearPolygon = PolygonTools.CreateGear(radius, numberOfTeeth, tipPercentage, toothHeight);

            //Gears can in some cases be convex
            if (!gearPolygon.IsConvex())
            {
                //Decompose the gear:
                List <Vertices> list = EarclipDecomposer.ConvexPartition(gearPolygon);

                return(CreateCompoundPolygon(world, list, density));
            }

            List <Fixture> fixtures = new List <Fixture>();

            fixtures.Add(CreatePolygon(world, gearPolygon, density));
            return(fixtures);
        }
        /// <summary>
        /// Creates a rounded rectangle.
        /// Note: Automatically decomposes the capsule if it contains too many vertices (controlled by Settings.MaxPolygonVertices)
        /// </summary>
        /// <param name="world">The world.</param>
        /// <param name="width">The width.</param>
        /// <param name="height">The height.</param>
        /// <param name="xRadius">The x radius.</param>
        /// <param name="yRadius">The y radius.</param>
        /// <param name="segments">The segments.</param>
        /// <param name="density">The density.</param>
        /// <param name="position">The position.</param>
        /// <returns></returns>
        public static List <Fixture> CreateRoundedRectangle(World world, float width, float height, float xRadius,
                                                            float yRadius,
                                                            int segments, float density, Vector2 position)
        {
            Vertices verts = PolygonTools.CreateRoundedRectangle(width, height, xRadius, yRadius, segments);

            //There are too many vertices in the capsule. We decompose it.
            if (verts.Count >= Settings.MaxPolygonVertices)
            {
                List <Vertices> vertList    = EarclipDecomposer.ConvexPartition(verts);
                List <Fixture>  fixtureList = CreateCompoundPolygon(world, vertList, density);
                fixtureList[0].Body.Position = position;
                return(fixtureList);
            }

            return(new List <Fixture> {
                CreatePolygon(world, verts, density)
            });
        }
        public override void LoadContent()
        {
            if (!isInitialized)
            {
                polygons = new List <Vector2[]>();
                vertices = new List <VertexPositionColor[]>();
                Vertices        tempVertices     = new Vertices(WorldPoints);
                List <Vertices> tempVerticesList = EarclipDecomposer.ConvexPartition(tempVertices);

                int index = 0;

                foreach (Vertices v in tempVerticesList)
                {
                    polygons.Add(new Vector2[v.Count]);

                    for (int i = 0; i < polygons[index].Length; i++)
                    {
                        polygons.ElementAt(index)[i] = v.ElementAt(i);
                    }
                    index++;
                }

                for (int i = 0; i < polygons.Count; i++)
                {
                    vertices.Add(new VertexPositionColor[polygons[i].Length * 3]);

                    for (int i2 = 1; i2 < polygons[i].Length - 1; i2++)
                    {
                        vertices.ElementAt(i)[(i2 - 1) * 3].Position = new Vector3(polygons.ElementAt(i)[0], 0.0f);
                        vertices.ElementAt(i)[(i2 - 1) * 3].Color    = color;

                        vertices.ElementAt(i)[(i2 - 1) * 3 + 1].Position = new Vector3(polygons.ElementAt(i)[i2], 0.0f);
                        vertices.ElementAt(i)[(i2 - 1) * 3 + 1].Color    = color;

                        vertices.ElementAt(i)[(i2 - 1) * 3 + 2].Position = new Vector3(polygons.ElementAt(i)[i2 + 1], 0.0f);
                        vertices.ElementAt(i)[(i2 - 1) * 3 + 2].Color    = color;
                    }
                }

                isInitialized = true;
            }
        }
        /// <summary>
        /// Creates a capsule.
        /// Note: Automatically decomposes the capsule if it contains too many vertices (controlled by Settings.MaxPolygonVertices)
        /// </summary>
        /// <param name="world">The world.</param>
        /// <param name="height">The height.</param>
        /// <param name="topRadius">The top radius.</param>
        /// <param name="topEdges">The top edges.</param>
        /// <param name="bottomRadius">The bottom radius.</param>
        /// <param name="bottomEdges">The bottom edges.</param>
        /// <param name="density">The density.</param>
        /// <param name="position">The position.</param>
        /// <returns></returns>
        public static List <Fixture> CreateCapsule(World world, float height, float topRadius, int topEdges,
                                                   float bottomRadius,
                                                   int bottomEdges, float density, Vector2 position)
        {
            Vertices verts = PolygonTools.CreateCapsule(height, topRadius, topEdges, bottomRadius, bottomEdges);

            //There are too many vertices in the capsule. We decompose it.
            if (verts.Count >= Settings.MaxPolygonVertices)
            {
                List <Vertices> vertList    = EarclipDecomposer.ConvexPartition(verts);
                List <Fixture>  fixtureList = CreateCompoundPolygon(world, vertList, density);
                fixtureList[0].Body.Position = position;

                return(fixtureList);
            }

            return(new List <Fixture> {
                CreatePolygon(world, verts, density)
            });
        }
        private void MakePolygon()
        {
            Vector2 avgLoc = new Vector2();

            foreach (Vector2 vert in polyPoints)
            {
                avgLoc += vert;
            }
            avgLoc /= polyPoints.Count;



            Vertices verts = new Vertices();

            foreach (Vector2 v in polyPoints)
            {
                verts.Add(v - avgLoc);
            }

            Body           b           = new Body(game.farseerManager.world);
            List <Fixture> composition = FixtureFactory.AttachCompoundPolygon(EarclipDecomposer.ConvexPartition(verts), 1, b);

            b.Position = avgLoc;

            foreach (Fixture triangle in composition)
            {
                FarseerTextures.ApplyTexture(triangle, FarseerTextures.TextureType.Normal);
            }

            if (composition.Count > 0)
            {
                FormManager.Property.setPendingObjects(new List <object>()
                {
                    composition[0].Body
                });
            }

            polyPoints.Clear();
        }
        private void UpdatePolys()
        {
            World.Clear();
            _sw.Start();

            _aabb = new AABB {
                LowerBound = new Vector2(0, 0), UpperBound = new Vector2(_terrainTex.Width, _terrainTex.Height),
            };
            _polys = MarchingSquares.DetectSquares(_aabb, _gridSize, _gridSize, Eval, _level, _combine);

            _sw.Stop();
            _time = _sw.Elapsed.TotalMilliseconds;
            _sw.Reset();

            for (int i = 0; i < _polys.Count; i++)
            {
                Vertices poly = _polys[i];
                poly.Translate(ref _translate);

                poly.Scale(ref _scale);
                poly.ForceCounterClockWise();

                if (!poly.IsConvex())
                {
                    List <Vertices> verts = EarclipDecomposer.ConvexPartition(poly);

                    for (int j = 0; j < verts.Count; j++)
                    {
                        Vertices v = verts[j];
                        FixtureFactory.CreatePolygon(World, v, 1);
                    }
                }
                else
                {
                    FixtureFactory.CreatePolygon(World, poly, 1);
                }
            }
        }
Exemple #16
0
        /// <summary>
        /// Creates a capsule.
        /// Note: Automatically decomposes the capsule if it contains too many vertices (controlled by Settings.MaxPolygonVertices)
        /// </summary>
        /// <param name="world">The world.</param>
        /// <param name="height">The height.</param>
        /// <param name="topRadius">The top radius.</param>
        /// <param name="topEdges">The top edges.</param>
        /// <param name="bottomRadius">The bottom radius.</param>
        /// <param name="bottomEdges">The bottom edges.</param>
        /// <param name="density">The density.</param>
        /// <param name="position">The position.</param>
        /// <returns></returns>
        public static Body CreateCapsule(World world, float height, float topRadius, int topEdges,
                                         float bottomRadius,
                                         int bottomEdges, float density, Vector2 position, object userData)
        {
            Vertices verts = PolygonTools.CreateCapsule(height, topRadius, topEdges, bottomRadius, bottomEdges);

            Body body;

            //There are too many vertices in the capsule. We decompose it.
            if (verts.Count >= Settings.MaxPolygonVertices)
            {
                List <Vertices> vertList = EarclipDecomposer.ConvexPartition(verts);
                body          = CreateCompoundPolygon(world, vertList, density, userData);
                body.Position = position;

                return(body);
            }

            body          = CreatePolygon(world, verts, density, userData);
            body.Position = position;

            return(body);
        }
Exemple #17
0
        public Texture2D TextureFromVertices(Vertices vertices, MaterialType type, Color color, float materialScale)
        {
            // copy vertices
            Vertices verts = new Vertices(vertices);

            // scale to display units (i.e. pixels) for rendering to texture
            Vector2 scale = ConvertUnits.ToDisplayUnits(Vector2.One);

            verts.Scale(ref scale);

            // translate the boundingbox center to the texture center
            // because we use an orthographic projection for rendering later
            AABB vertsBounds = verts.GetCollisionBox();

            verts.Translate(-vertsBounds.Center);

            List <Vertices> decomposedVerts;

            if (!verts.IsConvex())
            {
                decomposedVerts = EarclipDecomposer.ConvexPartition(verts);
            }
            else
            {
                decomposedVerts = new List <Vertices>();
                decomposedVerts.Add(verts);
            }
            List <VertexPositionColorTexture[]> verticesFill =
                new List <VertexPositionColorTexture[]>(decomposedVerts.Count);

            materialScale /= _materials[type].Width;

            for (int i = 0; i < decomposedVerts.Count; ++i)
            {
                verticesFill.Add(new VertexPositionColorTexture[3 * (decomposedVerts[i].Count - 2)]);
                for (int j = 0; j < decomposedVerts[i].Count - 2; ++j)
                {
                    // fill vertices
                    verticesFill[i][3 * j].Position              = new Vector3(decomposedVerts[i][0], 0f);
                    verticesFill[i][3 * j + 1].Position          = new Vector3(decomposedVerts[i].NextVertex(j), 0f);
                    verticesFill[i][3 * j + 2].Position          = new Vector3(decomposedVerts[i].NextVertex(j + 1), 0f);
                    verticesFill[i][3 * j].TextureCoordinate     = decomposedVerts[i][0] * materialScale;
                    verticesFill[i][3 * j + 1].TextureCoordinate = decomposedVerts[i].NextVertex(j) * materialScale;
                    verticesFill[i][3 * j + 2].TextureCoordinate = decomposedVerts[i].NextVertex(j + 1) * materialScale;
                    verticesFill[i][3 * j].Color         =
                        verticesFill[i][3 * j + 1].Color = verticesFill[i][3 * j + 2].Color = color;
                }
            }

            // calculate outline
            VertexPositionColor[] verticesOutline = new VertexPositionColor[2 * verts.Count];
            for (int i = 0; i < verts.Count; ++i)
            {
                verticesOutline[2 * i].Position     = new Vector3(verts[i], 0f);
                verticesOutline[2 * i + 1].Position = new Vector3(verts.NextVertex(i), 0f);
                verticesOutline[2 * i].Color        = verticesOutline[2 * i + 1].Color = Color.Black;
            }

            Vector2 vertsSize = new Vector2(vertsBounds.UpperBound.X - vertsBounds.LowerBound.X,
                                            vertsBounds.UpperBound.Y - vertsBounds.LowerBound.Y);

            return(RenderTexture((int)vertsSize.X, (int)vertsSize.Y,
                                 _materials[type], verticesFill, verticesOutline));
        }
Exemple #18
0
        public static Texture2D PolygonTexture(Vertices vertices, string pattern, Color mainColor, Color patternColor, Color outlineColor, float materialScale)
        {
            if (_assetCreator != null)
            {
                if (!_materials.ContainsKey(pattern))
                {
                    pattern = "blank";
                }

                // copy vertices
                Vertices scaledVertices = new Vertices(vertices);

                // scale to display units (i.e. pixels) for rendering to texture
                Vector2 scale = ConvertUnits.ToDisplayUnits(Vector2.One);
                scaledVertices.Scale(ref scale);

                // translate the boundingbox center to the texture center
                // because we use an orthographic projection for rendering later
                AABB verticesBounds = scaledVertices.GetCollisionBox();
                scaledVertices.Translate(-verticesBounds.Center);

                List <Vertices> decomposedVertices;
                if (!scaledVertices.IsConvex())
                {
                    decomposedVertices = EarclipDecomposer.ConvexPartition(scaledVertices);
                }
                else
                {
                    decomposedVertices = new List <Vertices>();
                    decomposedVertices.Add(scaledVertices);
                }

                List <VertexPositionColorTexture[]> verticesFill = new List <VertexPositionColorTexture[]>(decomposedVertices.Count);

                materialScale /= _materials[pattern].Width;

                for (int i = 0; i < decomposedVertices.Count; i++)
                {
                    verticesFill.Add(new VertexPositionColorTexture[3 * (decomposedVertices[i].Count - 2)]);
                    for (int j = 0; j < decomposedVertices[i].Count - 2; j++)
                    {
                        // fill vertices
                        verticesFill[i][3 * j].Position              = new Vector3(decomposedVertices[i][0], 0f);
                        verticesFill[i][3 * j + 1].Position          = new Vector3(decomposedVertices[i].NextVertex(j), 0f);
                        verticesFill[i][3 * j + 2].Position          = new Vector3(decomposedVertices[i].NextVertex(j + 1), 0f);
                        verticesFill[i][3 * j].TextureCoordinate     = decomposedVertices[i][0] * materialScale;
                        verticesFill[i][3 * j + 1].TextureCoordinate = decomposedVertices[i].NextVertex(j) * materialScale;
                        verticesFill[i][3 * j + 2].TextureCoordinate = decomposedVertices[i].NextVertex(j + 1) * materialScale;
                        verticesFill[i][3 * j].Color = verticesFill[i][3 * j + 1].Color = verticesFill[i][3 * j + 2].Color = mainColor;
                    }
                }

                // calculate outline
                VertexPositionColor[] verticesOutline = new VertexPositionColor[2 * scaledVertices.Count];
                for (int i = 0; i < scaledVertices.Count; i++)
                {
                    verticesOutline[2 * i].Position     = new Vector3(scaledVertices[i], 0f);
                    verticesOutline[2 * i + 1].Position = new Vector3(scaledVertices.NextVertex(i), 0f);
                    verticesOutline[2 * i].Color        = verticesOutline[2 * i + 1].Color = outlineColor;
                }

                Vector2 vertsSize = new Vector2(verticesBounds.UpperBound.X - verticesBounds.LowerBound.X, verticesBounds.UpperBound.Y - verticesBounds.LowerBound.Y);

                if (pattern == "blank")
                {
                    return(_assetCreator.RenderTexture((int)vertsSize.X, (int)vertsSize.Y, null, Color.Transparent, verticesFill, verticesOutline));
                }
                else
                {
                    return(_assetCreator.RenderTexture((int)vertsSize.X, (int)vertsSize.Y, _materials[pattern], patternColor, verticesFill, verticesOutline));
                }
            }
            return(null);
        }
Exemple #19
0
        public static void ComputeProperties(this Rigidbody2D body, IList <Collider2D> shapes, ref MassData[] massData)
        {
            var totalMass = body.mass;
            var totalArea = 0.0f;

            // Calculate initial properties
            for (var i = 0; i < massData.Length; i++)
            {
                var shape = shapes[i];
                massData[i].shape = shape;

                var xf = shape.transform;
                massData[i].xf = xf;

                Vector2 scale = xf.lossyScale;
                scale.Set(Mathf.Abs(scale.x), Mathf.Abs(scale.y));

                if (!shape.enabled)
                {
                    massData[i].area = 0;
                    continue;
                }

                if (shape is CircleCollider2D)
                {
                    var   circle = shape as CircleCollider2D;
                    var   rad    = circle.radius * Mathf.Max(scale.x, scale.y);
                    float area   = Mathf.PI * rad * rad;
                    massData[i].area     = area;
                    massData[i].centroid = circle.offset;
                    totalArea           += area;
                }
                else if (shape is BoxCollider2D)
                {
                    var box = shape as BoxCollider2D;

                    var       area   = 0f;
                    var       I      = 0.0f;
                    var       center = Vector2.zero;
                    var       s      = Vector2.zero;
                    const int l      = 4;

                    var points = new Vector2[4];
                    var ex     = Vector2.Scale(box.size, scale) / 2f;
                    points[0] = box.offset + ex;
                    points[1] = box.offset + new Vector2(-ex.x, ex.y);
                    points[2] = box.offset - ex;
                    points[3] = box.offset + new Vector2(ex.x, -ex.y);

                    massData[i].points = points;
                    massData[i].depths = new float[4];

                    // This code would put the reference point inside the polygon
                    for (var j = 0; j < l; ++j)
                    {
                        s += points[i];
                    }
                    s *= 1.0f / l;

                    const float k_inv3 = 1.0f / 3.0f;

                    for (var j = 0; j < l; ++j)
                    {
                        // Triangle vertices
                        var e1 = points[j] - s;
                        var e2 = j + 1 < l ? points[j + 1] - s : points[0] - s;

                        var D = Cross(e1, e2);

                        float triangleArea = 0.5f * D;
                        area += triangleArea;

                        // Area weighted centroid
                        center += triangleArea * k_inv3 * (e1 + e2);

                        float ex1 = e1.x, ey1 = e1.y;
                        float ex2 = e2.x, ey2 = e2.y;

                        var intx2 = ex1 * ex1 + ex2 * ex1 + ex2 * ex2;
                        var inty2 = ey1 * ey1 + ey2 * ey1 + ey2 * ey2;

                        I += 0.25f * k_inv3 * D * (intx2 + inty2);
                    }

                    // Area
                    massData[i].area = area;
                    totalArea       += area;

                    // Center of mass
                    center *= 1.0f / area;
                    massData[i].centroid = center + s;

                    // For inertia calc
                    massData[i].center = center;
                    massData[i].i      = I;
                }
                else if (shape is EdgeCollider2D)
                {
                    // Edges have no area, therefore they don't have mass or
                    // contribute to center of mass
                    massData[i].area = 0;
                }
                else if (shape is PolygonCollider2D)
                {
                    var poly = shape as PolygonCollider2D;

                    var pathL = poly.pathCount;

                    for (int k = 0; k < pathL; ++k)
                    {
                        var decomposed = EarclipDecomposer.ConvexPartition(poly.GetPath(k));

                        var l = decomposed.Count;

                        // Resize array
                        System.Array.Resize(ref massData, massData.Length + (l - 1));

                        // Compute each path as a seperate set of mass data
                        for (var j = 0; j < l; ++j)
                        {
                            if (decomposed[j].Count < 3)
                            {
                                // Degenerate case
                                continue;
                            }
                            ComputePropertiesPoly(poly, decomposed[j], massData, scale, j, i, ref totalArea);
                        }

                        // Increase iterator
                        i += l - 1;
                    }
                }
            }

            for (var i = 0; i < massData.Length; i++)
            {
                var shape = massData[i].shape;

                if (!shape || !shape.enabled)
                {
                    massData[i].mass    = 0;
                    massData[i].inertia = 0;
                    continue;
                }

                massData[i].mass = (massData[i].area * totalMass) / totalArea;

                if (shape is CircleCollider2D)
                {
                    var circle = shape as CircleCollider2D;
                    // inertia about the local origin
                    massData[i].inertia = massData[i].mass * (0.5f * circle.radius * circle.radius + Vector2.Dot(circle.offset, circle.offset));
                }
                else if (shape is BoxCollider2D || shape is PolygonCollider2D)
                {
                    var density = massData[i].mass / massData[i].area;

                    // Inertia tensor relative to the local origin (point s).
                    massData[i].inertia = density * massData[i].i;

                    // Shift to center of mass then to original body origin.
                    massData[i].inertia += massData[i].mass * (Vector2.Dot(massData[i].centroid, massData[i].centroid) - Vector2.Dot(massData[i].center, massData[i].center));
                }
            }
        }
Exemple #20
0
        public static List <Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f)
        {
            if (vertices.Count <= 3)
            {
                return new List <Vertices> {
                           vertices
                }
            }
            ;

            List <Vertices> results = null;

            switch (algorithm)
            {
            case TriangulationAlgorithm.Earclip:
#pragma warning disable 162
                // ReSharper disable three ConditionIsAlwaysTrueOrFalse
                if (Settings.SkipSanityChecks)
                {
                    Debug.Assert(!vertices.IsCounterClockWise(), "The Ear-clip algorithm expects the polygon to be clockwise.");
                }
                else
                {
                    if (vertices.IsCounterClockWise())
                    {
                        Vertices temp = new Vertices(vertices);
                        temp.Reverse();
                        results = EarclipDecomposer.ConvexPartition(temp, tolerance);
                    }
                    else
                    {
                        results = EarclipDecomposer.ConvexPartition(vertices, tolerance);
                    }
                }
                break;

            case TriangulationAlgorithm.Bayazit:
                if (Settings.SkipSanityChecks)
                {
                    Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly.");
                }
                else
                {
                    if (!vertices.IsCounterClockWise())
                    {
                        Vertices temp = new Vertices(vertices);
                        temp.Reverse();
                        results = BayazitDecomposer.ConvexPartition(temp);
                    }
                    else
                    {
                        results = BayazitDecomposer.ConvexPartition(vertices);
                    }
                }
                break;

            case TriangulationAlgorithm.Flipcode:
                if (Settings.SkipSanityChecks)
                {
                    Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly.");
                }
#pragma warning restore 162
                else
                {
                    if (!vertices.IsCounterClockWise())
                    {
                        Vertices temp = new Vertices(vertices);
                        temp.Reverse();
                        results = FlipcodeDecomposer.ConvexPartition(temp);
                    }
                    else
                    {
                        results = FlipcodeDecomposer.ConvexPartition(vertices);
                    }
                }
                break;

            case TriangulationAlgorithm.Seidel:
                results = SeidelDecomposer.ConvexPartition(vertices, tolerance);
                break;

            case TriangulationAlgorithm.SeidelTrapezoids:
                results = SeidelDecomposer.ConvexPartitionTrapezoid(vertices, tolerance);
                break;

            case TriangulationAlgorithm.Delauny:
                results = CDTDecomposer.ConvexPartition(vertices);
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(algorithm));
            }

            if (discardAndFixInvalid)
            {
                for (int i = results.Count - 1; i >= 0; i--)
                {
                    Vertices polygon = results[i];

                    if (!ValidatePolygon(polygon))
                    {
                        results.RemoveAt(i);
                    }
                }
            }

            return(results);
        }
Exemple #21
0
        /// <summary>
        /// Old relic before the soft time
        /// </summary>
        public override void CreateBody()
        {
            uint[] data = new uint[_cellTexture.Width * _cellTexture.Height];

            _cellTexture.GetData(data);

            //Find the vertices that makes up the outline of the shape in the texture
            Vertices textureVertices = PolygonTools.CreatePolygon(data, _cellTexture.Width, false);

            //The tool return vertices as they were found in the texture.
            //We need to find the real center (centroid) of the vertices for 2 reasons:

            //1. To translate the vertices so the polygon is centered around the centroid.
            Vector2 centroid = -textureVertices.GetCentroid();

            textureVertices.Translate(ref centroid);

            //2. To draw the texture the correct place.
            _origin = -centroid;
            _spriteDict[PlayerSprites.Cell].Origin = _origin;

            float scale = _spriteDict[PlayerSprites.Cell].Scale.X;

            foreach (PlayerSprites sprite in Enum.GetValues(typeof(PlayerSprites)))
            {
                if (sprite == PlayerSprites.Cell)
                {
                    continue;
                }
                else
                {
                    _spriteDict[sprite].Position -= _origin * scale;
                }
            }

            //We simplify the vertices found in the texture.
            textureVertices = SimplifyTools.ReduceByDistance(textureVertices, 4f);

            //Since it is a concave polygon, we need to partition it into several smaller convex polygons
            List <Vertices> list = EarclipDecomposer.ConvexPartition(textureVertices);

            //scale the vertices from graphics space to sim space
            Vector2 vertScale = ConvertUnits.ToSimUnits(new Vector2(1)) * scale;

            foreach (Vertices vertices in list)
            {
                vertices.Scale(ref vertScale);
            }

            //Create a single body with multiple fixtures
            Body                     = BodyFactory.CreateCompoundPolygon(PlayWindow.World, list, 1f, BodyType.Dynamic);
            Body.Position            = ConvertUnits.ToSimUnits(Position);
            Body.BodyType            = BodyType.Dynamic;
            Body.CollisionCategories = Category.Cat10;
            Body.CollidesWith        = Category.All;
            Body.OnCollision        += ObjectCollision;
            Body.Friction            = 0.1f;
            Body.FixedRotation       = true;
            Body.Mass                = 2f;
            Body.LinearDamping       = 1;
        }
Exemple #22
0
        public Texture2D TextureFromVertices(Vertices vertices, Texture2D material, Color fillColor, bool hasOutline, Color outlineColor, float materialScale)
        {
            Vertices verts = new Vertices(vertices);

            AABB vertsBounds = verts.GetCollisionBox();

            verts.Translate(-vertsBounds.Center);

            List <Vertices> decomposedVerts;

            if (!verts.IsConvex())
            {
                decomposedVerts = EarclipDecomposer.ConvexPartition(verts);
            }
            else
            {
                decomposedVerts = new List <Vertices>()
                {
                    verts
                };
            }

            //fill
            List <VertexPositionColorTexture[]> verticesFill = new List <VertexPositionColorTexture[]>(decomposedVerts.Count);

            for (int i = 0; i < decomposedVerts.Count; i++)
            {
                verticesFill.Add(new VertexPositionColorTexture[3 * (decomposedVerts[i].Count - 2)]);
                for (int j = 0; j < decomposedVerts[i].Count - 2; j++)
                {
                    verticesFill[i][3 * j].Position              = new Vector3(decomposedVerts[i][0], 0f);
                    verticesFill[i][3 * j + 1].Position          = new Vector3(decomposedVerts[i].NextVertex(j), 0f);
                    verticesFill[i][3 * j + 2].Position          = new Vector3(decomposedVerts[i].NextVertex(j + 1), 0f);
                    verticesFill[i][3 * j].TextureCoordinate     = decomposedVerts[i][0] * materialScale;
                    verticesFill[i][3 * j + 1].TextureCoordinate = decomposedVerts[i].NextVertex(j) * materialScale;
                    verticesFill[i][3 * j + 2].TextureCoordinate = decomposedVerts[i].NextVertex(j + 1) * materialScale;
                    verticesFill[i][3 * j].Color = verticesFill[i][3 * j + 1].Color = verticesFill[i][3 * j + 2].Color = fillColor;
                }
            }

            //outline
            VertexPositionColor[] verticesOutline;

            if (!hasOutline)
            {
                verticesOutline = new VertexPositionColor[0];
            }
            else
            {
                verticesOutline = new VertexPositionColor[2 * verts.Count];
                for (int i = 0; i < verts.Count; i++)
                {
                    verticesOutline[2 * i].Position     = new Vector3(verts[i], 0f);
                    verticesOutline[2 * i + 1].Position = new Vector3(verts.NextVertex(i), 0f);
                    verticesOutline[2 * i].Color        = verticesOutline[2 * i + 1].Color = outlineColor;
                }
            }

            Vector2 vertsSize = new Vector2(vertsBounds.UpperBound.X - vertsBounds.LowerBound.X, vertsBounds.UpperBound.Y - vertsBounds.LowerBound.Y);

            return(RenderTexture((int)System.Math.Ceiling(vertsSize.X), (int)System.Math.Ceiling(vertsSize.Y), material, verticesFill, hasOutline, verticesOutline));
        }