Skip to content
Tags

6. More physics

March 21, 2013

Physics isn’t just useful for gravity, but if you program a tabletop application, you may want to handle collisions between objects, bouncing off the sides, friction, etc. Codea’s physics can handle all this for you, as we will show now – and show you how to spin an object round, and make sounds, too.

Let’s use a rectangle, so we can see it spin, and an image from the Codea library.

First the rectangle. There’s quite a lot of code to put in the setup function, but it’s mostly settings, and once they’re set, there is surprisingly little to do after that. So don’t stop now. Wait until you see the result.

    --first the rectangle
    rect_width=100 --size of rectangle
    rect_height=50

    --now create the physics object, we feed it the location
    --of the four corners, relative to the centre of the
    --rectangle, which is why all the measurements below
    --are for half the height or width
    p_rect = physics.body(POLYGON,
                        vec2(-rect_width / 2, -rect_height / 2),
                        vec2(-rect_width / 2, rect_height / 2),
                        vec2(rect_width / 2, rect_height / 2),
                        vec2(rect_width / 2, -rect_height / 2)
                        )
    p_rect.x = math.random(60,250)  -- choose random x
    p_rect.y = math.random(60,250) -- same for y
    p_rect.angle=math.random(0,360) -- rotation, 0 to 360deg
    p_rect.gravityScale = 0
    p_rect.restitution = 1 -- this rectangle is bouncy
    p_rect.friction = 0.1 -- the amount of friction to apply
    -- set a random velocity (pixels per second)
    p_rect.linearVelocity = vec2(100+math.random(400),100+math.random(400))
    p_rect.info='rect' --give the rectangle a name, so when
    --collisions occur, we can figure out which object was
    --involved. This is optional.

Now the image.

    img=readImage('Tyrian Remastered:Mine Spiked Huge')
    --I've chosen a roughly circular image so I can
    --use a physics circle object
    --use the average of height and width as diameter of circle
    img_diam=(img.width+img.height)/2
    --create the physics object - note diam/2 as
    --use radius not diameter
    p_img = physics.body(CIRCLE,img_diam/2)
    p_img.x = math.random(60,250) -- random position
    p_img.y = math.random(60,250) -- ditto
    p_img.angle=math.random(0,360)
    p_img.gravityScale = 0 -- no gravity
    p_img.restitution = 0.8 -- this image is not so bouncy
    p_img.friction = 0.4 -- the amount of friction
    p_img.linearVelocity = vec2(math.random(400),math.random(400))
    p_img.info='mine' --as for rectangle above

Now the walls around the side. I’ve created a little function to help with this.

--create the walls - physics objects can only bounce off
--each other. The first four parameters are the starting x,y
--and ending x,y; the fifth parameter is restitution, or
--bounciness, from 0=no bounce to 1=very bouncy
function CreateWalls()
    leftWall = CreateWall(1,1,1,HEIGHT-1,1.0)
    rightWall = CreateWall(WIDTH-1,0,WIDTH-1,HEIGHT-1,0.9)
    bottomWall = CreateWall(1,1,WIDTH-1,1,0.2)
    topWall = CreateWall(1,HEIGHT-1,WIDTH-1,HEIGHT-1,0.7)
end

--this function creates one wall (actually just a line)
function CreateWall(x,y,x1,y1,r)
    local w = physics.body(EDGE,vec2(x,y),vec2(x1,y1)) -- vec2
    w.restitution=r --see comment above
    return w
end

Now the drawing routine. There’s not much code, considering how much work the physics engine is doing for us. Here is the first half, for the rectangle.

function draw()
    background(200,200,200,255)
    --draw the rectangle --
    pushStyle()
    fill(255,0,0,255)
    --see explanation of next few lines underneath
    pushMatrix()
        translate(p_rect.x, p_rect.y)
        rotate(p_rect.angle)
        rect(-rect_width / 2, -rect_height / 2, rect_width, rect_height)
    popMatrix()
    popStyle()

The lines above really confused me at first, because I couldn’t figure out what was happening, but this analogy may help.

Suppose you had to draw a little shape lots of times, all over a piece of paper, at different angles. The hard way is to keep the paper as is, and lean all over the place to draw sideways over here, and upside down over there.

The sensible approach is to turn the paper round and move it so that you can draw each shape the right way up, right in front of you. And Codea finds that the best way, too. It’s much easier to turn the screen around and draw a normal rectangle, than to try to draw the rectangle at an angle.

So let’s look at the code, now. The pushMatrix and popMatrix lines simply store the screen settings before you make changes, then put things back when you’re done.

Translate moves the 0,0 point to the x,y position of the physics rectangle, so now you can draw it as though it as at 0,0.

Rotate turns the screen around to match the angle of the physics object, so when we draw our rectangle, it will be correctly rotated.

