about         games         blog         gifts         contact
  • WIP Game
  • Cargo Delivery
  • Sally
http://www.catsinthesky.com/blog/article/2012/03/3/new-game-studies http://www.catsinthesky.com/game/cargo-delivery http://www.catsinthesky.com/game/sallys-cats
A new site
We made some big changes to make our site more active and up to date. Apart from the layout, we added Facebook integration and the blog is finally up.
What's next?
Multi-language support;
Twitter integration;
Achievements;
... and more

New Game Studies

We started producing a new IP! We can't unveil a large amount of details yet, but we will do it in the coming months. For now, we're posting some concepts and art studies.


Mysterious concept #1


Mysterious concept #2


Mysterious concept #3


Mysterious concept #4

Farseer Physics (Box2D) and Unity (Part #4)

Part #1 | Part #2 | Part #3 | Part #4 | .unitypackage | GitHub
This part of the tutorial covers collision events, a.k.a. triggers. Unlike collision filtering, triggers are always present in games. They are essential for a game's logic, from save points to deadly bullets.

Since triggers can be used for anything and in many different ways, I'll cover more the programming logic behind it (instead relying on already made components like in the previous parts). Grab the Unity package file, start a new project then import everything. The base scene is in Tutorials/Part 4/CollisionEventsBase (Image 1).


Image 1 - The tutorial starter scene

Now FarseerUnity also stores the Tag information inside Body and Fixture instances. You can use this to work with your trigger logic. For this tutorial, we will change the PLAYER tag to "Player" (Image 2) and the playerBOX tag to "Respawn" (Image 3).


Image 2 - PLAYER tag


Image 3 - playerBOX tag

Now, create a new C# script at Tutorials/Part 4/CollisionEventsBase folder named "TestCollisionEventsCp". For now we will leave it with this code:

using UnityEngine;

using System.Collections.Generic;

using FarseerPhysics.Dynamics.Contacts;

using FarseerPhysics.Dynamics;

using FVector2 = Microsoft.Xna.Framework.FVector2;

public class TestCollisionEventsCp : MonoBehaviour

{

}

Add this script to the PLAYER game object (Image 4).


Image 4 - The new component added to the PLAYER game object

Now replace the code with this basic structure:

using UnityEngine;

using System.Collections.Generic;

using FarseerPhysics.Dynamics.Contacts;

using FarseerPhysics.Dynamics;

using FVector2 = Microsoft.Xna.Framework.FVector2;

public class TestCollisionEventsCp : MonoBehaviour

{

private Body body;

private List<Contact> lastContacts;

void Start()

{

body = GetComponent<FSBodyComponent>().PhysicsBody;

lastContacts = new List<Contact>();

}

void Update()

{

}

private bool OnCollisionEvent(Fixture fixtureA, Fixture fixtureB, Contact contact)

{

return true;

}

}

The Farseer Physics Engine uses default C# events to dispatch when a collision takes place (body.OnCollision) and when it stops (body.OnSeparation). This is similar to Physx OnCollisionEnter and OnCollisionExit, but it is per fixture (a body can have multiple fixtures/shapes). To handle the in-between collision steps, you can store the contact instance, like it's prepared for the lastContacts variable.

After this line:

lastContacts = new List<Contact>();

Add this line:

body.OnCollision += OnCollisionEvent;

Now when a collision takes place, the OnCollisionEvent function will be triggered. It returns a boolean because the function tells Farseer if we want this collision to occur, or not. If you return false, the objects won't collide at all. Change the "return true;" into "return false;" and hit play on the editor to see what happens.

Now, to test a scenario when you don't want a collision between 2 specific objects (in this case, PLAYER and playerBOX), move the CubeB stack away from the player game object, and replace the OnCollisionEvent function with this:

private bool OnCollisionEvent(Fixture fixtureA, Fixture fixtureB, Contact contact)

{

Body bodyB = fixtureB.Body;

if(bodyB.UserTag == "Respawn")

return false;

return true;

}

Since we set the tags earlier, we can use them to filter a collision just like a simple collision filtering setup would do. If you hit play now, PLAYER and playerBOX won't collide because this event is manually filtering them out.

Now suppose you would want to react to this collision immediately. The Contact class holds everything you need to do that. The global Manifold holds the global collision points and the collision normal. Replace OnCollisionEvent with this:

private bool OnCollisionEvent(Fixture fixtureA, Fixture fixtureB, Contact contact)

{

Body bodyB = fixtureB.Body;

if(bodyB.UserTag == "Respawn")

{

FVector2 normal;

FarseerPhysics.Common.FixedArray2<FVector2> contactPoints;

contact.GetWorldManifold(out normal, out contactPoints);

bodyB.ApplyLinearImpulse(normal * -55f);

body.ApplyLinearImpulse(normal * 55f);

}

return true;

}

In the code above, the normal variable holds the global collision normal, so when we apply a force using it, the objects will fly at opposite directions. The global contact points could also be used for many things, such as playing 3D impact sounds at a point.

Suppose that playerBOX is a collectible item. You could do something like this:

private bool OnCollisionEvent(Fixture fixtureA, Fixture fixtureB, Contact contact)

{

Body bodyB = fixtureB.Body;

if(bodyB.UserTag == "Respawn")

{

// remove BodyB controller

Destroy(bodyB.UserFSBodyComponent.gameObject);

// add points, stats, anything else

// here

// don't return a collision

return false;

}

return true;

}

And for checking if the player can jump:

CODENEW

Now, let's do a more complex example to use what the Contact class can offer, like getting the total weight of an object (like scales). Since the contact also stores the resulting normal and tangent impulses, it's easy to do it. First, create a new 3D Text game object to display the weight (Image 5).


Image 5 - New 3D Text

Now make this game object a child of PLAYER (Image 6).


Image 6 - 3D Text GO as a child of PLAYER GO

And add a public member inside TestCollisionEventsCp class (paste the code below):

public TextMesh LinkedTextMesh;

Now drag the 3D Text game object instance to the LinkedTextMesh property (Image 7):


Image 7 - Linking the 3D text instance.

Now replace the TestCollisionEventsCp code with this:

using UnityEngine;

using System.Collections.Generic;

using FarseerPhysics.Dynamics.Contacts;

using FarseerPhysics.Dynamics;

using FVector2 = Microsoft.Xna.Framework.FVector2;


public class TestCollisionEventsCp : MonoBehaviour

{

public TextMesh LinkedTextMesh;

private Body body;

private List<Contact> lastContacts;

void Start()

{

body = GetComponent<FSBodyComponent>().PhysicsBody;

lastContacts = new List<Contact>();

body.OnCollision += OnCollisionEvent;

}

void Update()

{

float weight = body.Mass;

GetWeight(ref weight);

LinkedTextMesh.text = weight.ToString("#0.00") + "Kg";

}

private void GetWeight(ref float weight)

{

if(lastContacts.Count < 1)

return;

float ownWeight = weight;

weight = 0f;

foreach(Contact lastContact in lastContacts)

{

bool isTouching = lastContact.IsTouching();

if(isTouching)

{

FarseerPhysics.Common.FixedArray2<FarseerPhysics.Collision.ManifoldPoint> localManifoldPoints = 

lastContact.Manifold.Points;

// gravity = 9.8f (hard coded here just for testing purposes)

// Time.fixedDeltaTime is the FPE timeStep

weight += 

(1f * (localManifoldPoints[0].NormalImpulse/Time.fixedDeltaTime) / 9.8f);

weight += 

(1f * (localManifoldPoints[1].NormalImpulse/Time.fixedDeltaTime) / 9.8f);

}

}

// remove inactive contacts

for(int i = 0; i < lastContacts.Count; i++)

{

if(!lastContacts[i].IsTouching())

{

lastContacts.RemoveAt(i);

i = Mathf.Max(0, i - 1);

}

}

// calc weight

weight -= ownWeight;

weight *= 0.5f;

weight += ownWeight;

}

private bool OnCollisionEvent(Fixture fixtureA, Fixture fixtureB, Contact contact)

{

if(!lastContacts.Contains(contact))

lastContacts.Add(contact);

return true;

}

}

As you can see, the local Manifold points are packed with impulse data. This can be used to determine the total weight, crush force, break force, etc. To view the global manifold points and normals, add this:

void OnDrawGizmos()

{

if(lastContacts == null)

return;

foreach(Contact lastContact in lastContacts)

{

if(!lastContact.IsTouching())

return;

FarseerPhysics.Common.FixedArray2<FVector2> contactPoints;

FVector2 normal;

lastContact.GetWorldManifold(out normal, out contactPoints);

Vector3 p0 = FSHelper.FVector2ToVector3(contactPoints[0]);

Vector3 p1 = FSHelper.FVector2ToVector3(contactPoints[1]);

Vector3 pn = FSHelper.FVector2ToVector3(normal);

Gizmos.color = Color.red;

Gizmos.DrawWireSphere(p0, 0.15f);

Gizmos.DrawLine(p0, p0 + pn * 2f);

Gizmos.color = Color.yellow;

Gizmos.DrawWireSphere(p1, 0.15f);

Gizmos.DrawLine(p1, p1 + pn * 2f);

}

}

If everything is working properly, the weight will change when you stack objects on top (Image 8):


Image 8 - 44.0Kg

That's it for part 4! I decided to focus on programming because it doesn't matter how many collision events components I may add in the future, there will always be a case when your game needs something specific.

Farseer Physics (Box2D) and Unity (Part #3)

Part #1 | Part #2 | Part #3 | Part #4 | .unitypackage | GitHub
Now that we have the basics, concave objects and joints, what about collision filtering? Eventually you will reach a development stage in your game that "certain objects should not collide with each other", or "Group A" should ignore collisions from "Group B". That's when Collision Filtering kicks in.

I like the way that Farseer Physics Engine extends this feature from Box2D. Instead of setting hard-coded bit flags on each fixture, you just need to set collision groups. A fixture can belong to zero or more groups and it can also collide with any group(s) you want to. When I was porting this to Unity, I avoided using Unity layers and tags because both properties are used a lot on other things, but it also couldn't be a DIY hard-coded solution.

Now, there's a new configuration window. Right now there's only the option to name the collision categories, but I plan to port all settings defined in Farseer Physics Settings.cs file (so you don't have to change them in code).


Image 1 - New configuration window

I also decided not to use PlayerPrefs (and EditorPrefs) for the configuration files, since the PlayerPrefs can't be easily shared between developers, and any end user can edit them, so it's unsafe. The configuration is compiled with all the other scripts.


Image 2 - Configuring collision categories

To begin with this tutorial, download the latest package then open the scene indicated on the image below (Image 3).


Image 3 - Base scene

For convenience's sake, the collision groups are already setup. They are located at Assets/Tests/CollisionGroups. To create a new group, right-click at a folder then go to Create/FarseerUnity Collision Group (Image 4).


Image 4 - New collision group asset

The Collision Group asset is pretty simple. It's just a bunch of checkboxes that you can determine the category (or categories) this group belongs and what collides with it (Image 5). This process saves you from doing this setup on each shape.


Image 5 - A Collision Group asset

Now, inside the "STATIC" GameObject, there are 3 GameObjects that are the ground and walls of the scene, go to the "filter Collision" property of the FSShapeComponent and change it to "Preset File" (Image 6).


Image 6 - Preset file popup field

Drag the "Ground" Collision Group asset to the object field (Image 7).


Image 7 - A wild object field appears

Now, inside the "complexBody" GameObject there's a FSConcaveShapeComponent that also needs to be setup (Image 8). Drag the "RegularObjects" collision group to it.


Image 8 - Setting up another collision group

Don't forget to click on the "Generate convex shapes" button (since you altered its properties).


Image 9 - To update the convex shapes

Setup the "Sphere00" to use the "Oranges" group, and the "Cube" to use the "Rectangles" group. Then duplicate all the dynamic objects several times to test the collision filtering, then press play!


Image 10 - Testing the scene

That's it for part 3. The next part of the tutorial will cover collision events.

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.

Concave Shapes

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


Image 6

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).


Image 8

Now, instead of adding the usual FSShapeComponent, we will add the FSConvexShapeComponent (Image 9).


Image 9

Add a new GameObject, make it a child of "complexShape". I named mine as "p00". Setup its position (Image 10).


Image 10

Now start cloning the points and positioning them in a counter-clockwise order (Image 11, 12).


Image 11


Image 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.


Image 13

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).


Image 14


Image 15

The image below shows what the component generated. The outline was converted into 6 polygon shapes (Image 16).


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.


Image 17

Distance Joints

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).


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).


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).


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).


Image 21

Once you linked everything, you can press play and test your creation (Image 22).


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).


Image 23


Image 24

Revolute Joints

"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).


Image 25

Add the FSRevoluteJointComponent to the base (smaller, static box) (Image 26).


Image 26


Image 27

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).


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).


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.


Image 30

Set the local anchor so the shared point will be at the left edge of Body B (Image 31, 32).


Image 31


Image 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).


Image 33


Image 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).


Image 35


Image 36

Prismatic Joints

"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.


Image 37

Add a FSPrismaticJointComponent to it (Image 38).


Image 38

The Body A is the big platform. I renamed the box to "slider". It's the Body B (Image 39).


Image 39

Now test it again. If everything is correct, you should see something like in the picture below:


Image 40

That's it (for now)! I will cover the remaining joints on Part 3. Here's the end result of this part 2: