Remove object on collision?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Kevinpt8339
Prole
Posts: 3
Joined: Thu Jan 19, 2017 12:52 am

Remove object on collision?

Post by Kevinpt8339 »

Hi all,

I'm new to Lua programming and Love2d, and need some help to get on the right track. I'm working on a game where a player shoots bullets and when they collide with a crate or a wall, I need for the bullet to be destroyed. After messing around for a while I'm still not able to figure out what I'm doing wrong. I can detect the collisions just fine, I just do not know how to go about removing the body/shape/fixture and the table entry for the bullet. If I just remove the table entry for the bullet, the physics still exist and collisions occur with objects that are no longer being drawn to the screen. If I try to destroy() the bullet, I get an error when a bullet collides "attempt to use destroyed fixture" in the bullet.lua file. I've attached my code below, any help would be greatly appreciated. I have a feeling I'm not creating the bullets properly.

main.lua

Code: Select all

function love.load()
  
  --Store the new world in a variable such as "world"
	
  world = love.physics.newWorld(0, 0, true)  --New World w/ 0 gravity
  world:setCallbacks(beginContact, endContact, preSolve, postSolve) -- Set World callbacks
    
  require "camera"
  require "player"
  require "crate"
  require "stage"
  
  gameState = "Play" 
	background = love.graphics.newImage("Images/background.png")
  cursor = love.mouse.newCursor("Images/guncursor.png", 16, 16)
  love.mouse.setCursor(cursor)
  crates = {}
  load_stage()
  
  text = ""
  persisting = 0
  
end
 
 
function love.update(dt)
  
  if (gameState == "Play") then
    
    world:update(dt) -- Update World
    
    player:update(dt) -- Update Player
    
    for k in pairs(crates) do 
        crates[k]:update(dt)   -- Update for each Crate
    end
  
    for k=#player.bullets,1,-1 do 
      player.bullets[k]:update(dt)   -- Update for each Bullet
      if player.bullets[k].hitboxF:getUserData() == "Remove" then
        player.bullets[k].hitboxF:destroy()
        table.remove(player.bullets[k])
      end
    end
   
  end
  
  if string.len(text) > 700 then -- Stop collision text from filling the screen
    text = ""
  end
    
  camera:setPosition(player.x-love.graphics.getWidth()/2,player.y-love.graphics.getHeight()/2) -- Move camera to player coordinates
  
end
 
 
function love.draw()
  
	camera:set()
  
  love.graphics.draw(background,-700,-400,0,2,2) -- Draw background image
    
    
    for k in pairs(player.bullets) do
      player.bullets[k]:draw()            --Draw bullets to screen
    end
    
    for k in pairs(crates) do
      crates[k]:draw()             --Draw crates to screen
    end
  
    player:draw()
    
    love.graphics.polygon("line", northwall.hitboxB:getWorldPoints(northwall.hitboxS:getPoints())) -- Draw hitbox for northwall
    love.graphics.polygon("line", eastwall.hitboxB:getWorldPoints(eastwall.hitboxS:getPoints())) -- Draw hitbox for eastwall
    love.graphics.polygon("line", southwall.hitboxB:getWorldPoints(southwall.hitboxS:getPoints())) -- Draw hitbox for southwall
    love.graphics.polygon("line", westwall.hitboxB:getWorldPoints(westwall.hitboxS:getPoints())) -- Draw hitbox for westwall
    
    love.graphics.print(text, player.x-love.graphics.getWidth()/2+10, player.y-love.graphics.getHeight()/2+10) -- Draw collision text to screen
  
  camera:unset()
  
end

function love.keypressed(p)
  
  if p == "p" or p == "escape" then
    if gameState == "Play" then
      gameState = "Pause"
    else 
      gameState = "Play"
    end
  end
  
end

