Is there a quick way to identify bodies in the collide function?

Hi,

I am new to Codea and prototyping a bit on the physics functions. Now I have three types of bodies on the screen, each about 10 objects. I want to find out, if one type touches another type to execute an action then. My current solution is to iterate through all bodies in my list and compare with bodyA and bodyB. But I think, this could slow down the program when there are too many objects on the screen. Is there a better way to do that?

I have seen the “info” on the body, but it seems to be an internal number? I tried to set it to an ID and check it then in the collide function, but it did not work.

Also, the “sensor” property is not clear to me. It makes no difference if I set it to true or false, I get collision information always?

The best solution for me would be to add the pointer to my object class to a user property in the body to access it directly in the collide function, but I havent seen a way to do that.

Thanks,
Kilam.

I’ve tried to use body.info as well, and didn’t work either. iirc John from TTL said it was a bug.

I ended up just keeping a table that maps my objects to physics bodies. Here’s an example

https://github.com/ruilov/CargoBot/blob/master/StagePhysics.lua#L107

and then collide just looks it up

https://github.com/ruilov/CargoBot/blob/master/StagePhysics.lua#L85

(incidentally sometimes I got problems because either bodyA or bodyB wasn’t found on my table. Might be a problem with my code, but I conjecture the physics api has issues with tracking pointer to objects which causes both this and the problem with info)

Edit: http://twolivesleft.com/Codea/Talk/discussion/612/physics.body.info

Thanks, so i have to iterate, which was my fallback solution. But your code was very helful: I did not code in lua yet, so i didnt know that i can search a list by simply use the []. I assume that is much faster than iterating and comparing on my own. But I have to keep a second list then, with my other information on that object. Or would it be possible to have a list with key value pairs, where the key is the body and the value is my own class for that body?

Yea, it’s possible to use key value pairs, with a lua table. Just do tab = [] and tab[key] = value. Key can be almost anything you want, physics bodies, whatever. The example that I gave uses that, rather than lists, because it’s faster. It doesn’t have to iterate through all the elems. You give it the key and it knows how to find the value

KilamMalik

Look at this program that I wrote. It’s a random pinball example and it uses bodyA and bodyB.

The program is at: http://gist.github.com/2943054

Dave

body.info should work now, but I don’t think you can set it to a primitive value, rather you need to set it to a table. I’ll need to check.

Edit:
I’ve just checked one of my example projects and it does seem to work perfectly well but you just need to use tables in body.info not numbers or strings

Here’s an example project that uses body.info for collision logic in a game similar to HammerFight (you fly a ship attached to a big spikey ball and smash monsters).

https://gist.github.com/2985825

Here’s a video of it:
http://www.youtube.com/watch?v=H4ilC0oMafs

Thanks for all your feedback. John, I tried to use the body.info again with Codea 1.4.1 and now it works for me. But I possibly found a bug in Codea which might be interesting to fix. Or I have a bug in my code and I would be glad to get a hint. I stripped down the code to only contain the problem.

I create three types of objects: Balls, Catchers and Walls. The Balls and Catchers use the .info to store the class. In the collide function it checks, if a Ball and a Catcher collide and then print “Catched.”.

But when a Ball touches the wall, which has an emtpy .info (nil), then Codea completely crashes. But I check for nil in the collide function.

Just start the code and wait until the balls fall down. I’m sure this could be solved by having the wall done as class and a filled info, but I think it should not crash in the way it is done now, thats why i post it.

Ball = class()

function Ball:init(radius, col, x, y)
    -- you can accept and set parameters here
    self.what = "Ball"
    self.col = col

    self.body = physics.body(CIRCLE, radius)
    self.body.info = self
    self.body.type = DYNAMIC
    self.body.x = x
    self.body.y = y
    self.body.interpolate = true
    self.body.mass = radius / 100
    self.body.restitution = 0.4
    self.body.sleepingAllowed = false
    self.body.bullet = true
    --self.body.friction = 1
end

