Multiple physics objects

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

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

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

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

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

Thanks guys it worked perfectly the both of them.

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

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.

It’s completely fine :slight_smile:

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

.@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.

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

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 :wink: and 16

Oops!! I’ll fix that.

Done, I hope.

. @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.

@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.

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

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

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??

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