function beginContact(a, b, coll)
    
    if (a:getUserData() == "Bullet" and b:getUserData() == "Crate") then 
      text = text.."\n"..a:getUserData().." collided with " .. b:getUserData()
      a:setUserData("Remove")
    end
    
    if (a:getUserData() == "Crate" and b:getUserData() == "Bullet") then
      text = text.."\n"..a:getUserData().." collided with " .. b:getUserData()
      b:setUserData("Remove")
    end
    
    if (a:getUserData() == "Bullet" and b:getUserData() == "Wall") then
      text = text.."\n"..a:getUserData().." collided with " .. b:getUserData()
      a:setUserData("Remove")
    end
    
    if (a:getUserData() == "Wall" and b:getUserData() == "Bullet") then
      text = text.."\n"..a:getUserData().." collided with " .. b:getUserData()
      b:setUserData("Remove")
    end
    
end
 
function endContact(a, b, coll)
    
end
 
function preSolve(a, b, coll)
    
end
 
function postSolve(a, b, coll, normalimpulse, tangentimpulse)
    
end
player.lua

Code: Select all

require "bullet"

player = {}
player.x = 640
player.y = 360
player.xvel = 0
player.yvel = 0
player.centerx = 100
player.centery = 155
player.rotation = 0
player.width = .33
player.height = .33
player.movementspeed = 100
player.friction = .25
player.hitboxsize = 25
player.cooldowntime = 20
player.cooldowncurrent = 0
player.bullettype = 1
player.bullets = {}
player.inventory = {}
playerSprite = love.graphics.newImage("Images/player.png")

player.hitboxB = love.physics.newBody(world, player.x+(playerSprite:getWidth()/2), player.y+(playerSprite:getHeight()/2), "dynamic")
player.hitboxB:setMass(1)
player.hitboxB:setAngularDamping(10000)
player.hitboxB:setLinearDamping(10)
player.hitboxS = love.physics.newRectangleShape(50,40)
player.hitboxF = love.physics.newFixture(player.hitboxB, player.hitboxS, 1)          -- connect body to shape
player.hitboxF:setRestitution(0.1)                                -- make it bouncy
player.hitboxF:setUserData("Player")                                -- give it a name, which we'll access later


  
  function player:update(dt)
    
    
    player.xvel = player.xvel * (1 - math.min(dt+player.friction,1))
    
    player.yvel = player.yvel * (1 - math.min(dt+player.friction,1))
    
      while love.keyboard.isDown("d") and player.xvel < 100 do
        player.xvel = player.xvel + player.movementspeed * dt
        player.hitboxB:applyForce(500, 0)
      end
      while love.keyboard.isDown("a") and player.xvel > -100 do
        player.xvel = player.xvel - player.movementspeed * dt
        player.hitboxB:applyForce(-500,0)
      end
      
      while love.keyboard.isDown("s") and player.yvel < 100 do
        player.yvel = player.yvel + player.movementspeed * dt
        player.hitboxB:applyForce(0,500)
      end
      while love.keyboard.isDown("w") and player.yvel > -100 do
        player.yvel = player.yvel - player.movementspeed * dt
        player.hitboxB:applyForce(0,-500)
      end
      
      if love.keyboard.isDown("1") then
        player.bullettype = 1
        player.cooldowntime = 15
      elseif love.keyboard.isDown("2") then
        player.bullettype = 2
        player.cooldowntime = 7
      elseif love.keyboard.isDown("3") then
        player.bullettype = 3
        player.cooldowntime = 1
      end
      
      
      player.rotation = math.atan2((love.mouse.getY()-love.graphics.getHeight()/2), (love.mouse.getX()-love.graphics.getWidth()/2))
      player.bulletrotationd = math.deg(player.rotation) + 18
      player.bulletrotation = math.rad(player.bulletrotationd)
      
      if love.mouse.isDown(1) then
        if player.cooldowncurrent <= 0 then
          if  (love.mouse.getX() > love.graphics.getWidth()/2+70 or love.mouse.getX() < love.graphics.getWidth()/2-70) or (love.mouse.getY() > love.graphics.getHeight()/2+70 or love.mouse.getY() < love.graphics.getHeight()/2-70)  then
              shoot()
              player.cooldowncurrent = player.cooldowntime
          end
        end
      end
         
      player.cooldowncurrent = player.cooldowncurrent - 1
      
      player.x = player.hitboxB:getX()
      player.y = player.hitboxB:getY()
      
      player.hitboxB:setAngle(player.rotation)
      
      
  end
  
  function player:draw()
    
    
    love.graphics.polygon("line", player.hitboxB:getWorldPoints(player.hitboxS:getPoints())) -- Draw hitbox
    --love.graphics.draw(playerSprite,player.hitboxB:getX(), player.hitboxB:getY()+10,player.hitboxB:getAngle(),player.width,player.height,player.centerx,player.centery)
    love.graphics.draw(playerSprite,player.hitboxB:getX(),player.hitboxB:getY(), player.hitboxB:getAngle(), player.width, player.height, 110, 100)
    
  end
  
  function shoot()
  
    table.insert(player.bullets, create_bullet(getBlastpointX(), getBlastpointY(), getMIGxpos(), getMIGypos() , player.bullettype))
  
