I'm looking for help with making bullets in LÖVE

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
The Lie
Prole
Posts: 3
Joined: Wed Dec 23, 2015 10:36 pm

I'm looking for help with making bullets in LÖVE

Post by The Lie »

So I tried making bullets for a game by creating bodies and shapes and putting them into a table on keypress. After this step I wanted to put them together by a fixture. When I tried pressing the button though, löve told me that either the body was a shape or the shape was a body. Which was wrong dependet on what I put into the table first. The code in question:

Code: Select all

if love.keyboard.isDown('kp6') then
	if sniggle == 1 then
	newShape = love.physics.newRectangleShape( 2, 2)
	table.insert(objects.bullets, newShape)
	newBody = love.physics.newBody(world, objects.player.body:getX(), objects.player.body:getY())
	table.insert(objects.bullets, newBody)
	
	sniggle = sniggle-1
	end
	else
	sniggle = 1

	for i, Body in ipairs(objects.bullets) do

	
	for j, Shape in ipairs(objects.bullets) do
	
	if i == j and i > 0  then
	newFixture = love.physics.newFixture(Body, Shape, 0)
	table.insert(objects.bullets, newFixture)
	Body:setLinearVelocity(400,0)
	end
	
	end

	end
	
	end
Main.lua
My Main.lua for additional info if necessary
(5.02 KiB) Downloaded 149 times
thanks in advance for any help :3
User avatar
giantofbabil
Prole
Posts: 32
Joined: Tue Dec 15, 2015 6:07 pm

Re: I'm looking for help with making bullets in LÖVE

Post by giantofbabil »

It looks like you are making the bullet shape before making the body. A shape is attached to a body by a fixture. Look at your other physics objects when you make them it goes Body->Shape->Fixture.

Code: Select all

if enemy == lowerClassSaiyan and powerLevel > 9000 then
    love.graphics.print("What?! 9000?! There's no way that could be right!", 10, 200)
else
    love.graphics.print("You fool!", 10, 200)
end
The Lie
Prole
Posts: 3
Joined: Wed Dec 23, 2015 10:36 pm

Re: I'm looking for help with making bullets in LÖVE

Post by The Lie »

giantofbabil wrote:It looks like you are making the bullet shape before making the body. A shape is attached to a body by a fixture. Look at your other physics objects when you make them it goes Body->Shape->Fixture.
First, thanks for the help. But If I change the order, the error just switches. when I write:

Code: Select all

newBody = love.physics.newBody(world, objects.player.body:getX(), objects.player.body:getY())
newShape = love.physics.newRectangleShape( 2, 2)
table.insert(objects.bullets, newBody)
table.insert(objects.bullets, newShape)
It says that it got a body when it expected a shape.
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: I'm looking for help with making bullets in LÖVE

Post by bartbes »

If we presume you insert the shape first, and then the body, and we rewrite the nested ipairs to a print, like this:

Code: Select all

for i, Body in ipairs(objects.bullets) do
    for j, Shape in ipairs(objects.bullets) do
        print(i, j, Body, Shape)
    end
end
We'll see the output is:

Code: Select all

1, 1, Shape, Shape
1, 2, Shape, Body
2, 1, Body, Shape
2, 2, Body, Body
As you may now realise, the nested ipairs must not be doing what you expect them to, since this always means both 'Body' and 'Shape' will have a value of the other type at some point.

The best way to fix this is to not store the two together, perhaps by storing more structured data instead:

Code: Select all

local body = love.physics.newBody(world, objects.player.body:getX(), objects.player.body:getY())
local shape = love.physics.newRectangleShape(2, 2)
table.insert(objects.bullets, {body = body, shape = shape})

for i, bullet in ipairs(objects.bullets) do
    bullet.fixture = love.physics.newFixture(bullet.body, bullet.shape, 0)
    bullet.body:setLinearVelocity(400, 0)
end
Of course since you probably don't want to recreate fixtures for every bullet whenever a new one is fired, you're probably better off not using a loop just calling newFixture once.

As some extra explanation, the names given in the for loop for ipairs are not filters of any sort. They simply represent the variable names used for the iteration values.
User avatar
giantofbabil
Prole
Posts: 32
Joined: Tue Dec 15, 2015 6:07 pm

Re: I'm looking for help with making bullets in LÖVE

Post by giantofbabil »

bartbes wrote:Of course since you probably don't want to recreate fixtures for every bullet whenever a new one is fired, you're probably better off not using a loop just calling newFixture once.
A little confused by this, if he has multiple bullets on the screen at the same time doesn't each bullet need a fixture? That way they can be set as sensors to detect collision? I'm building a system like this right now as well about to start digging into some source to try to find something similar because putting in bullets and enemies is much more complicated when they are physics based and no tutorials seem to cover it :P

Code: Select all

if enemy == lowerClassSaiyan and powerLevel > 9000 then
    love.graphics.print("What?! 9000?! There's no way that could be right!", 10, 200)
else
    love.graphics.print("You fool!", 10, 200)
