Collision code, HELP !!

I want to know how to collide things( for example: when a character collides with a ball then the character goes the other way ).

You can use the physics engine which will calculate everything very close to how it would react in the real world. Check out the physics lab examples to get an idea of how to do this.

For making a character react appropriately to collisions, you often don’t want to use the physics engine, though. Check out the Brickout example for a lesson on how to manually check for collisions and change an objects direction.

Here is a small example to get you started. A lot of this you can ignore, but look at the physics documentation and this example to get an idea of what you need. The best way to learn is to take an example, modify it and see what happens. As always, if you have more questions, we’re all here to help.


function setup() 
    b=65    -- starting value for letter A
    
    c1 = physics.body(CIRCLE,5)     -- create boundary for the letter
    c1.x=295
    c1.y=900
    c1.restitution=.8
    c1.gravityScale=1
    
    c2 = physics.body(CIRCLE,50)    -- create boundary for 1st circle
    c2.type=STATIC
    c2.x=300
    c2.y=600
    
    c3 = physics.body(CIRCLE,50)    -- create boundary for 2nd circle
    c3.type=STATIC
    c3.x=120
    c3.y=400
end

function draw()
    a=string.char(b)    -- convert value to a letter
    
    background(30, 30, 30, 25)
    
    stroke(255)
    strokeWidth(1)
    noFill()
    ellipse(c2.x,c2.y,100,100)    -- draw the 1st circle
    ellipse(c3.x,c3.y,100,100)    -- draw the 2nd circle    
    
    fill(255)
    fontSize(30)
    text(a,c1.x,c1.y)   -- draw the letter
    
    -- get next letter when previous gets below y position of 20
    if c1.y<20 then
        c1.y=900
        c1.x=295
        c1.linearVelocity=vec2(0,0)
        b = b + 1
        if b>90 then
            b=65
        end
    end
end

@dave1707 Hey thanks a lot Dave! This very short piece of code is really useful for a newbe as myself. Several very short codes like this are better than a big, comprehensive , accurate but … scary piece of code: it shows Codea is really an easy platform and one can quickly have fun with it. Thanks!

@Rakarinn i have made this exemple of colliding particles with two bumpers, right from the exemple of Dave1707, in a couple hours. This is my first Codea program and i am rather proud of the result (remember, i am a newbe, so it doesn’t take much to make me happy!)
@dave1707 As you can see you quick exemple really helped me to go a step further, and really quick! Thanks a lot!

– Collision

function setup()

-- create balls 
NUMBALLS = 10
SPEED0 = 1000
ball = {}
for i=0,NUMBALLS do
    ball[i] = physics.body(CIRCLE,20) 
    ball[i].x = math.random(WIDTH/2) + WIDTH/4
    ball[i].y = math.random(HEIGHT/2) + HEIGHT/4
    ball[i].restitution = .9
    ball[i].gravityScale = 0
    ball[i].linearVelocity=vec2(math.random(SPEED0)-SPEED0/2,math.random(SPEED0)-SPEED0/2)
end
 
c2 = physics.body(CIRCLE,50)    -- create boundary for 1st circle
c2.type=STATIC
c2.x=WIDTH/3
c2.y=HEIGHT/3
c2.restitution=2

c3 = physics.body(CIRCLE,50)    -- create boundary for 2nd circle
c3.type=STATIC
c3.x=WIDTH/3*2
c3.y=HEIGHT/3
c3.restitution=2

-- create borders
local w = 5
b0 = physics.body(POLYGON, vec2(0,w), vec2(0,0), vec2(WIDTH,0), vec2(WIDTH,w))
b0.type = STATIC
b1 = physics.body(POLYGON, vec2(0,0), vec2(w,0), vec2(w,HEIGHT), vec2(0,HEIGHT))
b1.type = STATIC
b2 = physics.body(POLYGON, vec2(WIDTH - w,0), vec2(WIDTH,0), vec2(WIDTH,HEIGHT), vec2(WIDTH - w,HEIGHT))
b2.type = STATIC
b3 = physics.body(POLYGON, vec2(0,HEIGHT), vec2(0,HEIGHT - w), vec2(WIDTH,HEIGHT - w), vec2(WIDTH,HEIGHT))
b3.type = STATIC    

end

function draw()

background(30, 30, 30, 25)

stroke(255)
strokeWidth(1)
noFill()
ellipse(c2.x,c2.y,100,100)    -- draw the 1st circle
ellipse(c3.x,c3.y,100,100)    -- draw the 2nd circle    

