Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more

Tech

Physics In GameMaker: Studio - Part 2

Posted by Mark Alexander on 10 October 2014

This week's tech blog is a follow on from the previous one we posted about physics in GameMaker: Studio. If you haven't read through that one (you can find it here) then we recommend that you do, and that you download the attached GMZ example from that article as this week follows on from where we left off, and will continue to build on what we have already.

In this article, we are going to leave the object interface behind and delve into the GML code for physics in GameMaker. This is a necessary step, as creating physics objects from the UI is fine for very basic stuff, but if you want to have any control over a physics enabled instance, you need to use code as there are no equivalent Drag'n'Drop actions for them. However, as you will see, the transition to code is easy enough as long as you have grasped the fundamentals and have a bit of patience!

Coding Fixtures

In our previous article we set up a room, created some objects and gave those objects some physical properties through the GameMaker UI. We are now going to convert those UI physics properties into coded physics properties so that we can later permit the user to interact with them. So, to start with, open up the object "obj_Base" and give it a Create Event. In the Create Event, add a code block with the following code:

var fixture = physics_fixture_create();
physics_fixture_set_box_shape(fixture, sprite_width / 2, sprite_height / 2);
physics_fixture_set_density(fixture, 0);
physics_fixture_set_restitution(fixture, 0.2);
physics_fixture_set_friction(fixture, 0.5);
physics_fixture_bind(fixture, id);
physics_fixture_delete(fixture);

Let's just go through what's happening here...

  1. We create a fixture which is the combination of the shape and the properties of a physics body
  2. We set the fixture shape to be a box. This function takes half width and half height to create a rectangular shape, and it will be bound to the origin of the sprite.
  3. We set the density to 0 (it is a static instance remember), and then a couple of other basic properties. Note that we do not need to set ALL the available properties like linear dampning etc... as for a static fixture they are not required.
  4. We bind the fixture to the instance, effectively transferring the physical properties and shape to the instance.
  5. We delete the parent fixture, since we don't need it any more and to save memory.

You may be wondering why we delete the fixture if that is what we need to give the instance physical properties? Well, let's abstract it out for a moment and think about objects and instances. As you should know, an object is like a "blueprint" and an instance is what that blueprint creates. So objects are never present in rooms, it is always an instance of that object, and an instance can also be changed after creation to use different variable values or call different scripts, etc... Fixtures work in the same way. you create a "blueprint" fixture which can be then be bound to an instance. This bound fixture is what is actually created and used in the room for the physics simulation, not the blueprint fixture, so we can delete it when we are finished binding a copy to the instance.

If you add this code to the static "obj_Base" object (and switch off "enables physics" as binding the fixture will flag the instance as physics enabled), you can test again and you shouldn't notice any difference.

It is worth noting that since the binding of the fixture occurs after the instance has been created, you can set the x or y scale in the room editor for the instance and since we set the fixture using these values your instance will have a fixture created of the same size. This can't be done with the UI physics as those are bound at the same time as the instance is created. You can test this by going into the room ediotr and stretching the "obj_Base" along the x or y axis and running the example again.

You can now do the same for the "obj_Block" and "obj_Circle" objects, disbaling physics in the UI and adding code to create the fixture in the Create Event. The code itself should be straightforward for you, as you all have to do is use the same values that we had in the UI, applying each to the appropriate function. Use the manual here for help, as it has examples for all the required functions.

Coding A Polygon Fixture

Polygon fixtures are slightly different to the basic box and circle fixtures, as you have to define the positions of each point of the polygon though code. Let's look at the code for binding a polygon fixture to out "obj_Triangle" object and then explain it:

var fixture = physics_fixture_create();
physics_fixture_set_polygon_shape(fixture);
physics_fixture_add_point(fixture, 0, -(sprite_height / 2));
physics_fixture_add_point(fixture, sprite_width / 2, sprite_height / 2);
physics_fixture_add_point(fixture, -(sprite_width / 2), sprite_height / 2);
physics_fixture_set_density(fixture, 0.8);
physics_fixture_set_restitution(fixture, 0.1);
physics_fixture_set_linear_damping(fixture, 0.5);
physics_fixture_set_angular_damping(fixture, 0.5);
physics_fixture_set_friction(fixture, 0.5);
physics_fixture_bind(fixture, id);
physics_fixture_delete(fixture);

The code is pretty much the same as for the previous fixtures, only we have an extra function in there which is used to define the points of the polygon. You must call this function at least three times, as you cannot have a polygon with less than three points or you'll get an error, and a maximum of 8, as you cannot have a polygon fixture with more than 8 points. Also note that the points are defined in local space. What this means is that the polygon points are not defined using room coordinates, but rather around a (0, 0) point, which would be the "center" of the fixture.

Hopefully that image helps you to understand the point positioning easier. If you notice the text also mentions that the points must be defined in a clockwise order, otherwise the game will error, and that you cannot create concave fixtures. That doesn't mean you can't ever create concave fixtures, as you can, but just not in this way! We will now look and see how it can be done.

Multiple Fixtures

Since a fixture is really only a combination of properties and a shape, they can be combined. You can bind multiple fixtures to a single instance and that instance will use the combined shape as a collision mask along with the properties defined for all the fixtures. So you can see how that works, we're going to add a star shaped fixture to our example. You can use the one below, or create your own.

To create this shape we can simply use two triangles, with one of them "flipped", so you can make a duplicate of our object "obj_Triangle" and call it "obj_Star" and give it our new sprite. Now open the create event, and copy and paste ALL the code for the triangle polygon fixture twice, such that you have two sets of identical code. Change the polygon points in the first code block to:

physics_fixture_add_point(fixture, 0, -20);
physics_fixture_add_point(fixture, sprite_width / 2, 12);
physics_fixture_add_point(fixture, -(sprite_width / 2), 12);

 And then change the points in the second one to:

physics_fixture_add_point(fixture, -(sprite_width / 2), -12);
physics_fixture_add_point(fixture, sprite_width / 2, -12);
physics_fixture_add_point(fixture, 0, 20);

If you now fix up the Step Event of the "obj_Control" object to spawn the star object, you can see when you test the game that you now have concave shapes. This is just a simple example, but with a little bit of planning and a bit of maths, you can add multiple fixtures to a single instance to achieve many different effects. You can even create full levels from one instance and multiple bound fixtures!

Movement

The last thing we are going to cover in this tech blog, is how to move instances around in a physics enabled room. You can't just set the speed and direction and of it goes, since this is physics we are talking about here and the whole point is to try and get something approaching realistic action/reaction. Instead of speed and direction we use impulses and forces

Impulses and Forces

An impulse is when you apply a physics force to an instance or instances and this force sets a new velocity and direction, irrespective of the current velocity and direction of the instance. So if an instance is moving right and you give it an impulse upwards, the instance will suddenly move straight upwards. In GameMaker, impulses are great for things like canons and movement. 

Impulses come in two types, local and relative. Local impulses are positioned relative to a local (0,0) position, as illustrated in this image:

This type of impulse id great for creating rocket ships, or jumping mechanisms as you can ignore the rotation and position of the instance when using them.

The normal impulse is positioned based on the room coordinates, so if you have an instance at (400, 500), and place an impulse at (300, 500), it would give the instance a "push" from the left. 

You don't just give a single position for an impulse. You have to give a second one, since the magnitude and direction of the impulse is governed by the length and direction from a (0,0) point. This is called a vector and if you have trouble visualising this, just think of a clock face with a hand that moves around. The center of the clock is the (0,0) position, and the position of the end of the hand is the (xpos, ypos) of the impulse vector - the direction that the hand points in is the direction we want the impulse to go in, and the length of the hand the power to use. 

To add an impulse to our small example, open up "obj_Control" and in the Step Event, after all the other code, add this:

if mouse_check_button(mb_right)
{
with (obj_DynamicParent)
    {
    var dir = point_direction(mouse_x, mouse_y, x, y);
    physics_apply_impulse(x, y, lengthdir_x(10, dir), lengthdir_y(10, dir));
    }
}

Forces are similar to impulses in the way they are programmed (ie: you have regular and local forces, and they are set from a vector), but forces are much subtler than impulses and will add to the instances current speed, direction and rotation, rather than set it. If you change the above code to use a force instead of an impulse, you'll see that the effect isn't very noticeable as the force is being added to the stronger gravity and existing speed and direction vector. Change the length vale for the vector to 100, for example, and you'll see much more effect. Forces are great for things like magnets, gravity and propulsion.

Summary

That's it for this weeks tech blog, and we hope that this has helped you to further understand the physics integration in GameMaker: Studio. However this is not quite the end of our mini-tutorial series as there is still one further basic physics idea that you need to learn... Joints! Physics in GameMaker: Studio permits you to link fixtures together and so create complex mechanisms that react realistically. So stay tuned for the next physics tech blog where we'll cover this.

You can download a GMZ for this tech blog showing the finished example from here.

Back to Top