end




function getMIGxpos()
  
  local migx = player.x+(love.mouse.getX()-love.graphics.getWidth()/2)
  
  return migx
  
end

function getMIGypos()
  
  local migy = player.y+(love.mouse.getY()-love.graphics.getHeight()/2)
  
  return migy
  
end

function getBlastpointX()
  
  local blastpointx = player.hitboxB:getX()+(55*math.cos(player.bulletrotation))
  
  return blastpointx
  
end

function getBlastpointY()
  
  local blastpointy = player.hitboxB:getY()+(55*math.sin(player.bulletrotation))
  
  return blastpointy

end
bullet.lua

Code: Select all

function create_bullet(inx, iny, mousex, mousey, bullettype)

  self = {} 
  self.x = inx
  self.y = iny
  self.dx = mousex
  self.dy = mousey
  self.speed = 500
  self.range = 400
  self.size = 3
  self.damage = 1
  self.angle = math.atan2((self.dy - self.y), (self.dx - self.x))
  self.fired = true
  self.rem = false
  self.time = 0
  self.maxtime = 1
  self.weight = 100

  self.hitboxB = love.physics.newBody(world, self.x+(self.size/2), self.y+(self.size/2), "dynamic")
  self.hitboxB:setMass(self.weight)
  self.hitboxB:setLinearDamping(.01)
  self.hitboxS = love.physics.newCircleShape(self.size)
  self.hitboxF = love.physics.newFixture(self.hitboxB, self.hitboxS)          -- connect body to shape
  self.hitboxF:setRestitution(0.1)
  self.hitboxF:setUserData("Bullet")

  if bullettype == 1 then
    self.speed = 650
    self.range = 400
    self.hitboxB:setLinearDamping(.01)
  end

  if bullettype == 2 then
    self.speed = 750
    self.range = 700
    self.hitboxB:setLinearDamping(.01)
  end

  if bullettype == 3 then
    self.speed = 1000
    self.range = 500
    self.size = 10
    self.hitboxB:setLinearDamping(4)
  end

  function self:update(dt)
    
      if self.fired == true then
        self.hitboxB:setLinearVelocity(self.speed * math.cos(self.angle),self.speed * math.sin(self.angle))
        self.fired = false
      end
      
      self.time = self.time + dt
      
  end

  function self:draw()
        
        love.graphics.circle("line",self.hitboxB:getX(),self.hitboxB:getY(),self.size)
    
  end


  return self

end
UPDATE: I don't think I'm creating the Bullet "Object" correctly. I've been reading up on Lua OOP and metatables, I think it may be where my problem lies. If someone can confirm that would help.
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Remove object on collision?

Post by ivan »

First of all, you need to study up on collision filters,
that way you don't have to write checks like "if (a == bullet and b == crate) or (b == bullet and a == crate)".
Collision filters can do that for you automatically.

Instead of "setUserData" you can just keep a queue like so:

Code: Select all

local destroy_queue = {}

function beginContact(a, b, coll)
    if some_condition then
      -- mark for deletion
      destroy_queue[a] = true
    end
end

function love.update(dt)
  for b in pairs(destroy_queue) do
    world:DestroyBody(b)
    destroy_queue[b] = nil
  end