fill(255, 13, 0, 255)
for i=0,NUMBALLS do
    ellipse(ball[i].x,ball[i].y,40,40)    -- draw the circle
end

end

Ooops! I hadnt read about the ‘three tilde’ format around the code.

Sorry


-- Collision

function setup() 

    -- create balls 
    NUMBALLS = 10
    SPEED0 = 1000
    ball = {}
    for i=0,NUMBALLS do
        ball[i] = physics.body(CIRCLE,20) 
        ball[i].x = math.random(WIDTH/2) + WIDTH/4
        ball[i].y = math.random(HEIGHT/2) + HEIGHT/4
        ball[i].restitution = .9
        ball[i].gravityScale = 0
        ball[i].linearVelocity=vec2(math.random(SPEED0)-SPEED0/2,math.random(SPEED0)-SPEED0/2)
    end
     
    c2 = physics.body(CIRCLE,50)    -- create boundary for 1st circle
    c2.type=STATIC
    c2.x=WIDTH/3
    c2.y=HEIGHT/3
    c2.restitution=2
    
    c3 = physics.body(CIRCLE,50)    -- create boundary for 2nd circle
    c3.type=STATIC
    c3.x=WIDTH/3*2
    c3.y=HEIGHT/3
    c3.restitution=2

    -- create borders
    local w = 5
    b0 = physics.body(POLYGON, vec2(0,w), vec2(0,0), vec2(WIDTH,0), vec2(WIDTH,w))
    b0.type = STATIC
    b1 = physics.body(POLYGON, vec2(0,0), vec2(w,0), vec2(w,HEIGHT), vec2(0,HEIGHT))
    b1.type = STATIC
    b2 = physics.body(POLYGON, vec2(WIDTH - w,0), vec2(WIDTH,0), vec2(WIDTH,HEIGHT), vec2(WIDTH - w,HEIGHT))
    b2.type = STATIC
    b3 = physics.body(POLYGON, vec2(0,HEIGHT), vec2(0,HEIGHT - w), vec2(WIDTH,HEIGHT - w), vec2(WIDTH,HEIGHT))
    b3.type = STATIC    
end

function draw()
 
    background(30, 30, 30, 25)
    
    stroke(255)
    strokeWidth(1)
    noFill()
    ellipse(c2.x,c2.y,100,100)    -- draw the 1st circle
    ellipse(c3.x,c3.y,100,100)    -- draw the 2nd circle    
    
    fill(255, 13, 0, 255)
    for i=0,NUMBALLS do
        ellipse(ball[i].x,ball[i].y,40,40)    -- draw the circle
    end

end


@Jmv38

I’m glad I could help. I find small examples that get to the point are easier to follow and learn from than large ones that do a lot of other things. As you figured out, it doesn’t take a lot of code to do interesting things. If you’re interested in another example along the same line, here is a program I wrote back in June.


-- Random PinBall by Dave1707

function setup()
    displayMode(FULLSCREEN)
    
    -- define variables and tables
    cx=0
    cy=0
    limit=150   
    tab1={}
    tab2={}
    
    create()    -- set table values
    
    -- set pinball values
    circ1 = physics.body(CIRCLE,5)
    circ1.x=300
    circ1.y=HEIGHT-50
    circ1.gravityScale=.6
    circ1.restitution=1

    -- set line values   
    line1 = physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
    line2 = physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT))
    line3 = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
    line4 = physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT))     
end

function create()
    -- set initial values for pins in tables 
    for x=1,limit do
        tab1[x] = physics.body(CIRCLE,10)  
        tab1[x].x = math.random(WIDTH)
        tab1[x].y = math.random(HEIGHT)
        tab1[x].type = STATIC
        tab2[x]=0    -- 0=pin not hit, 1=pin was hit
    end       
end

function collide(contact)
    -- check for collision 
    if contact.state == BEGAN then
        cx=contact.bodyA.x    -- x position of hit pin
        cy=contact.bodyA.y    -- y position of hit pin
        -- restart pinball when at bottom of screen
        if circ1.y < 20 then
            circ1.y = HEIGHT-50
            circ1.x = math.random(WIDTH)
        end
    end   
end

