Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

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

edited June 2012 in Questions Posts: 123

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.

Comments

  • edited June 2012 Posts: 447

    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

  • Posts: 123

    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?

  • Posts: 447

    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

  • dave1707dave1707 Mod
    edited June 2012 Posts: 7,676

    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

  • JohnJohn Admin Mod
    edited June 2012 Posts: 575

    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

  • JohnJohn Admin Mod
    edited June 2012 Posts: 575

    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:

  • edited June 2012 Posts: 123

    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
    
  • edited June 2012 Posts: 580

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

    this is some code
    
  • Posts: 123

    Thanks, toadkick

Sign In or Register to comment.