end
That's one simple way to do it, but note that when you destroy/create fixtures that may trigger collision callbacks in a cascade.

Instead of using the callbacks, you can just iterate the contacts:

Code: Select all

function love.update(dt)
  for b in pairs(bullets) do
    local cl = b:getContactList()
    -- check if b should be destroyed
  end
end
In rare cases, this approach might miss some collisions if your bullets are moving really, really fast.
nyenye
Citizen
Posts: 62
Joined: Fri Dec 02, 2016 1:44 pm

Re: Remove object on collision?

Post by nyenye »

UPDATE: I don't think I'm creating the Bullet "Object" correctly. I've been reading up on Lua OOP and metatables, I think it may be where my problem lies. If someone can confirm that would help
Personally I do it this way:

Code: Select all

local Bullet = {
 -- here you type in the properties
}
local bullet_metatable = {__index = Bullet}

-- One the new method we use dot notation and return a new instance.
function Bullet.new()
  local instance = {}
  -- add body and values you need and return as follows
  return setmetatable(instance, bullet_metatable)
end

-- notice colon notation. This means that you can call self on this method
function Bullet:hit(other)
  -- do things
end

return Bullet
the method 'setmetatable(i, mt) returns the firs arg, but with all the wethods defined on the metatable. See documentation for more details.

Then you require bullet.lua as follows:

Code: Select all

local BulletFactory = require('bullet.lua')
-- create a new bullet with dot notation
local bullet = BulletFactory.new()
-- call hit method with colon
bullet:hit()
Kevinpt8339
Prole
Posts: 3
Joined: Thu Jan 19, 2017 12:52 am

Re: Remove object on collision?

Post by Kevinpt8339 »

Thank you both for the quick replies, I'm definitely going to try those methods out when\if I get time tomorrow. As a visual learner, it is very helpful to see the code written out especially for my specific case here. I appreciate the time you both spent in doing so. Once I get everything working, I'll post the new code so this could hopefully help someone else in the same situation.
Kevinpt8339
Prole
Posts: 3
Joined: Thu Jan 19, 2017 12:52 am

Re: Remove object on collision?

Post by Kevinpt8339 »

Ok, so I was able to able to implement a destroy queue like in ivan's post and updated my bullet.lua file to actually be a class as nyenye mentioned. I've run into a small problem though, I'm not sure how to remove the bullet from the bullets table after the body of the instance has been destroyed. I thought I would be able to call the isDestroyed() function in my Bullet:update(dt) function to see if its destroyed and set self.rem to true but isDestroyed() always returns as false. This results in the bullets hitting the wall, destroying the body of the bullet, but still drawing the circle which will continue through all walls/crates since it no longer has a body. I guess I just don't understand how to link the beginContact(a,b,coll) function to the instance of the bullet. Tried making a variable bt and setting it = to the body, but it returns nil. I'll post the code below.

main.lua

Code: Select all



function love.load()
  
  --Store the new world in a variable such as "world"
	
  world = love.physics.newWorld(0, 0, true)  --New World w/ 0 gravity
  world:setCallbacks(beginContact, endContact, preSolve, postSolve) -- Set World callbacks
  
  bullets = {}
  crates = {}
    
  require "camera"
  require "player"
  require "stage"
  local BulletFactory = require("bullet")
  local CrateFactory = require("crate")
  
  destroy_queue = {}
  
  gameState = "Play" 
	background = love.graphics.newImage("Images/background.png")
  cursor = love.mouse.newCursor("Images/guncursor.png", 16, 16)
  love.mouse.setCursor(cursor)
  load_stage()
  
  text = ""
  persisting = 0
  