function draw()
    background(0, 0, 0) 

    -- draw pinball
    fill(255,0,0,255)
    ellipse(circ1.x,circ1.y,10,10)

    -- draw boundary lines    
    line(0,0,0,HEIGHT)  
    line(WIDTH,0,WIDTH,HEIGHT) 
    line(0,0,0,WIDTH)
    line(0,HEIGHT,WIDTH,HEIGHT)
    
    -- draw flashing pins or white pins each draw cycle
    for x=1,limit do
        -- check which pin was hit
        if cx == tab1[x].x and cy == tab1[x].y then
            tab2[x] = 1    -- set table for hit pin
            cx=0           -- clear values         
            cy=0
        end
        
        fill(255)                -- set color to white
        if tab2[x] > 0 then      -- pin was hit, set random color
            fill(math.random(255),math.random(255),math.random(255),255)
        end
        
        ellipse(tab1[x].x,tab1[x].y,20)    -- draw pins       
    end 

    -- draw credits    
    fill(0, 252, 0, 255) 
    text("Random PinBall by Dave1707",WIDTH/2,HEIGHT/2)   
end

@dave1707 Thanks! Some more functions i needed are in this exemple, yep!

Lots of helpful stuff here however how would you do a game over screen when object gets hit. Any advice would be appreciated.

@Frazamataza

Not exactly sure what you’re after. Maybe something here will give you an idea.


function setup()
    displayMode(FULLSCREEN)
    showShip=true
    explodeShip=false
    endGame=false
    x=0
    e=30
end

function draw()
    background(40, 40, 50)
    
    x = x + 1        -- simulate game
    
    if showShip then
        ship()
        if x==100 then        -- simulate ship being hit
            explodeShip=true 
        end
    end
    if explodeShip then
        explode()
    end
    if endGame then
        endOfGame()
    end
    
end

function ship()
    sprite("SpaceCute:Rocketship",350,500)    
end

function explode()
    e = e + 2
    sprite("Tyrian Remastered:Explosion Huge",350,500,e,e)  
    if e>500 then
        showShip=false
        explodeShip=false
        endGame=true
    end
end

function endOfGame()
    fill(255)
    font("Baskerville-SemiBold")
    fontSize(40)
    text("End of Game",WIDTH/2,HEIGHT/1.3)
    text("Press New Game for another game",WIDTH/2,HEIGHT/1.5)
    fill(255,0,0)
    text("NEW GAME",WIDTH/2,HEIGHT/1.8)
end

My program keeps crashing (codea closes) when i try to use the body.info property to store a value like a number or a string. Can someone tell me how to use this property? Thanks
@dave1707 @Simeon

@Jmv38

Body.info uses a table. I don’t think there’s anything that says that, but this example works.


function setup()
    tab={"qwerty","asdfg","zxcvb"}

    circle = physics.body(CIRCLE,10)
    circle.info=tab

    print(circle.info)
    print()

    for x,y in pairs(circle.info) do
        print(x,y)
    end

end

thanks dave however i was looking for if an object hits something it then explodes and then game over screen. I believe you helped me before on the math.randomseed topic, and this is for that same game I have managed to get it to explode but can not figure out how to then get game over screen. I already have a game over screen just wondering how you get to it. Sorry if I wasn’t clear before.

@dave1707 thanks for this info. @Simeon maybe the fact that body.info is a table should be added in the refrence? Without this information i couldnt make it work. By the way, i have the feeling that in a contact involving contact.bodyA and contact.bodyB, bodyA is always the physics object that was defined first in the code. This is useful to know (if true) because only half the number of tests have to be made during a collision.


As an example for others who need a hand to start with collisions, here is my last version of the code: access to body info, collision management, sounds… Woks nicely.

-- Collision

