Remove object on collision?
Posted: Thu Jan 19, 2017 1:19 am
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
player.lua
bullet.lua
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.
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
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
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