end
 
 
function love.update(dt)
  
  
  
  if (gameState == "Play") then
    
    world:update(dt) -- Update World
    
    player:update(dt) -- Update Player
    
    for k=#crates,1,-1 do 
      if crates[k] ~= nil then
        crates[k]:update(dt)   -- Update for each Bullet
      end    
    end
  
    for k=#bullets,1,-1 do 
      if bullets[k].rem == true then
        bullets[k] = nil
        else
        bullets[k]:update(dt)   -- Update for each Bullet
        end
    end
  
    if string.len(text) > 700 then -- Stop collision text from filling the screen
      text = ""
    end
  
  end
  
  for b in pairs(destroy_queue) do
    b:destroy()
    destroy_queue[b] = nil
  end
    
  camera:setPosition(player.x-love.graphics.getWidth()/2,player.y-love.graphics.getHeight()/2) -- Move camera to player coordinates
  
end
 
 
function love.draw()
  
	camera:set()
  
  love.graphics.draw(background,-700,-400,0,2,2) -- Draw background image
    
    
    for k in pairs(bullets) do
      bullets[k]:draw()            --Draw bullets to screen
    end
    
    for k in pairs(crates) do
      if crates[k] ~= nil then
      crates[k]:draw()             --Draw crates to screen
      end
    end
  
    player:draw()
    
    love.graphics.polygon("line", northwall.hitboxB:getWorldPoints(northwall.hitboxS:getPoints())) -- Draw hitbox for northwall
    love.graphics.polygon("line", eastwall.hitboxB:getWorldPoints(eastwall.hitboxS:getPoints())) -- Draw hitbox for eastwall
    love.graphics.polygon("line", southwall.hitboxB:getWorldPoints(southwall.hitboxS:getPoints())) -- Draw hitbox for southwall
    love.graphics.polygon("line", westwall.hitboxB:getWorldPoints(westwall.hitboxS:getPoints())) -- Draw hitbox for westwall
    
    love.graphics.print(text, player.x-love.graphics.getWidth()/2+10, player.y-love.graphics.getHeight()/2+10) -- Draw collision text to screen
  
  camera:unset()
  
end

function love.keypressed(p)
  
  if p == "p" or p == "escape" then
    if gameState == "Play" then
      gameState = "Pause"
    else 
      gameState = "Play"
    end
  end
  
end

function beginContact(a, b, coll)
    
    if (a:getUserData() == "Bullet" and b:getUserData() == "Crate") then 
      text = text.."\n"..a:getUserData().." collided with " .. b:getUserData()
      destroy_queue[a] = true
    end
    
    if (a:getUserData() == "Crate" and b:getUserData() == "Bullet") then
      text = text.."\n"..a:getUserData().." collided with " .. b:getUserData()
      destroy_queue[b] = true
      destroy_queue[a] = true
    end
    
    if (a:getUserData() == "Bullet" and b:getUserData() == "Wall") then
      text = text.."\n"..a:getUserData().." collided with " .. b:getUserData()
      destroy_queue[a] = true
    end
    
    if (a:getUserData() == "Wall" and b:getUserData() == "Bullet") then
      text = text.."\n"..a:getUserData().." collided with " .. b:getUserData()
      destroy_queue[b] = true
    end
    
end
 
function endContact(a, b, coll)
    
end
 
function preSolve(a, b, coll)
    
end
 
function postSolve(a, b, coll, normalimpulse, tangentimpulse)
    
end



player.lua

Code: Select all


player = {}
player.x = 640
player.y = 360
player.xvel = 0
player.yvel = 0
player.centerx = 100
player.centery = 155
player.rotation = 0
player.width = .33
player.height = .33
player.movementspeed = 100
player.friction = .25
player.hitboxsize = 25
player.cooldowntime = 20
player.cooldowncurrent = 0
player.bullettype = 1
player.bullets = {}
player.inventory = {}
playerSprite = love.graphics.newImage("Images/player.png")