function setup() 

    -- create balls 
    NUMBALLS = 10
    SPEED0 = 1000
    ball = {}
    ballInfo = {}
    for i=0,NUMBALLS do
        ball[i] = physics.body(CIRCLE,20) 
        ball[i].x = math.random(WIDTH/2) + WIDTH/4
        ball[i].y = math.random(HEIGHT/2) + HEIGHT/4
        ball[i].restitution = 0.9
        ball[i].gravityScale = 0
        ball[i].linearVelocity=vec2(math.random(SPEED0)-SPEED0/2,math.random(SPEED0)-SPEED0/2)
        ball[i].info = {} -- body.info is a table and has to be initialized otherwise ..bug!
        ball[i].info.state = 0
        ball[i].info.type = "ball"
    end
     
    c2 = physics.body(CIRCLE,50)    -- create boundary for 1st circle
    c2.x=WIDTH/3
    c2.y=HEIGHT/2
    c2.restitution=0.9
    c2.gravityScale = 0
    c2.info = {}
    c2.info.state = 0
    c2.info.type = "target"
    
    c3 = physics.body(CIRCLE,50)    -- create boundary for 2nd circle
    c3.type=STATIC
    c3.x=WIDTH/3*2
    c3.y=HEIGHT/2
    c3.restitution=4
    c3.info = {}
    c3.info.state = 0
    c3.info.type = "bumper"
    
    -- create borders
    local w = 5
    b0 = physics.body(POLYGON, vec2(0,w), vec2(0,0), vec2(WIDTH,0), vec2(WIDTH,w))
    b0.type = STATIC

    b1 = physics.body(POLYGON, vec2(0,0), vec2(w,0), vec2(w,HEIGHT), vec2(0,HEIGHT))
    b1.type = STATIC

    b2 = physics.body(POLYGON, vec2(WIDTH - w,0), vec2(WIDTH,0), vec2(WIDTH,HEIGHT), vec2(WIDTH - w,HEIGHT))
    b2.type = STATIC

    b3 = physics.body(POLYGON, vec2(0,HEIGHT), vec2(0,HEIGHT - w), vec2(WIDTH,HEIGHT - w), vec2(WIDTH,HEIGHT))
    b3.type = STATIC    

end

function collide(contact)
    -- check for collision 
    if contact.state == ENDED then
       if contact.bodyA.info.type == "ball" then
         if contact.bodyB.info.type == "bumper" then
            contact.bodyA.info.state = 1
            contact.bodyB.info.state = 1
            sound(SOUND_HIT, 2652)
            -- print(contact.bodyB.info.type.."  "..contact.bodyA.info.type)
         end 
         if contact.bodyB.info.type == "target" then
            contact.bodyA.info.state = 2
            sound(SOUND_PICKUP, 2652)
            -- print(contact.bodyB.info.type.."  "..contact.bodyA.info.type)
         end 
       end 
    end   
end

function action(obj,val)
      -- print("contact: "..obj.info)
end


function draw()
 
    background(30, 30, 30, 25)
    
    stroke(255)
    strokeWidth(1)
    fill(0, 1, 255, 255)
    ellipse(c2.x,c2.y,100,100)    -- draw the 1st circle
      -- draw the 2nd circle    
    fill(255, 222, 0, 255)
    if c3.info.state==0 then 
        ellipse(c3.x,c3.y,100,100) 
    else
        ellipse(c3.x,c3.y,120,120) 
        c3.info.state = 0
    end
    

    for i=0,NUMBALLS do
        if ball[i].info.state == 0 then
            fill(255, 13, 0, 255)
        elseif ball[i].info.state == 1 then
            fill(255, 147, 0, 255)
        elseif ball[i].info.state == 2 then
            fill(255, 0, 236, 255)
        end
        ellipse(ball[i].x,ball[i].y,40,40)    -- draw the circle
    end

end

@Frazamataza

Is this something that you’re after. I added the circles to show you the collision areas. Play around with this to get an idea of what’s happening. There are collisions as soon as the program starts because I set the x,y values for s1, r1, and r2 to the same values in setup.

function setup() 
    x = WIDTH/2    
    y = HEIGHT/2     
    c = color(0, 0, 0, 255) 
    x1=0  
    y1=0  
    
    s1=physics.body(CIRCLE,30)    -- collision area around star
    s1.x=x
    s1.y=y
        
    r1=physics.body(CIRCLE,90)    -- collision area at back of ship
    r1.x=x
    r1.y=y
    
    r2=physics.body(CIRCLE,40)    -- collision area at front of ship
    r2.x=x
    r2.y=y       
end

function draw()    
    background(0, 0, 0, 225)
    
    x1=x1-5
    if x1<1 then
        rand()
    end

    sprite("SpaceCute:Star",x1,y1) -- x,y position of star
    s1.x=x1    -- x,y position of star collision area
    s1.y=y1
 
    sprite("SpaceCute:Rocketship",150,y) -- x,y position of ship
    r1.x=100    -- x,y position of both ship collision areas
    r1.y=y
    r2.x=230
    r2.y=y-10    -- -10 to adjust collision area down
    
    -- this just shows collision area circles, to be removed in game
    noFill()
    stroke(255)
    strokeWidth(4)
    ellipse(s1.x,s1.y,60,60)
    ellipse(r1.x,r1.y,180,180)
    ellipse(r2.x,r2.y-10,80,80)    -- -10 to adjust circle down
    -- 