end
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: I'm looking for help with making bullets in LÖVE

Post by bartbes »

giantofbabil wrote: A little confused by this, if he has multiple bullets on the screen at the same time doesn't each bullet need a fixture?
Yes, but you don't need to create a fixture for every bullet every time you add one bullet, you only need to create the fixture for that bullet.
User avatar
giantofbabil
Prole
Posts: 32
Joined: Tue Dec 15, 2015 6:07 pm

Re: I'm looking for help with making bullets in LÖVE

Post by giantofbabil »

I'm trying to do the same thing as OP with this and having an error when I press 'f'(my fire button) that says:
Error

assets/loaders/weapons.lua:49: attempt to index field 'body' (a nil value)

Code: Select all

function weaponsLoad()

 local sprite = map.layers['Sprite Layer'].sprites.player
 --set up table for Zapper
 sprite.zapperGun = {canShoot         = true,
                  canShootTimerMax = 0.2,
                  canShootTimer    = 0.2,
                  zapImg           = love.graphics.newImage('assets/particles/roundBlue.png'),
                  zapSound         = love.audio.newSource('assets/sound/serglaser.wav', 'static'),
                  zapBullet        = {}}

end

function weaponsUpdate(dt)

  --timer for Zapper shot separation
  local sprite = map.layers['Sprite Layer'].sprites.player
  if playerStats.weaponEquip == 0 then
    sprite.zapperGun.canShootTimer = sprite.zapperGun.canShootTimer - (1 * dt)
    if sprite.zapperGun.canShootTimer <= 0 then
      sprite.zapperGun.canShoot = true
    end
  end

  --fire button response
  local isDown = love.keyboard.isDown
  if isDown('f') and playerStats.weaponEquip == 0 and sprite.zapperGun.canShoot == true then
    --create zapper shot
    local body  = love.physics.newBody(world, sprite.body:getX(), sprite.body:getY(), 'dynamic')
    local shape = love.physics.newRectangleShape(0, 0, 15, 15, 0)
    table.insert(sprite.zapperGun.zapBullet, {body, shape})
    sprite.zapperGun.zapSound:play()
    sprite.zapperGun.canShoot = false
    sprite.zapperGun.canShootTimer = sprite.zapperGun.canShootTimerMax
  end


  --update position for zapper shots
  if playerStats.weaponEquip == 0 then
    for i, bullet in ipairs(sprite.zapperGun.zapBullet) do
      if sprite.lastdirection == 'right' then
        bullet.fixture = love.physics.newFixture(bullet.body, bullet.shape)
        bullet.body:setLinearVelocity(500, 0)
      elseif sprite.lastdirection == 'left' then
        bullet.fixture = love.physics.newFixture(bullet.body, bullet.shape)
        bullet.body:setLinearVelocity(-500, 0)
      end
      if bullet.body:getX() < 0 or bullet.body:getX() > 7680 then
        table.remove(sprite.zapperGun.zapBullet, i)
      end
    end
  end

end

function weaponsDraw(dt)

  local sprite = map.layers['Sprite Layer'].sprites.player
  --update position for zapper shots
  if playerStats.weaponEquip == 0 then
    for i, bullet in ipairs(sprite.zapperGun.zapBullet) do
      love.graphics.setColor(0, 255, 0, 255)
      love.graphics.draw(sprite.zapperGun.zapImg, bullet.body:getX(), bullet.body:getY(), 0, 0.5, 0.5)
    end
  end

end
Github: https://github.com/NeverHuman/Space-Chow.love

I'm using STI so I'm trying to create the bullet in a custom layer called 'Sprite Layer', I'm sure there's probably a syntax error or something... I'm guessing to fix the fixture thing you were talking about I would have to add fixture to the table.insert so it would be table.insert{body, shape, fixture} right?

Code: Select all

if enemy == lowerClassSaiyan and powerLevel > 9000 then
    love.graphics.print("What?! 9000?! There's no way that could be right!", 10, 200)
else
    love.graphics.print("You fool!", 10, 200)
end
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: I'm looking for help with making bullets in LÖVE

Post by bartbes »

The actual error is that you're inserting {body, shape}, where it should be {body = body, shape = shape}, the first is equivalent to {[1] = body, [2] = shape} instead.
The Lie
Prole
Posts: 3
Joined: Wed Dec 23, 2015 10:36 pm

Re: I'm looking for help with making bullets in LÖVE

Post by The Lie »

bartbes wrote:If we presume you insert the shape first, and then the body, and we rewrite the nested ipairs to a print, like this:

Code: Select all

for i, Body in ipairs(objects.bullets) do
    for j, Shape in ipairs(objects.bullets) do
        print(i, j, Body, Shape)
    end
end
We'll see the output is:

Code: Select all

1, 1, Shape, Shape
1, 2, Shape, Body
2, 1, Body, Shape
2, 2, Body, Body
As you may now realise, the nested ipairs must not be doing what you expect them to, since this always means both 'Body' and 'Shape' will have a value of the other type at some point.