function Ball:draw()
    -- Codea does not automatically call this method

    pushMatrix()
        translate(self.body.x, self.body.y)
        rotate(self.body.angle)
        r = self.body.radius * 2
            stroke(0, 0, 0, 255)
            fill(self.col)
            ellipse(0, 0, r)
            fill(0,0,0,255)
            ellipse(r / 4, r / 4, r / 10)
    popMatrix()              
end

function Ball:touched(touch)
    -- Codea does not automatically call this method
end

Catcher = class()

function Catcher:init(w, h, col, x, y)
    -- you can accept and set parameters here
    self.what = "Catcher"
    self.col = col
    self.w = w
    self.h = h
    self.x = x
    self.y = y

    self.body = physics.body(POLYGON, vec2(-w/2, -h/2), vec2(-w/2, h/2), vec2(w/2, h/2), vec2(w/2, -h/2))
    self.body.info = self
    self.body.x = x
    self.body.y = y
    self.body.type = STATIC
    --self.body.fixedRotation = true
    self.body.restitution = 0
    self.body.sleepingAllowed = false
    self.body.interpolate = true
    self.body.gravityScale = 0
    self.body.mass = 1
    self.body.bullet = true
    --racket.friction=0
end

function Catcher:draw()
    -- Codea does not automatically call this method

    -- Reset position
    --self.body.x = self.x
    --self.body.y = self.y

    stroke(0,0,0,255)
    fill(self.col)
    pushMatrix()
        translate(self.body.x, self.body.y)
        rotate(self.body.angle)
            rect(-self.w/2, -self.h/2, self.w, self.h)
    popMatrix()
end

function Catcher:touched(touch)
    -- Codea does not automatically call this method
end


--# Main

-- Use this function to perform your initial setup
function setup()
    supportedOrientations(LANDSCAPE_LEFT)
    --backingMode(RETAINED)
    backingMode(STANDARD)
    displayMode(STANDARD)
    --displayMode(FULLSCREEN)
    parameter("CreationDelta", 2, 10, 5)

    balls = {}
    catchers = {}
    lastCreatedTime = 0
    watch("lastCreatedTime")
    watch("ElapsedTime")

    goal = Catcher(200, 25, color(30, 150, 30, 128), WIDTH/2, HEIGHT * 1/32)
    goal.body.angle = 2
    table.insert(catchers, goal)
    
    wall2 = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
    wall2.type = STATIC
    wall2.info = nil
end

function collide(contact)
    if contact.bodyA == nil or contact.bodyB == nil then
        return nil end
    
    local infoA = contact.bodyA.info
    local infoB = contact.bodyB.info

    -- check for collision
    if infoA and infoB and contact.state == BEGAN then
        print(string.format("%s : %s", contact.bodyA.info.what, contact.bodyB.info.what))
        if contact.bodyA.info.what == "Ball" then
            if contact.bodyB.info.what == "Catcher" then
                print("Catched.")
            end
        elseif contact.bodyB.info.what == "Ball" then
            if contact.bodyA.info.what == "Catcher" then
                print("Catched.")
            end
        end
    end
end

-- This function gets called once every frame
function draw()
    --tint(255, 255, 255, 5)
    background(255, 255, 255, 255)

    stroke(0, 0, 0, 255)
    strokeWidth(2)

    if ElapsedTime > (lastCreatedTime + CreationDelta) then
        lastCreatedTime = ElapsedTime
        s=50
        
        -- Balls should not be able to stack, so create a small random x - translation.
        rnd = math.random() - 0.5
        newBall = Ball(s, color(math.random(0,255), math.random(0,255), math.random(0,255), 128), WIDTH / 2 + rnd, HEIGHT - 25)
        table.insert(balls, newBall)
        currentBall = newBall
    end
        
    for i = 0, table.maxn(balls) do
        if balls[i] == nil then
        else
            balls[i]:draw()
        end
    end
    
    
    for i = 0, table.maxn(catchers) do
        if catchers[i] == nil then
        else
            catchers[i]:draw()
        end
    end
end

Your code will be properly formatted and easier to read if you sandwich it between two ~~~, instead of . For example:

this is some code

Thanks, toadkick