end

function touched(touch) 
    x = x 
    y = touch.y 
end

function rand()
    y1=math.random(100,HEIGHT-100)
    x1=WIDTH
end

function collide(contact)
    if contact.state == BEGAN then
        print("collision")        -- collision occurs, add your code here 
    end   
end

On the example that you have where you have the letters bouncing off the balls, how would you code it so you can touch the ball and move it?

Starting here, I have some tutorials on bouncing things with and without physics
http://coolcodea.wordpress.com/2013/03/11/3-moving-an-object-around-the-screen/

. @Andrewsimpson4 I added the touched function so it allows you to move the balls. There are other ways of doing this, but I was in a hurry.


function setup() 
    b=65    -- starting value for letter A
    
    c1 = physics.body(CIRCLE,5)     -- create boundary for the letter
    c1.x=295
    c1.y=900
    c1.restitution=.8
    c1.gravityScale=1
    
    c2 = physics.body(CIRCLE,50)    -- create boundary for 1st circle
    c2.type=STATIC
    c2.x=300
    c2.y=600
    
    c3 = physics.body(CIRCLE,50)    -- create boundary for 2nd circle
    c3.type=STATIC
    c3.x=120
    c3.y=400
end

function draw()
    a=string.char(b)    -- convert value to a letter
    
    background(30, 30, 30, 25)
    
    stroke(255)
    strokeWidth(1)
    noFill()
    ellipse(c2.x,c2.y,100,100)    -- draw the 1st circle
    ellipse(c3.x,c3.y,100,100)    -- draw the 2nd circle    
    
    fill(255)
    fontSize(30)
    text(a,c1.x,c1.y)   -- draw the letter
    
    -- get next letter when previous gets below y position of 20
    if c1.y<20 then
        c1.y=900
        c1.x=295
        c1.linearVelocity=vec2(0,0)
        b = b + 1
        if b>90 then
            b=65
        end
    end
end

function touched(t)
    if math.abs(t.x-c2.x)<50 and math.abs(t.y-c2.y)<50 then
        c2.x=t.x
        c2.y=t.y
    end
    if math.abs(t.x-c3.x)<50 and math.abs(t.y-c3.y)<50 then
        c3.x=t.x
        c3.y=t.y
    end
end

Thant you so much one more thing how can I make the circles to a rectangle because the physics.body is still set to CIRCLE and I could not figure out how to change that.

. @Andrewsimpson4 I changed one of the circles to a square so you can compare the code for a circle and a square.


function setup() 
    b=65    -- starting value for letter A
    rectMode(CENTER)
    
    c1 = physics.body(CIRCLE,10)     -- create boundary for the letter
    c1.x=295
    c1.y=900
    c1.restitution=.8
    c1.gravityScale=1
    c1.sleepingAllowed=false    -- don't let letter sleep
    
    -- create a square physics body
    c2 = physics.body(POLYGON,vec2(-50,-50),vec2(-50,50),vec2(50,50),vec2(50,-50))
    c2.type=STATIC
    c2.x=300
    c2.y=600
   
    -- create circle physics body 
    c3 = physics.body(CIRCLE,50)
    c3.type=STATIC
    c3.x=120
    c3.y=400
end

function draw()
    a=string.char(b)    -- convert value to a letter
    background(30, 30, 30, 25)

    stroke(255)
    strokeWidth(2)
    noFill()
    rect(c2.x,c2.y,100,100)        -- draw square 
    ellipse(c3.x,c3.y,100,100)     -- draw circle    
    
    fill(255)
    fontSize(30)
    text(a,c1.x,c1.y)   -- draw the letter
    
    -- get next letter when previous gets below y position of 20
    if c1.y<20 then
        c1.y=900
        c1.x=295
        c1.linearVelocity=vec2(0,0)
        b = b + 1
        if b>90 then
            b=65
        end
    end
end

function touched(t)
    if math.abs(t.x-c2.x)<50 and math.abs(t.y-c2.y)<50 then
        c2.x=t.x
        c2.y=t.y
    end
    if math.abs(t.x-c3.x)<50 and math.abs(t.y-c3.y)<50 then
        c3.x=t.x
        c3.y=t.y
    end
end