player.hitboxB = love.physics.newBody(world, player.x+(playerSprite:getWidth()/2), player.y+(playerSprite:getHeight()/2), "dynamic")
player.hitboxB:setMass(1)
player.hitboxB:setAngularDamping(10000)
player.hitboxB:setLinearDamping(10)
player.hitboxS = love.physics.newRectangleShape(50,40)
player.hitboxF = love.physics.newFixture(player.hitboxB, player.hitboxS, 1)          -- connect body to shape
player.hitboxF:setRestitution(0.1)                                -- make it bouncy
player.hitboxF:setUserData("Player")                                -- give it a name, which we'll access later


  
  function player:update(dt)
    
    
    player.xvel = player.xvel * (1 - math.min(dt+player.friction,1))
    
    player.yvel = player.yvel * (1 - math.min(dt+player.friction,1))
    
      while love.keyboard.isDown("d") and player.xvel < 100 do
        player.xvel = player.xvel + player.movementspeed * dt
        player.hitboxB:applyForce(500, 0)
      end
      while love.keyboard.isDown("a") and player.xvel > -100 do
        player.xvel = player.xvel - player.movementspeed * dt
        player.hitboxB:applyForce(-500,0)
      end
      
      while love.keyboard.isDown("s") and player.yvel < 100 do
        player.yvel = player.yvel + player.movementspeed * dt
        player.hitboxB:applyForce(0,500)
      end
      while love.keyboard.isDown("w") and player.yvel > -100 do
        player.yvel = player.yvel - player.movementspeed * dt
        player.hitboxB:applyForce(0,-500)
      end
      
      if love.keyboard.isDown("1") then
        player.bullettype = 1
        player.cooldowntime = 1
      elseif love.keyboard.isDown("2") then
        player.bullettype = 2
        player.cooldowntime = 2
      elseif love.keyboard.isDown("3") then
        player.bullettype = 3
        player.cooldowntime = 1
      end
      
      
      player.rotation = math.atan2((love.mouse.getY()-love.graphics.getHeight()/2), (love.mouse.getX()-love.graphics.getWidth()/2))
      player.bulletrotationd = math.deg(player.rotation) + 18
      player.bulletrotation = math.rad(player.bulletrotationd)
      
      if love.mouse.isDown(1) then
        if player.cooldowncurrent <= 0 then
          if  (love.mouse.getX() > love.graphics.getWidth()/2+70 or love.mouse.getX() < love.graphics.getWidth()/2-70) or (love.mouse.getY() > love.graphics.getHeight()/2+70 or love.mouse.getY() < love.graphics.getHeight()/2-70)  then
              shoot()
              player.cooldowncurrent = player.cooldowntime
          end
        end
      end
         
      player.cooldowncurrent = player.cooldowncurrent - 1
      
      player.x = player.hitboxB:getX()
      player.y = player.hitboxB:getY()
      
      player.hitboxB:setAngle(player.rotation)
      
      
  end
  
  function player:draw()
    
    
    love.graphics.polygon("line", player.hitboxB:getWorldPoints(player.hitboxS:getPoints())) -- Draw hitbox
    --love.graphics.draw(playerSprite,player.hitboxB:getX(), player.hitboxB:getY()+10,player.hitboxB:getAngle(),player.width,player.height,player.centerx,player.centery)
    love.graphics.draw(playerSprite,player.hitboxB:getX(),player.hitboxB:getY(), player.hitboxB:getAngle(), player.width, player.height, 110, 100)
    
  end
  
  function shoot()
  
   -- table.insert(bullets, createBullet(getBlastpointX(), getBlastpointY(), getMIGxpos(), getMIGypos() , player.bullettype))
  table.insert(bullets,Bullet.new(getBlastpointX(), getBlastpointY(), getMIGxpos(), getMIGypos() , player.bullettype))
  
end




function getMIGxpos()
  
  local migx = player.x+(love.mouse.getX()-love.graphics.getWidth()/2)
  
  return migx
  
end

function getMIGypos()
  
  local migy = player.y+(love.mouse.getY()-love.graphics.getHeight()/2)
  
  return migy
  
end

function getBlastpointX()
  
  local blastpointx = player.hitboxB:getX()+(55*math.cos(player.bulletrotation))
  
  return blastpointx
  
end

function getBlastpointY()
  
  local blastpointy = player.hitboxB:getY()+(55*math.sin(player.bulletrotation))
  
  return blastpointy

end


  

bullet.lua

Code: Select all


