Howdy, Stranger!

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

Multiple physics objects

edited April 2013 in Questions Posts: 372

I was making a small game for me to play when I'm bored and I came across an issue.
What I want to do is shoot bullets by clicking on the screen and it also happens that way.
But if I click quickly then the first bullet disappears and a new bullet is formed. I need to know how can I make the first bullet go on even after making a second one. I tried to see the inbuilt physics example, test 1, where he creates multiple polygons but I couldn't understand it.
Here is my code.

function setup()
    bullet = physics.body(CIRCLE,10)
end

function draw()
    background(0, 0, 0, 255)
    pushStyle()
    fill(255, 255, 255, 255)
    ellipse(bullet.x,bullet.y,10)
    popStyle()
end

function createBullet()
    bullet.x = x
    bullet.y = y
    bullet.linearVelocity = vec2(1000,0)
    bullet.restitution = 0
    bullet.type = DYNAMIC
end

function touched(touch)
    x = touch.x
    y = touch.y
    if touch.state == BEGAN then
        createBullet()
    end
end

Comments

  • IgnatzIgnatz Mod
    edited April 2013 Posts: 5,396

    Hi again, Saurabh

    You need to add your bullets to a table, so in set up you add

    bullets={}
    

    Then in createBullet you add at the end

    table.insert(bullets,bullet)
    

    Then in draw, you loop through your bullets

    for i,b in bullets do
       ellipse(b.x,b.y,10)
       --insert code here to adjust position of bullet for next time
        --then check if bullet is off screen
       if b.x<1 or b.x>WIDTH or b.y<1 or b.y>HEIGHT or [anything else you want to test] then
           b=nil --remove bullet from table
      end
    end
    
  • Posts: 372

    Thanks for the quick reply!
    But I'm getting an error stating "attempt to call table value" in function setup.
    Can you explain what you mean by inserting code to adjust position of next bullet
    I'm new to coding, I'm interested in it too, but a few things are just going a bouncer

  • Posts: 2,161

    This is untested, but I think it's what Ignatz meant.

    I suspect the error you got was due to a missing pairs.

    function setup()
        bullets = {}
    end
    
    function draw()
        background(0, 0, 0, 255)
        pushStyle()
        fill(255, 255, 255, 255)
        local dels = {}
        for k,v in ipairs(bullets) do
            ellipse(v.x,v.y,10)
            if v.x<1 or v.x>WIDTH or v.y<1 or v.y>HEIGHT then
               table.insert(dels,k,1)
            end
        end
        for _,v in ipairs(dels) do
            table.remove(bullets,v)
        end
        popStyle()
    end
    
    function createBullet(x,y)
        local bullet = physics.body(CIRCLE,10)
        bullet.x = x
        bullet.y = y
        bullet.linearVelocity = vec2(1000,0)
        bullet.restitution = 0
        bullet.type = DYNAMIC
        table.insert(bullets,bullet)
    end
    
    function touched(touch)
        if touch.state == BEGAN then
            createBullet(touch.x,touch.y)
        end
    end
    
  • IgnatzIgnatz Mod
    Posts: 5,396

    I hadn't noticed you were using physics objects. Try this code. Note I've moved the definition of bullet into createBullet, and made it local, so a new bullet is created each time. If you create your bullet in setup, then even if you add it to a table, you are adding the same old bullet.

    I might write a post about this because it is interesting.

    function setup()
        physics.gravity(0,0) -- turn gravity off
        bullets={}
    end
    
    function draw()
        background(0, 0, 0, 255)
        pushStyle()
        fill(255, 255, 255, 255)
        for i,b in pairs(bullets) do
       ellipse(b.x,b.y,10)
        --then check if bullet is off screen
       if b.x<1 or b.x>WIDTH or b.y<1 or b.y>HEIGHT then
           b=nil --remove bullet from table
      end
    end
        popStyle()
    end
    
    function createBullet()
        --create bullet in here
        local bullet = physics.body(CIRCLE,10)
        bullet.x = x
        bullet.y = y
        bullet.linearVelocity = vec2(100,0)
        bullet.restitution = 0
        bullet.type = DYNAMIC
        table.insert(bullets,bullet)
    end
    
    function touched(touch)
        x = touch.x
        y = touch.y
        if touch.state == BEGAN then
            createBullet()
        end
    end
    
  • Posts: 372

    Thanks guys it worked perfectly the both of them.

  • edited April 2013 Posts: 372

    I am into a new issue now what I did is that I added some ballons which rise from the bottom and we have to shoot those ballons using the bullets.
    I can make the ballons but I can't make them disappear properly I am using table.remove and collide(contact) as all of them are physics objects but I can't figure out how to give each ballon a unique name I tried out the following code but most of the times I hit one ballon and some other ballon pops and though the ballon disappears the physics object stays there and I also want the bullets to burst along with the ballon

    I used sound so that I can come to know when there's contact

    Here's the code

    function setup()
        physics.gravity(0,0)
        bullets={}
        ball = {}
        for i = 1,5 do
            ball[i] = Ballons()
            ball[i].info = "ball[i]"
        end
    end
    
    function draw()
        background(255, 255, 255, 255)
        pushStyle()
        fill(0, 0, 0, 255) -- drawing the bullets
        for i,b in pairs(bullets) do
        ellipse(b.x,b.y,10)
            if b.x<1 or b.x>WIDTH or b.y<1 or b.y>HEIGHT then
                b=nil
            end
        end
        popStyle()
        for i = 1,#ball do -- drawing the ballons
            pushStyle()
            fill(ball[i].ballon.colr)
            ellipse(ball[i].ballon.x, ball[i].ballon.y, ball[i].radius*2)
            popStyle()
        end
    end
    
    function createBullet()
        local bullet = physics.body(CIRCLE,5)
        bullet.x = x
        bullet.y = y
        bullet.linearVelocity = vec2(1000,0)
        bullet.restitution = 0
        bullet.type = DYNAMIC
        bullet.info = "bullet"
        table.insert(bullets,bullet)
    end
    
    function touched(touch)
        x = touch.x
        y = touch.y
        if touch.state == BEGAN then
            createBullet()
        end
    end
    
    function collide(contact)
        if contact.bodyA.info == "ball[i]" or contact.bodyB.info == "ball[i]" and
           contact.bodyA.info == "bullet" or contact.bodyB.info == "bullet" then
            if contact.state == BEGAN then
                sound(DATA, "ZgNAfj01Pzc2Qz1AnatePohA3T0LSTE+YgB/fz54NlVoQ0A6")
                table.remove(ball,i,ball[i])
                table.remove(bullets,bullet)
            end
        end
    end
    
    
            Ballons = class()
    
    function Ballons:init(x,y,r,c,lv)
        self.radius = r or math.random(25,50)
        self.ballon = physics.body(CIRCLE,self.radius)
        self.ballon.x = x or math.random(WIDTH/2,WIDTH)
        self.ballon.y = y or math.random(-HEIGHT/2,-self.radius)
        self.ballon.linearVelocity = lv or vec2(0,math.random(100,150))
        self.ballon.colr = c or color(math.random(255),math.random(255),math.random(255),math.random(100,150))
    end
    
  • Posts: 2,161

    You can edit your posts so there's no need to double post the code. I added the tildes to the first post and deleted (removed from view, nothing gets truly deleted) the second. Hope that's okay.

  • Posts: 372

    It's completely fine :)

  • IgnatzIgnatz Mod
    edited April 2013 Posts: 5,396

    See below

    1. when you are deleting objects in tables, it's probably best to use the for..pairs approach when looping, because the usual for i=1,.. loop may not work properly once there are gaps in the table

    2. you need to destroy the physics objects with the destroy function before setting them to nil, otherwise they will live on
      however..

    3. destroying physics objects in the collide function seems to cause Codea to crash, so I've simply stored the details and done the deletion in draw
    function setup()
        physics.gravity(0,0)
        bullets={}
        ball = {}
        for i = 1,5 do
            ball[i] = Ballons()
        end
    end
    
    function draw()
        background(255, 255, 255, 255)
    
        if collision~=nil then        ------------------- see note 3. above
            ball[collision[1]].ballon:destroy()   --- see note 2 above
            table.remove(ball,collision[1])
            bullets[collision[2]]:destroy()
            table.remove(bullets,collision[2])
            collision=nil
        end
    
        pushStyle()
        fill(0, 0, 0, 255) -- drawing the bullets
        for i,b in pairs(bullets) do
        ellipse(b.x,b.y,10)
            if b.x<1 or b.x>WIDTH or b.y<1 or b.y>HEIGHT then
                b=nil
            end
        end
        popStyle()
    
        for i,b in pairs(ball) do -- drawing the ballons
            pushStyle()
            fill(b.colr)
            ellipse(b.ballon.x, b.ballon.y, b.radius*2)
            popStyle()
        end
    end
    
    function createBullet()
        local bullet = physics.body(CIRCLE,5)
        bullet.x = x
        bullet.y = y
        bullet.linearVelocity = vec2(1000,0)
        bullet.restitution = 0
        bullet.type = DYNAMIC
        bullet.info = "bullet"
        table.insert(bullets,bullet)
    end
    
    function touched(touch)
        x = touch.x
        y = touch.y
        if touch.state == BEGAN then
            createBullet()
        end
    end
    
    function collide(contact) 
        if contact.bodyA.info~=nil and contact.bodyB.info~=nil then
            for i,b in pairs(ball) do
                if b.ballon==contact.bodyA or b.ballon==contact.bodyB then
                    for j,bb in pairs(bullets) do
                        if bb==contact.bodyA or bb==contact.bodyB then
                            sound(DATA, "ZgNAXS4wQEBAQEBA/9iePiN3mD64nKs+cgBAf0BAQEBAb0BA  ")
                            collision={i,j}   -- see note 3 above
                        end
                    end
                end
            end
        end      
    end
    
    Ballons = class()
    
    function Ballons:init(x,y,r,c,lv)
        self.radius = r or math.random(25,50)
        self.ballon = physics.body(CIRCLE,self.radius)
        self.ballon.x = x or math.random(WIDTH/2,WIDTH)
        self.ballon.y = y or math.random(-HEIGHT/2,-self.radius)
        self.ballon.linearVelocity = lv or vec2(0,math.random(100,150))
        self.ballon.info="ball"
        self.colr = c or color(math.random(255),math.random(255),math.random(255),math.random(100,150))
    end
    
  • dave1707dave1707 Mod
    Posts: 7,195

    .@Ignatz, @Saurabh There is still one more thing you need to do, that's to destroy the physics.bodies that were removed from the table. If you shoot at a ballon and remove it, even though you don't see it anymore, the bullets still bounce off it and the program crashes after awhile.

  • IgnatzIgnatz Mod
    Posts: 5,396

    yep, I fixed that above. Had a bit of trouble with Codea crashing if I destroyed objects in the collide function.

  • Posts: 372

    Thanks for the post Ignatz.
    But the code you have shared in the post is not working properly, the code over here is working perfectly fine I can't find out what you have missed out. I think you should paste the code from here to your post.
    And by the way I'm a guy ;) and 16

  • IgnatzIgnatz Mod
    edited April 2013 Posts: 5,396

    Oops!! I'll fix that.

    Done, I hope.

  • dave1707dave1707 Mod
    Posts: 7,195

    . @Ignatz Another way you could destroy the objects is to set up a variable like self.ballon.destroy and bullet.destroy. Set them to false when each object is created, then set them to true when they need to be destroyed. In the draw function, if they need to be destroyed, destroy them and remove them from the table, else draw them.

  • IgnatzIgnatz Mod
    Posts: 5,396

    @dave1707 absolutely. I took the suggestion of a table (or "stack") of objects to be destroyed from one of the help pages, but your way looks good, too.

  • edited April 2013 Posts: 372

    How can we keep track of the number of bullets that don't hit the ballon and go beyond the WIDTH of the screen if I make a function to increase count by one then if its called the number keeps on increasing (60 per second)

    I tried it using this class


    Point = class() function Point:init(score) self.score = score or 0 end function Point:ScoreIncrease() for i,b in pairs(bullets) do if b.x<1 or b.x>WIDTH or b.y<1 or b.y>HEIGHT then self.score = self.score + 1 end end end

    The inbuilt codes like invader were too complicated for me to understand.
    And I had parameter.watch in setup to check value

  • IgnatzIgnatz Mod
    Posts: 5,396

    Why do you need a class? Just put your counter into draw (you're already checking if the bullet is offscreen in there)

  • Posts: 372

    If I put it in draw the value keeps on increasing even if one bullet passes through
    I use count = count +1.
    How should I make counter stop??

  • IgnatzIgnatz Mod
    Posts: 5,396

    Try this, see the line marked ADD THIS. This should only increase when a bullet goes off the edge.

    function draw()
    
        ....other code
    
        pushStyle()
        fill(0, 0, 0, 255) -- drawing the bullets
        for i,b in pairs(bullets) do
        ellipse(b.x,b.y,10)
            if b.x<1 or b.x>WIDTH or b.y<1 or b.y>HEIGHT then
                b=nil
                score=score+1.     -- ADD THIS
            end
        end
        popStyle()
    
        .....other code....
    end
    
  • Posts: 372

    That didn't work :( out it increased the value infinitely
    But I found out a solution I made a table called score and ADDED THIS
    And btw "b =nil" didn't remove the bullet from the table (found out by parameter.watch("#bullets") so I also changed that to "table.remove(bullets, 1, b")

    function draw()
    
        ....other code
    
        pushStyle()
        fill(0, 0, 0, 255) -- drawing the bullets
        for i,b in pairs(bullets) do
        ellipse(b.x,b.y,10)
            if b.x<1 or b.x>WIDTH or b.y<1 or b.y>HEIGHT then
                table.remove(bullets,1,b)
                table.insert(score, 1)     -- ADDED THIS
            end
        end
        popStyle()
    
        .....other code....
    end
    
    

    It increased a value in the table since I added only one element '1' by one only and I could find the value using parameter.watch("#score")

    Now I have one more question.
    1) If I add a value to the table what position is it stored at the last position or the first position or a random position if I haven't mentioned the position?

    2) if I want to remove a value from the last instead of the first position want should i put in table.remove
    Example table.remove(bullets, ??, b) what should be there for last position

  • IgnatzIgnatz Mod
    Posts: 5,396

    Actually, the code below works perfectly for me, in scoring

    for i,b in pairs(bullets) do
           if b.x<1 or b.x>WIDTH or b.y<1 or b.y>HEIGHT then
                b:destroy()
                table.remove(bullets,i) 
                score=score+1
           else 
                fill(0)
                ellipse(b.x,b.y,10) 
            end
        end
    

    Lua stores all table values as key-value pairs, in no particular order. It's too hard to explain this properly in a forum post.

    Tables are very important in Codea, so I recommend you look at the Lua documentation, and some tutorials or explanations on the Internet, I have a tutorial as well, which refers to another good one by Reefwing.

  • edited April 2013 Posts: 372

    I dont know why it didnt work for me! This is the whole game till now if you want to check it out not that difficult but okay to pass your time. I'm still building it up but here's where I've reached till


    function setup() physics.pause() physics.gravity(0,0) score = {} bullets = {} number = {} ball = {} for i = 1,5 do ball[i] = Ballons() end sound(DATA, "ZgBAKgBLQFRAQEBAAAAAAK5T+j46fh4/UwBAf0BAQEBAZEBA") parameter.watch("#number") parameter.watch("#score") t = 300 end function draw() t = t - 1 if t>=0 then background(255, 255, 255, 255) pushStyle() font("MarkerFelt-Thin") fontSize(25) fill(0, 199, 255, 255) text("no more than 5 lives", WIDTH - 380, HEIGHT - 50) text("waste an arrow or miss a balloon and lose a life", WIDTH - 250, HEIGHT - 75) popStyle() pushStyle() fontSize(100) font("SnellRoundhand-Black") fill(192, 26, 18, 117) text("BALLONS", WIDTH/2, HEIGHT/2) popStyle() pushStyle() font("AmericanTypewriter-Bold") fontSize(20) text("(inspired by the old windows game)", WIDTH/2, HEIGHT/2 - 75) text("game begins in 5 seconds", WIDTH/2,HEIGHT/2 - 95) popStyle() pushStyle() font("MarkerFelt-Thin") fontSize(25) fill(0, 199, 255, 255) text("Touch behined this line to shoot arrows", 350, HEIGHT - 250) strokeWidth(3) stroke(0, 200, 255, 255) lineCapMode(ROUND) line(160,HEIGHT-250,75,HEIGHT-250) line(75,HEIGHT-250,85,HEIGHT-245) line(75,HEIGHT-250,85,HEIGHT-255) popStyle() pushStyle() strokeWidth(2) stroke(81, 31, 31, 255) line(50,0,50,HEIGHT) popStyle() end if t<= 0 then background(255, 255, 255, 255) strokeWidth(2) stroke(81, 31, 31, 255) line(50,0,50,HEIGHT) physics.resume() end if collision~=nil then ------------------- see note 3. above ball[collision[1]].ballon:destroy() --- see note 2 above table.remove(ball,collision[1]) bullets[collision[2]]:destroy() table.remove(bullets,collision[2]) collision=nil table.insert(score,1) end pushStyle() fill(0, 0, 0, 255) -- drawing the bullets for i,b in pairs(bullets) do sprite("Documents:arrow",b.x - 37,b.y,74) if b.x<1 or b.x>WIDTH or b.y<1 or b.y>HEIGHT then table.remove(bullets,1,b) table.insert(number,1) end end for i,b in pairs(ball) do if b.ballon.y>HEIGHT + b.radius then b:count() end end popStyle() for i,b in pairs(ball) do -- drawing the ballons pushStyle() fill(b.colr) ellipse(b.ballon.x, b.ballon.y, b.radius*2) end popStyle() if #number >= 5 then pushStyle() fill(255, 0, 0, 255) font("HoeflerText-BlackItalic") fontSize(50) text("Game Over", WIDTH/2, HEIGHT/2) physics.pause() popStyle() end if #ball == 0 then for i = 1,5 do ball[i] = Ballons() end end end function createBullet() local bullet = physics.body(CIRCLE,5) bullet.x = x bullet.y = y bullet.linearVelocity = vec2(750,0) bullet.restitution = 0 bullet.type = DYNAMIC bullet.info = "bullet" table.insert(bullets,bullet) end function touched(touch) x = touch.x y = touch.y if touch.x<=50 then if touch.state == BEGAN then a = true createBullet() end end end function collide(contact) if contact.bodyA.info~=nil and contact.bodyB.info~=nil then for i,v in pairs(ball) do if v.ballon==contact.bodyA or v.ballon==contact.bodyB then for j,bb in pairs(bullets) do if bb==contact.bodyA or bb==contact.bodyB then sound(DATA, "ZgNAXS4wQEBAQEBA/9iePiN3mD64nKs+cgBAf0BAQEBAb0BA ") collision={i,j} -- see note 3 above end end end end end end Ballons = class() function Ballons:init(x,y,r,c,lv) self.radius = r or math.random(25,50) self.ballon = physics.body(CIRCLE,self.radius) self.ballon.x = x or math.random(150,WIDTH - self.radius) self.ballon.y = y or math.random(-HEIGHT/2,-self.radius) self.ballon.linearVelocity = lv or vec2(0,math.random(100,200)) self.ballon.info="ball" self.colr = c or color(math.random(255),math.random(255),math.random(255),math.random(100,150)) end function Ballons:count() for i = 1,#ball do if self.ballon.y > HEIGHT + self.radius then table.insert(number,1) table.remove(ball,i,ball[i]) end end end

    Can't make a start button so I've added a five second delay.
    How can I make a start button?
    And how should I write the score as text not print in the end?

  • IgnatzIgnatz Mod
    Posts: 5,396

    There was a recent post on how to create a start button, have a look for that

    I would play around with writing text on the screen until you like it.

  • Posts: 372

    Thanks

  • Posts: 372

    How can I write number of values in a table on the screen as text?

  • IgnatzIgnatz Mod
    edited April 2013 Posts: 5,396

    You'd need to figure out the x,y values yourself and use the text function to write each item where you want it. There's no shortcut.

  • dave1707dave1707 Mod
    Posts: 7,195

    displayMode(FULLSCREEN) supportedOrientations(PORTRAIT) function setup()     scores={21342,12657,32121,54324,43278,33287,55223,45121,21387,22418} end function draw()     background(40, 40, 50)     showScores() end function showScores()     fill(255)     fontSize(40)     for z=1,#scores do         text(scores[z],WIDTH/2,HEIGHT-80*z)     end end
  • Posts: 372

    Thanks for the code. Though I didn't use it as it is but it helped me find a solution for my problem

Sign In or Register to comment.