Why do we have to move to the x,y position of the rectangle before we rotate? Because rotation is always around the point 0,0. If we want to only rotate our rectangle and nothing else, then we go to the point where we want to draw it, so 0,0 is now centred on the rectangle’s position, rotate the whole screen, draw the rectangle, and rotate back again (pushMatrix does that).

Then we draw our rectangle.

Now the rest of the draw function, for the image….

 --draw image ---
    --see explanation of next few lines at bottom below
    pushMatrix()
        translate(p_img.x, p_img.y)
        rotate(p_img.angle)
        sprite(img,0,0)
    popMatrix()
end

Finally, we give each object a different sound when it hits something. If you don’t want sound, you can just leave this out.

All you need to know is that when two bodies (including walls etc) collide, Codea provides a contact object via the collide function. The contact object can tell you things like the x,y location, and the two physics objects involved (it labels them contactA and contactB). We gave our physics bodies names, so we can use contactA and contactB to tell us if our rectangle or image were involved in the crash.

function collide(contact)
    if contact.state == BEGAN then --make sound at start of contact
        if contact.bodyA.info=='rect' or contact.bodyB.info=='rect' then
            sound(SOUND_JUMP, 50)
        end
        if contact.bodyA.info=='mine' or contact.bodyB.info=='mine' then
            sound(SOUND_EXPLODE, 50)
        end
    end
end

So the code is here or here.

Try it and see. I hope you agree it’s really not too scary.

Advertisement

From → Physics

11 Comments
  1. goblins2013 permalink

    Thanks for your tutorials – I’m new with codea, so this is a great help for me!
    One thing to mention: seems as you didn’t call your function CreateWalls() – I put this call into setup and it works fine!

    • Thank you for the kind words. I checked my code for post 6, and it does include the CreateWalls function in setup, so I’m not sure how the problem arose.

  2. goblins2013 permalink

    Sorry – it was my fault… I always work through the tutorials without looking at the posted code – I feel I am learning more without copy and paste. This way, I surely make mistakes, but fixing them, means more learning 😉 ! Thanx again for sharing your knowledge!

  3. Paul permalink

    Thanks for these tutorials. They are very helpful.
    I can’t seem to get the walls function to work. I know I’m missing something because it only is coded to make one wall. So, I just did this instead:
    local w1=physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
    w1.restitution=0
    local w2=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
    w2.restitution=0.9
    local w3=physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT))
    w3.restitution=0.2
    local w4=physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT))
    w4.restitution=0.7

    It works, but what am I missing?

    Also, this error occurs frequently:
    attempt to index field ‘bodyA” (a nil value)

    • I have two functions. One function, CreateWall, just makes one wall, and the other function, CreateWalls (NB plural, it’s a different function) uses CreateWall to make each of the four walls in turn.

      So maybe you were just looking at CreateWall. Btw, the reason I ave two functions is that whenever you start repeating lines of code, eg all the settings for the physics object, it’s good practice to take those lines into a function. Try not to repeat code if you can help it.

      Doing it your way is fine, though.

      I’m not sure why you’re having errors. Is that with my code or your version of my code? If its your own code, you can send it to me (ignatz on the Codea forum) and I’ll look at it.

  4. Emil permalink

    Sorry for asking but can you explain this code p_rect = physics.body(POLYGON,
    vec2(-rect_width / 2, -rect_height / 2),
    vec2(-rect_width / 2, rect_height / 2),
    vec2(rect_width / 2, rect_height / 2),
    vec2(rect_width / 2, -rect_height / 2) )

    What do vac2 and POLYGON stand for and what is there purpose? And why do you need one for every corner? And why do yo need to divide in 2? Because you do that on the circle too. And what stand p_rect for?

    • wow.

      If you’re asking those questions, then you don’t understand variables, physics, vectors, …

      You aren’t anywhere near ready for this project. First you need to learn something about the Lua programming language and Codea. When I started, I spent a month learning the basic language and writing very small programs. It took me over six months to be able to write programs like this.

      So you need to start with very simple programs, and practise.

  5. Emil permalink

    Yes I understand that but I don’t know where I Should begin because I have read you Ebooks about lua and codea, have you some good tips where I can begin? Because I have start reading the lua language but I don’t know what I should start with?

    • Start with really simple programs. Forget about drawing anything until you understand how to use variables, for loops, if statements, and tables. For example, write a program that adds the numbers 1 to 100, and prints the answer.

      Read other people’s code (eg dave1707 – he writes simple programs in the forum) and try to understand it.

      Until you can do these simple things, there is no point trying to write your own game.

  6. Anonymous permalink

    Hey Coolcodea! loving this page it is excellent for learning, I have done a bit of C, bit of swift and even some hopscotching!!.. by no mean would i call myself proficient but am using your tuts to learn codea, so far has been perfect for my “know a little bit” knowledge of programming!!.

    Just thought I’d let you know that the walls weren’t working for me and it was driving me nuts working out why!!, I finally worked out that the calling the CreatWalls function does not appear on the wordpress coding but is included in the links to the code!

    Excellent page and please keep it up!

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: