Tutorial details

Tutorial 11 - Physics 101 | App Code for Sale | Preview

Tutorial 11 - Physics 101 | iOS Tutorial

How to use Box2D physics engine

Overview PAGE TOP


11.1 Dropping Things PAGE TOP

We are constantly amazed by the capability of Codea. An example of this is the integration of the Box2D physics engine. The talented folks at Two Lives Left have made incorporating physics into your App absurdly easy.

The included Physics Lab example project provides a good overview of the techniques available. However, if you are starting out, sometimes it isn't obvious how you can integrate similar functionality into your program. This tutorial will show you which bits you need to include in your project and how you can attach a sprite to a physics object.

11.2 The Setup PAGE TOP

In our Minesweeper game we wanted to add a bit of bling to the Menu screen. To this end we thought about dropping some mines from the top of the screen. Initially we had them bouncing off the ground but this didn't seem like a sensible thing to do with a mine so we removed the ground. We have left the code for the ground in the example below in case you need it. In your Main class, we start off by reading the sprite image into the img variable. You want to do this in setup() to ensure you only read the sprite into memory once, doing it in draw() can cause your App to crash due to running out of memory.

The next step is to create an instance of the PhysicsDebugDraw() class which we copied from the Physics Lab example project (and modified a bit). We will cover this class in section 11.4 below.

We then assign the sprite image we read to the associated spriteImage parameter in PhysicsDebugDraw() and set staticVisible to false. The only static physics object we create is the ground so setting this to false means that the ground will be invisible (but there nonetheless).

Finally we create the physics objects, the ground (createGround), a box (createBox), a circle (createCircle) and a random sized polygon (createRandPoly). The interesting one is the circle which we will attach our sprite to. Note that the radius of the circle is the same size (32 pixels) as half the width of the sprite (64 pixels). To make this more general you could use img.width/2 in place of the 32 (assuming your sprite looks roughly circular).

1   supportedOrientations(ANY)
3   function setup()
5      -- Physics Demo Metadata
7      version = 1.0
9      saveProjectInfo("Description", "Physics v"..version)
10     saveProjectInfo("Author", "Reefwing Software")
11     saveProjectInfo("Date", "30th July 2012")
12     saveProjectInfo("Version", version)
14     print("Physics Demo v"..version.."\n")
16     -- Load the sprite you want to attach to your physics object
17     -- you want the sprite and the object to be roughly the same
18     -- size and shape.
20     img = readImage("Dropbox:Mine_64x64")
22     -- Create an instance of PhysicsDebugDraw(). You will need to copy
23     -- this tab from the Physics Lab project or duplicate the project
24     -- and make it a dependency to your project. We have modified the 
25     -- code to allow you to make the ground invisible and attach a 
26     -- sprite. A copy of the modified class is provided below.
28     physicsDraw = PhysicsDebugDraw()
29     physicsDraw.spriteImage = img
30     physicsDraw.staticVisible = false
32     -- These functions are from the Physics Lab example which we have
33     -- extracted and provided in the Physics file below. As our sprite
34     -- is circular we attach it to the circle sprite.
36     createGround()
37     createBox(WIDTH/2, 100, 30, 30)
38     createCircle(WIDTH/2 + 50, HEIGHT, 32)
39     createRandPoly(WIDTH/2 + 150, 120)
41  end
43  function draw()
45     -- This sets the background color to black
47     background(blackColor)
49     -- Draw Demo Physics objects
51     physicsDraw:draw()
53  end
55  function collide(contact)
57     -- Leave this function out if you don't want to show the red dots 
58     -- which indicate the collision points.
60     physicsDraw:collide(contact)
62  end
64  function touched(touch)
66     -- Use this method to demonstrate the pointInRect() collision detection function
68     if touch.state == ENDED then
70         -- Create a random polygon wherever you tap the screen.
72         createRandPoly(touch.x, touch.y, 25, 25)
74     end
76  end

11.3 Physics Functions PAGE TOP

We have also extracted the following physic object creation functions from the Physics Lab example project:

  • createCircle(x,y,r)
  • createBox(x,y,w,h)
  • createGround() - note you could change the dimensions of this by altering the physics.body polygon.
  • createRandPoly(x,y) - creates a random polygon at screen co-ordinates (x,y) with between 3 and 10 sides
  • cleanup() - will delete all of the physic objects that you added to the PhysicsDebugDraw rendering class. In Minesweeper we call this after creating 50 objects to ensure that we don't run out of memory. Remember that if you call this you will need to re-create any physics objects that you want to model.

    1   --# Physics
    2   --
    3   -- Functions from the Physics Lab example project
    4   -- courtesy of Two Lives Left
    6   function createCircle(x,y,r)
    7      local circle = physics.body(CIRCLE, r)
    8      -- enable smooth motion
    9      circle.interpolate = true
    10     circle.x = x
    11     circle.y = y
    12     circle.restitution = 0.25
    13     circle.sleepingAllowed = false
    14     physicsDraw:addBody(circle)
    15     return circle
    16  end
    18  function createBox(x,y,w,h)
    19     -- polygons are defined by a series of points in counter-clockwise order
    20     local box = physics.body(POLYGON, vec2(-w/2,h/2), vec2(-w/2,-h/2), vec2(w/2,-h/2), vec2(w/2,h/2))
    21     box.interpolate = true
    22     box.x = x
    23     box.y = y
    24     box.restitutions = 0.25
    25     box.sleepingAllowed = false
    26     physicsDraw:addBody(box)
    27     return box
    28  end
    30  function createGround()
    31     local ground = physics.body(POLYGON, vec2(0,20), vec2(0,0), vec2(WIDTH,0), vec2(WIDTH,20))
    32     ground.type = STATIC
    33     physicsDraw:addBody(ground)
    34     return ground
    35  end
    37  function createRandPoly(x,y)
    38     local count = math.random(3,10)
    39     local r = math.random(25,75)
    40     local a = 0
    41     local d = 2 * math.pi / count
    42     local points = {}
    44     for i = 1,count do
    45         local v = vec2(r,0):rotate(a) + vec2(math.random(-10,10), math.random(-10,10))
    46         a = a + d
    47         table.insert(points, v)
    48     end
    51     local poly = physics.body(POLYGON, unpack(points))
    52     poly.x = x
    53     poly.y = y
    54     poly.sleepingAllowed = false
    55     poly.restitution = 0.25
    56     physicsDraw:addBody(poly)
    57     return poly
    58  end
    60  function cleanup()
    61     clearOutput()
    62     physicsDraw:clear()
    63  end

11.4 The Engine Room - PhysicsDebugDraw Class PAGE TOP

This class renders the physics objects that you have added to it. We have made two minor modifications to the class. We added the staticVisible flag to allow you to choose whether your static objects were visible or not. Note that static bodies don't collide with other static bodies and are immovable, so they are usually used to represent the ground.

The other thing we added was the spriteImage parameter. If this is not nil then we draw the sprite image instead of a circle. And that's all there is to it. In future tutorials we will examine some of the other capabilities enabled by the physics engine.

Reference PAGE TOP


0 Comments Leave a comment

Please login in order to leave a comment.

Newest first

to your Chupamobile Account.

The Easiest way to Launch your next App or Game.

Join Chupamobile and get instant access to thousands of ready made App and Game Templates.

Creating an account means you’re okay with Chupamobile’s Terms of Service and Privacy Policy.