Farseer Physics (Box2D) and Unity (Part #2)
Part #1 | Part #2 | Part #3 | Part #4 | .unitypackage | GitHub
Now that we got the basics of how our Farseer Physics Engine port works, let's move to more advanced things. In the last part I covered the World, Body and Basic Shape components... so what about concave shapes and joints?
Image 1 - Concave objects and joints
Before starting this tutorial, download the FarseerUnity_CatsintheSky.unitypackage file then create a new project.
As of 99.9% of all physics engines out there, you can't have real concave shapes. If an engine is known to support concave shapes by default, it probably converts this shape into several smaller convex shapes. Doing this by hand can be very frustrating and time consuming but, luckily for us, Farseer includes several concave to convex decomposers.
Setup a scene with a camera (iso, size 27) and the FSWorldComponent like on the image below.
Image 2 - Initial scene setup
Now, before we continue, we can add a simple test component to the FSWorldComponent's GameObject, you can find it as FSMouseTest (project tab) or like on Image 3.
Image 3 - Mouse test component
Now create a basic cube to set it as the ground. Once you got the dimensions (also materials, name, etc.) the way you want it, add the FSBodyComponent.
Image 4 - Adding the body component
Add the regular FSShapeComponent at the same level as the FSBodyComponent remains. There's no need to put the shape component in a child object since we're using just one shape and we're borrowing Unity's collider to define the shape. After setting up the shape, I cloned the ground object to make the walls (Image 5).
Image 5 - Ground, walls
Add a new GameObject because now we will setup a concave shape. Actually it is a component that easily converts an outline into convex polygons. I named mine as complexBody (Image 6).
Add a new plane (to use it as the graphics for our complex concave shape). Make it a child of the "complexBody" GameObject. Rotate it in the X axis for about -90 degrees. Add the complexShape1 material to it (Image 7).
Image 7 - Setting up the new plane
Add a new GameObject and make it a child of "complexBody" again. This will be the container of the component that handles the shape conversion (Image 8).
Now, instead of adding the usual FSShapeComponent, we will add the FSConvexShapeComponent (Image 9).
Add a new GameObject, make it a child of "complexShape". I named mine as "p00". Setup its position (Image 10).
Now start cloning the points and positioning them in a counter-clockwise order (Image 11, 12).
Now rename the remaining GameObjects and add them to the "Transform Points" array (Image 13). if the setup was done properly, you should see magenta points and line numbers.
Click on the "Generate convex shapes" button so the real shapes will be generated. If you need to alter something later, you can press the button again to update the shapes (the old ones will be overwritten) (Image 14, 15).
The image below shows what the component generated. The outline was converted into 6 polygon shapes (Image 16).
The complex shape is done! Add a FSBodyComponent to "complexBody" if you didn't already. Then press play to test the collision of it. You can use the mouse to move objects around, since we added the mouse test component earlier.
From the Box2D manual, "one of the simplest joint is a distance joint which says that the distance between two points on two bodies must be constant". They are also the easiest ones to setup.
Start by making a sphere, attaching a FSBodyComponent then a FSShapeComponent. Set the shape type to circle then leave the "use unity collider" option checked (Image 18).
Clone the spheres until you have about 8 of them. Rename their GameObjects so you won't get lost when setting the distance joints (Image 19).
Add a FSDistanceJointComponent. It doesn't matter where you add those joint components since they link bodies regardlessly of being a child of one of them, or not. I added one component per each sphere (except the last one) (Image 20).
Link BodyA and BodyB on each joint component. The pattern I used to link them was linking the object with the joint component as BodyA and the next body as BodyB (Image 21).
Once you linked everything, you can press play and test your creation (Image 22).
After testing it, I cloned the connected bodies and turned one of the bodies as static to test this type of joint against static bodies too (Image 23, 24).
"A revolute joint forces two bodies to share a common anchor point, often called a hinge point. The revolute joint has a single degree of freedom: the relative rotation of the two bodies. This is called the joint angle."
Add two new boxes and setup their bodies and their basic shape components. Make one of them smaller than the other and set the shape type as static (Image 25).
Add the FSRevoluteJointComponent to the base (smaller, static box) (Image 26).
The FSRevoluteJointComponent has several options, unlike a distance joint. Both bodies will share the anchor point defined in Body B (Local Anchor B). Right now, it is set as [0,0], which means that both bodies will share the point at the center of Body B. The limit options can be used to limit the shared rotation of the connected bodies to a certain amount of degrees (this is commonly used when making ragdolls). The motor options can be used to apply an angular force at this shared point (commonly used when making wheels).
Add the smaller body (the base) to the Body A field, then add the other box to the Body B (Image 28).
If you press play, you should see that if an object falls on top of it, the platform will rotate.
Now let's test the motor properties. Check the "Motor Enabled" field then set a speed other than zero (Image 29).
Now, to test the angle limit properties, clone both objects and move them away from the original objects, then move the platform to the right like on the image below.
Set the local anchor so the shared point will be at the left edge of Body B (Image 31, 32).
Now check the "Limit Enabled" property. The white line is the current rotation of Body B. The rotation is limited by the green and red lines (Image 33, 34).
Clone the big platform, scale it, then move it to the right edge of the original platform (Image 35). Add a FSRevoluteJointComponent to it. The Body A will be the big platform and Body B will be this new object (Image 36).
"A prismatic joint allows for relative translation of two bodies along a specified axis. A prismatic joint prevents relative rotation. Therefore, a prismatic joint has a single degree of freedom."
To test a prismatic joint: Clone this box again, change the color/material, remove the revolute joint component from it then move it like in the image below.
Add a FSPrismaticJointComponent to it (Image 38).
The Body A is the big platform. I renamed the box to "slider". It's the Body B (Image 39).
Now test it again. If everything is correct, you should see something like in the picture below:
That's it (for now)! I will cover the remaining joints on Part 3. Here's the end result of this part 2: