Skip to content
Tags

5. Applying gravity

March 21, 2013

If you try to animate objects moving around the screen, and they start colliding, you’ll find it gets very difficult. Codea has a great physics library built into it, and it is easy to use. If you’ve looked at the physics lab built into Codea, you may have found it a bit complicated. Don’t worry – that demo had a lot of stuff in it, and most of the time, things are way simpler – as this post will show.

To apply physics, you need to create “physical” objects that will interact with each other. Suppose you want to bounce a ball on the floor, for example. You need two objects
1. A floor and sidewalls – these will be physics lines
2. A ball – this will be a circle drawing, with a circular physics object behind it

Let’s start with the walls, all around the edges (except the top)

w1 = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
w2 = physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
w3 = physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT))

Note – the word EDGE tells Codea this is a static object that will not move around.

Now the ball object. There are a few things we need to tell Codea, as explained below:

    ball_diam=60 --start by setting the diameter
    --now create the physics object that behaves like a
    --real ball, it will tell us where to draw our ball
    --think of it as a GPS navigator that guides us
    -- CREATE BODY
    --physics bodies use radius not diameter
    p_ball = physics.body(CIRCLE,ball_diam/2)
    -- APPLY GRAVITY
    p_ball.gravityScale = 1
    -- next the bounciness - this circle is bouncy, set lower for less
    p_ball.restitution = .8
    --Now give it some velocity (velocity is in pixels
    --per second, ie per 60 redraws)
    p_ball.linearVelocity = vec2(math.random(400),math.random(400))
    --POSITION it randomly on the screen
    p_ball.x = math.random(60,250)
    p_ball.y = math.random(400,600)

What have we actually created? It’s an invisible circle that will move around the screen, reacting with gravity and with the walls and floor. To make it visible, we have to draw a ball over it, like this:

function draw()
    background(200,200,200,255)
    --draw the ball --
    pushStyle() --see previous tutorials for explanation
    fill(255,0,0,255)
    --draw the ball using x,y position of physics object
    ellipse(p_ball.x,p_ball.y,ball_diam)
    popStyle()
end

So what is the difference between the physics object, and the circle we just drew? The circle is just a drawing, and has to be redrawn 60 times a second, whereas the physics object lives in the background all the time, like a real life object, and it updates its position all the time. So think of the drawn circle like putting clothes on the physics object, making it visible. Or you can think of the ellipse and physics object as being like our body and our mass – the mass is invisible but is what interacts with gravity.

Try changing the ball “restitution” above to see what effect it has. You can also set the restitution for individual walls like this

w1.restitution=0.4

but the default value is probably ok.

It’s important that your physics object and its picture are the same shape, otherwise it will bounce oddly on the screen. To help you do this, there are physics circles and rectangles, and also polygons – basically any shape made up of a set of lines.

The final code for the example above is:

function setup()
    w1 = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
    w2 = physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
    w3 = physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT))

    ball_diam=60 --start by setting the diameter
    --now create the physics object that behaves like a
    --real ball, it will tell us where to draw our ball
    --think of it as a GPS navigator that guides us
    -- CREATE BODY
    --physics bodies use radius not diameter
    p_ball = physics.body(CIRCLE,ball_diam/2)
    -- APPLY GRAVITY
    p_ball.gravityScale = 1
    -- next the bounciness - set lower for less
    p_ball.restitution = .8
    --Now give it some velocity (velocity is in pixels
    --per second, ie per 60 redraws)
    p_ball.linearVelocity=vec2(math.random(400),math.random(400))
    --POSITION it randomly on the screen
    p_ball.x = math.random(60,250)
    p_ball.y = math.random(400,600)
end

function draw()
    background(200,200,200,255)
    --draw the ball --
    pushStyle() --see previous tutorials for explanation
    fill(255,0,0,255)
    --draw the ball using x,y position of physics object
    ellipse(p_ball.x,p_ball.y,ball_diam)
    popStyle()
end

Endnote – zombie physics objects and garbage collection

There is a gotcha with physics objects. If you set them to nil, like you can do with normal variables, they don’t disappear immediately. It can take about a minute. So for a minute, you may have invisible (because you’re not drawing something visible over them any more) objects on your screen, and that can create very odd results if they collide with visible objects.

What is going on?

This is a VERY important question, because it turns out that physics objects aren’t quite like Lua variables. When you create a physics object with w1=physics.body … , you are actually creating two things – the physics object, and a Lua name for the object (so we can talk to it – think of the Lua name as an address or phone number we can use to get hold of the physics object).