The best way to fix this is to not store the two together, perhaps by storing more structured data instead:

Code: Select all

local body = love.physics.newBody(world, objects.player.body:getX(), objects.player.body:getY())
local shape = love.physics.newRectangleShape(2, 2)
table.insert(objects.bullets, {body = body, shape = shape})

for i, bullet in ipairs(objects.bullets) do
    bullet.fixture = love.physics.newFixture(bullet.body, bullet.shape, 0)
    bullet.body:setLinearVelocity(400, 0)
end
Of course since you probably don't want to recreate fixtures for every bullet whenever a new one is fired, you're probably better off not using a loop just calling newFixture once.

As some extra explanation, the names given in the for loop for ipairs are not filters of any sort. They simply represent the variable names used for the iteration values.
Wow, thanks for all the work especially on christmas eve, have happy holidays.
User avatar
giantofbabil
Prole
Posts: 32
Joined: Tue Dec 15, 2015 6:07 pm

Re: I'm looking for help with making bullets in LÖVE

Post by giantofbabil »

The Lie wrote:Wow, thanks for all the work especially on christmas eve, have happy holidays.
If it helps at all my bullet code is now working, the github link is above if you want to look at the whole code for my engine but keep in mind you may need different values than me my game is a platformer and I have physics and variables flying around like crazy lol. Anyway here's my working weapon/bullet code:

Code: Select all

function weaponsLoad()
  
  local sprite = map.layers['Sprite Layer'].sprites.player
  --set up table for Zapper
  sprite.zapperGun = {canShoot         = true,
                      canShootTimerMax = 0.2,
                      canShootTimer    = 0.2,
                      zapImg           = love.graphics.newImage('assets/particles/roundBlue.png'),
                      zapSound         = love.audio.newSource('assets/sound/serglaser.wav', 'static'),
                      zapBullet        = {}}

end

function weaponsUpdate(dt)
  
  --timer for Zapper shot separation
  local sprite = map.layers['Sprite Layer'].sprites.player
  if playerStats.weaponEquip == 0 then
    sprite.zapperGun.canShootTimer = sprite.zapperGun.canShootTimer - (1 * dt)
    if sprite.zapperGun.canShootTimer <= 0 then
      sprite.zapperGun.canShoot = true
    end
  end
  
  --fire button response
  local isDown = love.keyboard.isDown
  if isDown('f') and playerStats.weaponEquip == 0 and sprite.zapperGun.canShoot == true then
    --create zapper shot
    local body    = love.physics.newBody(world, sprite.body:getX(), sprite.body:getY(), 'dynamic')
    local shape   = love.physics.newRectangleShape(7, 7, 13, 13, 0)
    local fixture = love.physics.newFixture(body, shape)
    table.insert(sprite.zapperGun.zapBullet, {body = body, shape = shape, fixture = fixture:setSensor(true), body:setBullet(true), speedSet = false})
    sprite.zapperGun.zapSound:play()
    sprite.zapperGun.canShoot = false
    sprite.zapperGun.canShootTimer = sprite.zapperGun.canShootTimerMax
  end
  
  --update position for zapper shots
  if playerStats.weaponEquip == 0 then
    for i, bullet in ipairs(sprite.zapperGun.zapBullet) do
      if sprite.lastDirection == 'right' and bullet.speedSet == false then -- THIS MIGHT NOT WORK
        bullet.body:setLinearVelocity(2.5 * physicsMultiplier, -0.1 * physicsMultiplier)
        bullet.speedSet = true
      elseif sprite.lastDirection == 'left' and bullet.speedSet == false then
        bullet.body:setLinearVelocity(-2.5 * physicsMultiplier, -0.1 * physicsMultiplier)
        bullet.speedSet = true
      end
      if bullet.body:getX() < 0 or bullet.body:getX() > 7680 then
        table.remove(sprite.zapperGun.zapBullet, i)
      elseif bullet.body:getY() < 0 or bullet.body:getY() > 4352 then
        table.remove(sprite.zapperGun.zapBullet, i)
      end
    end
  end
  
end

function weaponsDraw(dt)
  
  local sprite = map.layers['Sprite Layer'].sprites.player
  --update position for zapper shots
  if playerStats.weaponEquip == 0 then
    for i, bullet in ipairs(sprite.zapperGun.zapBullet) do
      love.graphics.setColor(0, 255, 0, 255)
      love.graphics.draw(sprite.zapperGun.zapImg, bullet.body:getX(), bullet.body:getY(), 0, 0.5, 0.5)
      love.graphics.setColor(255, 255, 255, 255)
    end
  end
  
end
I'm going to modify this to include multiple weapons, ammo, and add animations as well :) but for now enemies is next on my list.

Happy holidays!

Code: Select all

if enemy == lowerClassSaiyan and powerLevel > 9000 then
    love.graphics.print("What?! 9000?! There's no way that could be right!", 10, 200)
else
    love.graphics.print("You fool!", 10, 200)
end
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot] and 3 guests