In the first part of this series, we wrote some code to handle player input and movement for our submarine shoot 'em up. But what good is a shoot 'em up if you can't shoot? No good at all, that's what! In this post I will show you how to get our little submarine to fire some torpedoes.
Initialization
First we will make some additions and changes to the load() method.
function love.load()
submarineImage = love.graphics.newImage("resources/images/submarine.png")
torpedoImage = love.graphics.newImage("resources/images/torpedo.png")
player = {xPos = 0, yPos = 0, width = 64, height = 64, speed=200, img=submarineImage}
torpedoes = {}
canFire = false
torpedoTimerMax = 0.2
torpedoTimer = torpedoTimerMax
torpedoStartSpeed = 100
torpedoMaxSpeed = 300
end
As you can see, we are now loading another image which will be used when drawing torpedoes. Also, all the information related to the player is now grouped in something called a table. Tables are a great way of grouping data and very easy to create. All you need to create a table is a pair of brackets enclosing some keys and values with equal signs in between. In order to access one of the values later, you just type the name of the object followed by a dot and the name of the associated key. We are also adding an empty table to keep track of all the torpedoes on the screen. Finally we add some variables that will be used to control the firing mechanic and the torpedoes themselves.
Let's draw some more things
The first addition to the draw() function tells the engine to draw a rectangle the size of the screen, using a blue color. The second setColor() call is used to reset the color before additional calls to the draw() function.
function love.draw()
love.graphics.setColor(186, 255, 255)
background = love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight())
love.graphics.setColor(255, 255, 255)
love.graphics.draw(player.img, player.xPos, player.yPos, 0, 2, 2)
for index, torpedo in ipairs(torpedoes) do
love.graphics.draw(torpedo.img, torpedo.xPos, torpedo.yPos)
end
end
The player is now drawn using the new 'player' table we created. We also need to draw the torpedoes, though, and this is where another Lua construct comes in, namely the 'for loop'. This loop allows us to go through all of the torpedoes currently in the table and draw them at their current positions. Lua lets you name two variables when creating a loop. The first one will hold the index of the current torpedo and the second one will hold the value. I chose to simply call these 'index' and 'torpedo'. Torpedoes are tables themselves and hold a reference to the torpedo image as well as values for their horizontal and vertical position. We will be creating some soon!
Let's update some more things
Writing all of the game logic inside of the update() function would lead to some very hard-to-maintain code once we add a few more features. That's why I have decided to extract the logic for the player object and the torpedoes into two separate functions. These functions are forwarded the same delta time value as a parameter.
function love.update(dt)
updatePlayer(dt)
updateTorpedoes(dt)
end
More input handling
For the updatePlayer() function, I slightly refactored the keyboard input code to store pressed direction keys in individual variables. I also took the new 'player' table into use. I omitted the player movement code from the above snippet for brevity.
function updatePlayer(dt)
down = love.keyboard.isDown("down")
up = love.keyboard.isDown("up")
left = love.keyboard.isDown("left")
right = love.keyboard.isDown("right")
--Player movement--
if love.keyboard.isDown("space") then
torpedoSpeed = torpedoStartSpeed
if(left) then
torpedoSpeed = torpedoSpeed - player.speed/2
elseif(right) then
torpedoSpeed = torpedoSpeed + player.speed/2
end
spawnTorpedo(player.xPos + player.width, player.yPos + player.height/2, torpedoSpeed)
end
if torpedoTimer > 0 then
torpedoTimer = torpedoTimer - dt
else
canFire = true
end
end
Since the player can now shoot, we need to check for another key. I chose the space bar. When the key is pressed, we first check if the player is moving left or right and if so, we allow the torpedo to be affected by the player velocity. I think it gives the projectiles a better feel, but it's a matter of taste. After calculating the speed, we call another new function called spawnTorpedo() which is described below. Remember those variables we defined at the end of the load() function? We will now use them to control the fire rate of the torpedoes. We let the timer count down until it reaches zero. Then we set the 'canFire' variable to true.
Creating and updating torpedoes
In the spawnTorpedo() function we check the 'canFire' variable and spawn a torpedo only if it's set to true. We simply create a table with position, size, speed and image values and add it to the torpedoes table. Then we reset the 'canFire' variable and the timer.
function spawnTorpedo(x, y, speed)
if canFire then
torpedo = {xPos = x, yPos = y, width = 16, height=16, speed=speed, img = torpedoImage}
table.insert(torpedoes, torpedo)
canFire = false
torpedoTimer = torpedoTimerMax
end
end
The last thing we have to write is the updateTorpedoes() function. We write another loop to go through all the torpedoes and update their position. We let the torpedoes accelerate from their initial speed to the max speed we defined in the load() function. This makes them behave more realistically in my opinion. Once a torpedo leaves the screen we are no longer interested in it, so we set it to nil. In Lua this basically means that the table object no longer exists and so it will no longer be updated or drawn.
function updateTorpedoes(dt)
for index, torpedo in ipairs(torpedoes) do
torpedo.xPos = torpedo.xPos + dt * torpedo.speed
if torpedo.speed < torpedoMaxSpeed then
torpedo.speed = torpedo.speed + dt * 100
end
if torpedo.xPos > love.graphics.getWidth() then
--torpedo = nil -does not actually work-
table.remove(torpedoes, index)
end
end
end
Edit: I had misunderstood something regarding removing items from tables. To actually remove something you need to call the table.remove() function, supplying the table and the index of the item to be removed.
Next up we will spawn some enemies to shoot!
Part 3
Top comments (1)
I'm learning Lua now. I like it so much more it's like a useful "Ruby" ha. But I like Ruby also. I'm learning Love2d right now.