Bullet = {
  x = 0,
  y = 0,
  dx = 0,
  dy = 0,
  speed = 500,
  range = 400,
  size = 3,
  damage = 1,
  angle = 0,
  fired = true,
  rem = false,
  time = 0,
  maxtime = 1,
  weight = 100,
  bt = 1
}

local Bullet_metatable = {__index = Bullet}

function Bullet.new(inx, iny, mousex, mousey, bullettype)

  local instance = {} 
  instance.x = inx
  instance.y = iny
  instance.dx = mousex
  instance.dy = mousey
  instance.speed = 500
  instance.range = 400
  instance.size = 7
  instance.damage = 1
  instance.angle = math.atan2((instance.dy - instance.y), (instance.dx - instance.x))
  instance.fired = true
  instance.rem = false
  instance.time = 0
  instance.maxtime = 1
  instance.weight = 100
  instance.bt = bullettype

  instance.hitboxB = love.physics.newBody(world, instance.x+(instance.size/2), instance.y+(instance.size/2), "dynamic")
  instance.hitboxB:setMass(instance.weight)
  instance.hitboxB:setLinearDamping(.01)
  instance.hitboxS = love.physics.newCircleShape(instance.size)
  instance.hitboxF = love.physics.newFixture(instance.hitboxB, instance.hitboxS)          -- connect body to shape
  instance.hitboxF:setRestitution(0.1)
  instance.hitboxF:setUserData("Bullet")
  
  instance.body = hitboxB
  
  return setmetatable(instance, Bullet_metatable)
  
end

function Bullet:update(dt)
    
      if self.hitboxB == nil then
        self.rem = true
      end
      
    
      if self.fired == true then
        self.hitboxB:setLinearVelocity(self.speed * math.cos(self.angle),self.speed * math.sin(self.angle))
        self.fired = false
      end
      
      self.time = self.time + dt
      
end

function Bullet:draw()
        
        love.graphics.circle("line",self.hitboxB:getX(),self.hitboxB:getY(),self.size)
        print(tostring(self.hitboxB:isDestroyed()))
    
end

return Bullet


nyenye
Citizen
Posts: 62
Joined: Fri Dec 02, 2016 1:44 pm

Re: Remove object on collision?

Post by nyenye »

Hi again, good to know it helped you. Seeing the code I have two thing to comment on: 1) collision filtering (as Ivan mentioned earlier), 2) your last question, for which I have some ideas.

1) Let's see, in Lua, tables can be used as Sets (http://lua-users.org/wiki/TablesTutorial - See last section 'Tables as unordered sets', really helpful this page as a whole). Which means that it's very easy to implement a collision filtering system as follows (just note that I haven't used Love2D's Box2D implementation, so this will be pseudo-code):
Bullet.lua

Code: Select all

-- Create a body for the bullet instance
local body = world.newBody()
-- Add a table field to 'body' called 'mask' as follows (use any other name if mask is already in use)
body.mask = {crate = true}
-- Add a string field to 'body' called 'group' as follows
body.group = 'bullet'
On Crate.lua do the same, but instead of body.mask.crate = true, do: body.mask.bullet = true, and instead of body.group = 'bullet', do: body.group = 'crate'
Then on the contactBegin method:

Code: Select all

	if a.mask[b.group] then
		-- contact is valid
		-- this could help you lessen the code you need to write depending on your needs.
		-- if you need to know if a is bullet then a.group == 'bullet' could be used
	end
Maybe you need to put those two values on the user_data field.

2) Now to remove the bullet instance, the easiest way to do it is to add a reference from body to bullet.

Code: Select all

function Bullet.new(x, y, mx, my, bt)
   local instance = {
 	...
   }
   local body = world.newBody()
   --This is the bullet to body reference
   instance.body = body
   --And here is the body to bullet reference
   body.entity = instance 
end

Like this you can tell the bullet instance to be deleted when contactBegin occurs (hint: setting a delete field to true on the bullet instance?).

Having said this, you will have to find the most efficient way to delete the bullet instance, but I'll leave this to you.
Post Reply

Who is online

Users browsing this forum: SiENcE and 4 guests