So let’s take the floor we created above.
w1 = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))

If for some reason, you don’t want a floor any more and you set w1=nil, it is like throwing away the address of the object. The floor is still there, but you can’t talk to it any more. So you have only deleted one of the two things you created.

So why does the floor disappear about a minute later? Because a different Lua process, called garbage collection, notices that the physics object has no addresses any more, ie nothing can talk to it, and destroys it. This isn’t much use to you, though, because you’ve had to put up with an invisible zombie object for about a minute.

So how do we get rid of the physics object straight away? To do this, you need to use the destroy command on it, using the Lua variable to talk to it, and then you can set the Lua variable=nil. So it takes two commands rather than one.

The built in documentation on the destroy command has this example:

-- destroy should be used before
-- setting a body to nil
circle = physics.body(CIRCLE, 100)
circle:destroy()
circle = nil

Note that the destroy command must be used with a colon, not a full stop.

Anyway, please try to understand what I’ve been explaining, so you won’t have the same problem I did early on, when I only deleted the Lua variables I’d assigned to physics objects, and found I had unseen zombie physics objects colliding with my stuff, because I hadn’t destroyed the actual physics objects! That was extremely puzzling. So I hope this helps.

Advertisement

From → Physics

23 Comments
  1. Snorky permalink

    When running the code the ball bounces and after a while it is rolling on the floor, but waiting and watching a little longer the ball suddenly falls through the floor down out of the screen. Why is this happening?

    • Possibly, the ball wore a hole through the floor, that’s how realistic Codea is! (Seriously, I’ll have a look to see what is happening – that is not intended).

  2. D&D permalink

    I removed the “local” in the wx declartion of the EDGEs and the floor remained solid šŸ™‚

    • Yes, it’s a bit confusing, isn’t it? You would expect that if w1, w2 etc are local, that the walls would disappear when that function ends, but they don’t. So what is going on?

      This is a very important question, and so I’ve updated this post to include the answer at the bottom. Have another look – and thanks for asking!

  3. Malik Shalash permalink

    I am new to this so this might be a stupid question but why is the setup function not needed?

  4. Lac permalink

    I still don’t get it: why does the floor dissapear after a while when w1 is declared as local, and why can be this “bug” fixed by declaring w1 as global?

    • OK, I’ve rewritten the last section of that post to correct what I had there. I had forgotten about something called garbage collection. I hope it makes more sense now. Thanks for noticing that.

  5. Lac permalink

    Seems to be a bug in Codea if all you’ve written is true šŸ™‚

    • More likely I’m wrong than there is a bug! I’ll have to check that out.

      The good thing about little problems like this is that they teach you something new.

      • Lac permalink

        It all makes sense now, thanks for the quick update.
        As a side note: while trying to figure out what happened, I found that there is a maximum velocity for falling bodies. Why is that? Is air resistance taken into the calculation, or are there other technical constraints?

      • Yes, that’s right, there is a speed limit. I believe it’s because Codea is trying to mimic real life gravity – there may be something in the docs about that.

  6. Lac permalink

    Ok. (sorry, I’ve been playing around so…)
    This might be discussed later, but I couldn’t find it. It seems that bouncing from an EDGE happens only if the perpendicular component of the velocity is more than 32 pix/s. Otherwise the CIRCLE will stick to the EDGE even if restitution is 1, and starts to roll/move parallel to it.

    I guess this has similar reasons as you’ve said above, but for Newton’s sake, can we switch this off?

  7. jpwerner permalink

    This may be an odd question here but in the code where you are positioning the ball randomly.

    The code:

    p_ball.x=math.random(60,250)
    p_ball.y=math.random(400,600)

    Why are the values 60,250 for x and 400,600 for y. It could just be an oversight on my part….

    • no particular reason! Use whatever you like.

      • Jpwerner18 permalink

        Well I guess my question really is, is what do those numbers signify. Does codea pick a random spot between 60-250 to place the ball on the x?

      • That’s correct

      • While you’re learning, and you’re not sure about something like this, I suggest looking it up in the reference (built into Codea, or at the top of the Codea forum), or just messing with it, eg write
        for i=1,25 do
        print math.random(1,10)
        end

        Try changing the numbers and see what happens. You can’t break anything!

      • Jpwerner18 permalink

        Thanks for the clarification!

  8. Anonymous permalink

    Thanks for your site. I really struggling with Codea since I bad at math and less community on Codea. You did a great job! Thanks

Trackbacks & Pingbacks

  1. 231. New project – Angry Birds | coolcodea

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: