Example #1
0
 /// <summary>
 /// Write out a json script compatible with R.U.B.E. from current LDPhysics model.
 /// See https://www.iforce2d.net/rube for more details.
 /// </summary>
 /// <param name="fileName">The full path to the json file to create.</param>
 public static void WriteJson(Primitive fileName)
 {
     try
     {
         JsonPhysics physicsJson = new JsonPhysics(_Engine);
         physicsJson.Write(fileName);
     }
     catch (Exception ex)
     {
         Utilities.OnError(Utilities.GetCurrentMethod(), ex);
     }
 }
Example #2
0
        /// <summary>
        /// Read in a json script compatible with R.U.B.E. and create a LDPhysics model.
        /// See https://www.iforce2d.net/rube for more details.
        /// </summary>
        /// <param name="fileName">The full path to the json file to read.</param>
        /// <param name="scale">Scale all shapes, default 1 (no scaling).</param>
        /// <param name="reverseY">Reverse the Y direction up to down ("True" or "False").</param>
        /// <param name="stationary">Set all shapes to be initially at rest, joint motors are still enabled ("True" or "False").</param>
        /// <param name="offsetX">Add an x coordinate offset to all shapes.</param>
        /// <param name="offsetY">Add a y coordinate offset to all shapes, especially useful when reverseY is set.</param>
        /// <returns>A text array containing the LDPhysics commands used to create the model.</returns>
        public static Primitive ReadJson(Primitive fileName, Primitive scale, Primitive reverseY, Primitive stationary, Primitive offsetX, Primitive offsetY)
        {
            try
            {
                List<string> result = new List<string>();

                //GraphicsWindow.Clear();
                _Engine = new PhysicsEngine();
                scale *= _Engine.scale;
                JsonPhysics physicsJson = new JsonPhysics(_Engine);
                JsonWorld world = physicsJson.Read(fileName);
                result.Add("LDGraphicsWindow.State = 2");
                result.Add("GraphicsWindow.PenWidth = 1");
                result.Add("LDPhysics.Reset()");
                Primitive x, y;

                if (world.positionIterations > 0)
                {
                    PositionIterations = world.positionIterations;
                    result.Add("LDPhysics.PositionIterations = " + world.positionIterations);
                }
                if (world.velocityIterations > 0)
                {
                    VelocityIterations = world.velocityIterations;
                    result.Add("LDPhysics.VelocityIterations = " + world.velocityIterations);
                }
                if (world.stepsPerSecond > 0)
                {
                    TimeStep = 1.0f / (float)world.stepsPerSecond;
                    result.Add("LDPhysics.TimeStep = " + Cast(1.0f / (float)world.stepsPerSecond, false));
                }
                if (null != world.gravity)
                {
                    x = Cast(_Engine.scale * world.gravity.x, false);
                    y = Cast((reverseY ? -_Engine.scale : _Engine.scale) * world.gravity.y, false);
                    SetGravity(x, y);
                    result.Add("LDPhysics.SetGravity(" + x + "," + y + ")");
                }

                Dictionary<int, string> imageFiles = new Dictionary<int, string>();
                Dictionary<int, string> bodyNames = new Dictionary<int, string>();
                Dictionary<int, string> firstFixtureNames = new Dictionary<int, string>();
                if (null != world.image)
                {
                    foreach (JsonImage image in world.image)
                    {
                        imageFiles[image.body] = image.file;
                    }
                }
                if (null != world.body)
                {
                    int iBody = 0;
                    int iImage = 0;
                    int iEllipse = 0;
                    int iTriangle = 0;
                    int iRectangle = 0;
                    int iPolygon = 0;
                    foreach (JsonBody body in world.body)
                    {
                        result.Add("");
                        result.Add("'Body " + iBody);

                        if (null == body.fixture || body.fixture.Count == 0)
                        {
                            result.Add("'WARNING: Body has no fixures");
                            iBody++;
                            continue;
                        }
                        //TextWindow.WriteLine("Body " + body.name);
                        string firstShapeName = "";
                        string firstFixtureName = "";
                        bool firstFixture = true;
                        body.fixture.Reverse(); //Last fixture was first added
                        foreach (JsonFixture fixture in body.fixture)
                        {
                            string imageFile;
                            string shapeName = "";
                            if (imageFiles.TryGetValue(iBody, out imageFile))
                            {
                                if (LoadImagesAsCircles == (null == fixture.circle))
                                {
                                    LoadImagesAsCircles = null != fixture.circle;
                                    result.Add("LDPhysics.LoadImagesAsCircles = " + (null != fixture.circle ? "\"True\"" : "\"False\""));
                                }
                                shapeName = Shapes.AddImage(ImageList.LoadImage(imageFile));
                                fixture.name = "Image" + ++iImage;
                                result.Add(fixture.name + " = Shapes.AddImage(ImageList.LoadImage(\"" + imageFile + "\"))");
                            }
                            else if (null != fixture.circle)
                            {
                                x = Cast(2 * scale * fixture.circle.radius, false);
                                y = Cast(2 * scale * fixture.circle.radius, false);
                                shapeName = Shapes.AddEllipse(x, y);
                                fixture.name = "Ellipse" + ++iEllipse;
                                result.Add(fixture.name + " = Shapes.AddEllipse(" + x + "," + y + ")");
                            }
                            else if (null != fixture.polygon)
                            {
                                Primitive points = "";
                                for (int i = 0; i < fixture.polygon.vertices.x.Count; i++)
                                {
                                    Primitive point = "";
                                    point[1] = offsetX + Cast(scale * (body.position.x + fixture.polygon.vertices.x[i]), false);
                                    point[2] = offsetY + Cast(scale * (body.position.y + fixture.polygon.vertices.y[i]), reverseY);
                                    points[i + 1] = point;
                                    //TextWindow.WriteLine("Corner " + (i + 1) + " " + point[1] + ", " + point[2]);
                                }
                                if (fixture.polygon.vertices.x.Count == 3)//Triangle
                                {
                                    shapeName = Shapes.AddTriangle(points[1][1], points[1][2], points[2][1], points[2][2], points[3][1], points[3][2]);
                                    fixture.name = "Triangle" + ++iTriangle;
                                    result.Add(fixture.name + " = Shapes.AddTriangle(" + points[1][1] + "," + points[1][2] + "," + points[2][2] + "," + points[2][2] + "," + points[3][2] + "," + points[3][2] + ")");
                                }
                                if (fixture.polygon.vertices.x.Count == 4 && points[1][1] == points[4][1] && points[2][1] == points[3][1] && points[1][2] == points[2][2] && points[4][2] == points[3][2])//Rectangle
                                {
                                    Primitive dx = System.Math.Abs(points[2][1] - points[1][1]);
                                    Primitive dy = System.Math.Abs(points[4][2] - points[1][2]);
                                    shapeName = Shapes.AddRectangle(dx, dy);
                                    fixture.name = "Rectangle" + ++iRectangle;
                                    result.Add(fixture.name + " = Shapes.AddRectangle(" + dx + "," + dy + ")");
                                }
                                else
                                {
                                    shapeName = LDShapes.AddPolygon(points);
                                    fixture.name = "Polygon" + ++iPolygon;
                                    result.Add(fixture.name + " = LDShapes.AddPolygon(\"" + points + "\")");
                                }
                            }
                            else
                            {
                                result.Add("'WARNING: Fixture is not an image, triangle, rectangle, circle or polygon");
                            }

                            if (shapeName != "")
                            {
                                x = body.position.x;
                                y = body.position.y;
                                if (null != fixture.circle)
                                {
                                    x += fixture.circle.center.x;
                                    y += fixture.circle.center.y;
                                }
                                else if (null != fixture.polygon)
                                {
                                    for (int i = 0; i < fixture.polygon.vertices.x.Count; i++)
                                    {
                                        x += fixture.polygon.vertices.x[i] / (float)fixture.polygon.vertices.x.Count;
                                        y += fixture.polygon.vertices.y[i] / (float)fixture.polygon.vertices.x.Count;
                                    }
                                }
                                x = offsetX + Cast(scale * x, false);
                                y = offsetY + Cast(scale * y, reverseY);
                                bool bSetPosition = false;
                                if (null != fixture.circle || shapeName.StartsWith("Rectangle"))
                                {
                                    LDShapes.Centre(shapeName, x, y);
                                    result.Add("LDShapes.Centre(" + fixture.name + "," + x + "," + y + ")");
                                    bSetPosition = true;
                                }

                                    if (body.type == 0 || body.type == 1) //treat kinematic as static
                                {
                                    //TextWindow.WriteLine("Fixed Shape");
                                    AddFixedShape(shapeName, fixture.friction, fixture.restitution);
                                    result.Add("LDPhysics.AddFixedShape(" + fixture.name + "," + Cast(fixture.friction, false) + "," + Cast(fixture.restitution, false) + ")");
                                }
                                else
                                {
                                    //TextWindow.WriteLine("Moving Shape");
                                    AddMovingShape(shapeName, fixture.friction, fixture.restitution, fixture.density);
                                    result.Add("LDPhysics.AddMovingShape(" + fixture.name + "," + Cast(fixture.friction, false) + "," + Cast(fixture.restitution, false) + "," + Cast(fixture.density, false) + ")");
                                }
                                //TextWindow.WriteLine("Filter " + fixture.filter_categoryBits + " , " + fixture.filter_maskBits);
                                if (fixture.filter_categoryBits > 0 && fixture.filter_maskBits > 0 && (fixture.filter_categoryBits != 1 || fixture.filter_maskBits != 65535))
                                {
                                    int _categoryBits = fixture.filter_categoryBits - 1;
                                    Primitive _maskBits = "";
                                    int index = 1;
                                    for (int i = 1; i <= 16; i++)
                                    {
                                        if ((fixture.filter_maskBits & i) != 0) _maskBits[index++] = i - 1;
                                    }
                                    //TextWindow.WriteLine("Filter "+ _categoryBits + " , " + _maskBits);
                                    SetGroup(shapeName, _categoryBits, _maskBits);
                                    result.Add("LDPhysics.SetGroup(" + fixture.name + "," + _categoryBits + ",\"" + _maskBits + "\")");
                                }
                                if (fixture.sensor)
                                {
                                    ToggleSensor(shapeName);
                                    result.Add("LDPhysics.ToggleSensor(" + fixture.name + ")");
                                }

                                if (!bSetPosition)
                                {
                                    body.angle = 0; //Position already includes any rotation
                                    SetPosition(shapeName, x, y, 180.0f / System.Math.PI * body.angle);
                                    result.Add("LDPhysics.SetPosition(" + fixture.name + "," + x + "," + y + "," + Cast(180.0f / System.Math.PI * body.angle, false) + ")");
                                }

                                if (firstFixture)
                                {
                                    x = Cast(scale * body.linearVelocity.x, false);
                                    y = Cast(scale * body.linearVelocity.y, reverseY);
                                    if (!stationary)
                                    {
                                        SetVelocity(shapeName, x, y);
                                        SetRotation(shapeName, 180.0f / System.Math.PI * body.angularVelocity);
                                        if (body.linearVelocity.x != 0 || body.linearVelocity.y != 0) result.Add("LDPhysics.SetVelocity(" + fixture.name + "," + x + "," + y + ")");
                                        if (body.angularVelocity != 0) result.Add("LDPhysics.SetRotation(" + fixture.name + "," + Cast(180.0f / System.Math.PI * body.angularVelocity, false) + ")");
                                    }
                                    if (body.bullet)
                                    {
                                        SetBullet(shapeName);
                                        result.Add("LDPhysics.SetBullet(" + fixture.name + ")");
                                    }
                                    if (body.fixedRotation)
                                    {
                                        ToggleRotation(shapeName);
                                        result.Add("LDPhysics.ToggleRotation(" + fixture.name + ")");
                                    }
                                    if (body.linearDamping > 0 || body.angularDamping > 0)
                                    {
                                        SetDamping(shapeName, body.linearDamping, body.angularDamping);
                                        result.Add("LDPhysics.SetDamping(" + fixture.name + "," + Cast(body.linearDamping, false) + "," + Cast(body.angularDamping, false) + ")");
                                    }
                                    firstShapeName = shapeName;
                                    bodyNames[iBody] = firstShapeName;
                                    firstFixtureName = fixture.name;
                                    firstFixtureNames[iBody] = firstFixtureName;
                                }
                                else
                                {
                                    if (firstShapeName != "")
                                    {
                                        GroupShapes(shapeName, firstShapeName);
                                        result.Add("LDPhysics.GroupShapes(" + fixture.name + "," + firstFixtureName + ")");
                                    }
                                }
                            }
                            firstFixture = false;
                        }
                        iBody++;
                    }
                }

                if (null != world.joint)
                {
                    jointNames.Clear();
                    foreach (JsonJoint joint in world.joint)
                    {
                        result.Add("");
                        string jointName = GetJointName(joint);

                        string jointVar = "";
                        Primitive parameters = "";
                        result.Add("'Joint (Body " + joint.bodyB + ",Body " + joint.bodyA + ")");
                        // "Distance" - damping ratio (default 0)
                        // "Gear" - gear ratio, first joint, second joint (default 1, auto detect joints)
                        // "Line" - X direction, Y direction, lower translation, upper translation (default line connecting shapes, no limits)
                        // "Mouse" - max acceleration, damping ratio (default 10000, 0.7)
                        // "Prismatic_H" - X direction, Y direction, lower translation, upper translation (default 1,0, no limits)
                        // "Prismatic_V" - X direction, Y direction, lower translation, upper translation  (default 0,1, no limits)
                        // "Pulley" - pulley ratio (block and tackle) (default 1)
                        // "Revolute" - lower angle, upper angle (default no limits)
                        string name;
                        if (!firstFixtureNames.TryGetValue(joint.bodyA, out name) || !firstFixtureNames.TryGetValue(joint.bodyB, out name))
                        {
                            result.Add("'WARNING: Bodies not found");
                            continue;
                        }
                        switch (joint.type)
                        {
                            case "revolute":
                                {
                                    if (joint.enableLimit)
                                    {
                                        parameters[1] = Cast(180.0f / System.Math.PI * joint.lowerLimit, false);
                                        parameters[2] = Cast(180.0f / System.Math.PI * joint.upperLimit, false);
                                    }
                                    jointVar = AttachShapesWithJoint(bodyNames[joint.bodyB], bodyNames[joint.bodyA], "Revolute", joint.collideConnected, parameters);
                                    result.Add(jointName + " = LDPhysics.AttachShapesWithJoint(" + firstFixtureNames[joint.bodyB] + "," + firstFixtureNames[joint.bodyA] + ",\"Revolute\"," + (joint.collideConnected ? "\"True\"" : "\"False\"") + ",\"" + parameters + "\")");
                                    if (joint.enableMotor)
                                    {
                                        SetJointMotor(jointVar, 180.0f / System.Math.PI * joint.motorSpeed, scale * scale * joint.maxMotorTorque);
                                        result.Add("LDPhysics.SetJointMotor(" + jointName + "," + Cast(180.0f / System.Math.PI * joint.motorSpeed, false) + "," + Cast(scale * scale * joint.maxMotorTorque, false) + ")");
                                    }
                                }
                                break;
                            case "distance":
                                {
                                    parameters[1] = Cast(joint.dampingRatio, false);
                                    jointVar = AttachShapesWithJoint(bodyNames[joint.bodyB], bodyNames[joint.bodyA], "Distance", joint.collideConnected, parameters);
                                    result.Add(jointName + " = LDPhysics.AttachShapesWithJoint(" + firstFixtureNames[joint.bodyB] + "," + firstFixtureNames[joint.bodyA] + ",\"Distance\"," + (joint.collideConnected ? "\"True\"" : "\"False\"") + ",\"" + parameters + "\")");
                                }
                                break;
                            case "prismatic":
                                {
                                    parameters[1] = Cast(joint.localAxisA.x, false);
                                    parameters[2] = Cast(joint.localAxisA.y, reverseY);
                                    if (joint.enableLimit)
                                    {
                                        parameters[3] = Cast(scale * joint.lowerLimit, false);
                                        parameters[4] = Cast(scale * joint.upperLimit, false);
                                    }
                                    jointVar = AttachShapesWithJoint(bodyNames[joint.bodyB], bodyNames[joint.bodyA], "Prismatic_H", joint.collideConnected, parameters);
                                    result.Add(jointName + " = LDPhysics.AttachShapesWithJoint(" + firstFixtureNames[joint.bodyB] + "," + firstFixtureNames[joint.bodyA] + ",\"Prismatic_H\"," + (joint.collideConnected ? "\"True\"" : "\"False\"") + ",\"" + parameters + "\")");
                                    if (joint.enableMotor)
                                    {
                                        SetJointMotor(jointVar, scale * joint.motorSpeed, scale * joint.maxMotorForce);
                                        result.Add("LDPhysics.SetJointMotor(" + jointName + "," + Cast(scale * joint.motorSpeed, false) + "," + Cast(scale * joint.maxMotorForce, false) + ")");
                                    }
                                }
                                break;
                            case "wheel":
                                {
                                    //This is a non standard compound joint I think
                                    //AttachShapesWithJoint(bodyNames[joint.bodyB], bodyNames[joint.bodyA], "Line", joint.collideConnected, "\"\"");
                                    //result.Add("LDPhysics.AttachShapesWithJoint(" + firstFixtureNames[joint.bodyB] + "," + firstFixtureNames[joint.bodyA] + ",\"Line\"," + (joint.collideConnected ? "\"True\"" : "\"False\"") + ",\"\")");
                                    jointVar = AttachShapesWithJoint(bodyNames[joint.bodyB], bodyNames[joint.bodyA], "Distance", joint.collideConnected, "\"\"");
                                    result.Add(jointName + " = LDPhysics.AttachShapesWithJoint(" + firstFixtureNames[joint.bodyB] + "," + firstFixtureNames[joint.bodyA] + ",\"Distance\"," + (joint.collideConnected ? "\"True\"" : "\"False\"") + ",\"\")");
                                    //AttachShapesWithRotation(bodyNames[joint.bodyB], bodyNames[joint.bodyA]);
                                    //result.Add("LDPhysics.AttachShapesWithRotation(" + firstFixtureNames[joint.bodyB] + "," + firstFixtureNames[joint.bodyA] + ")");
                                    jointName = GetJointName(joint);
                                    if (joint.enableLimit)
                                    {
                                        parameters[1] = Cast(180.0f / System.Math.PI * joint.lowerLimit, false);
                                        parameters[2] = Cast(180.0f / System.Math.PI * joint.upperLimit, false);
                                    }
                                    jointVar = AttachShapesWithJoint(bodyNames[joint.bodyB], bodyNames[joint.bodyA], "Revolute", joint.collideConnected, parameters);
                                    result.Add(jointName + " = LDPhysics.AttachShapesWithJoint(" + firstFixtureNames[joint.bodyB] + "," + firstFixtureNames[joint.bodyA] + ",\"Revolute\"," + (joint.collideConnected ? "\"True\"" : "\"False\"") + ",\"" + parameters + "\")");
                                    if (joint.enableMotor)
                                    {
                                        SetJointMotor(jointVar, 180.0f / System.Math.PI * joint.motorSpeed, scale * scale * joint.maxMotorTorque);
                                        result.Add("LDPhysics.SetJointMotor(" + jointName + "," + Cast(180.0f / System.Math.PI * joint.motorSpeed, false) + "," + Cast(scale * scale * joint.maxMotorTorque, false) + ")");
                                    }
                                }
                                break;
                            case "rope":
                            case "motor":
                            case "weld":
                            case "friction":
                            default:
                                {
                                    result.Add("'WARNING: Type " + joint.type + " not found or inconsistent conversion");
                                }
                                break;
                        }
                    }
                }

                result.Add("");
                result.Add("While(\"True\")");
                result.Add("  LDPhysics.DoTimestep()");
                result.Add("  Program.Delay(" + Cast(1000 * TimeStep, false) + ")");
                result.Add("  GraphicsWindow.Title=LDPhysics.GetAllShapesAt(GraphicsWindow.MouseX,GraphicsWindow.MouseY)");
                result.Add("EndWhile");
                string code = "";
                foreach (string line in result)
                {
                    code += line + "\n";
                }
                return code;
            }
            catch (Exception ex)
            {
                Utilities.OnError(Utilities.GetCurrentMethod(), ex);
                return "";
            }
        }