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