6
\$\begingroup\$

I just started learning programming in the past two or three months. I started with Python, and now I'm learning lua. I started game programming this week and this is a game I made with the Love2D engine for lua. If you don't know how it works, there are these three main functions:

love.load() -- Runs at game startup and doesn't run again unless explicitly called
love.update() -- Updates values in the game and runs every tick. It uses delta time as an argument for consistent speed on every machine
love.draw() -- Draws the updates to the screen, however you choose for them to be displayed. 

love.update() and love.draw() loop back and forth in-between each other. love.update() always runs first and then love.draw().

This is my first game, a Pong like game where you destroy blocks with a ball bounced off of a paddle like player. I would like less criticism on the game itself, but more on the structure of the code. Please let me know if you see anywhere I could make a function, or achieve something with less code.

function love.load()
 -- WINDOW SETUP
 love.window.setTitle("Block Buster")
 height = love.graphics.getHeight()
 width = love.graphics.getWidth()
 -- SOUND SOURCES
 hit = love.audio.newSource("hit.mp3")
 bounce = love.audio.newSource("bounce.mp3")
 loss = love.audio.newSource("loss.mp3")
 -- PLAYER SETUP
 player = {}
 function player.load()
 player.width = 70
 player.height = 20
 player.x = width/2 - player.width/2
 player.y = height - player.height
 player.speed = 400
 player.lives = 5
 player.points = 0
 end
 player.load()
 -- BLOCKS
 blocks = {}
 blocks.draw = {}
 -- LOAD BLOCKS
 function blocks.load()
 column = 0; row = 1
 while 5 >= row do
 block = {}
 block.width = width/10 - 5
 block.height = 20
 block.x = column * (block.width + 5)
 block.y = row * (block.height + 5)
 table.insert(blocks.draw, block)
 column = column + 1
 if column == 10 then column = 0; row = row + 1 end
 end
 end
 blocks.load()
 -- BALL
 ball = {}
 function ball.load()
 ball.radius = 5
 ball.x = width/2
 ball.y = player.y - 200
 ball.speed = 200
 ball.direction = "d"
 ball.cooldown = 200
 end
 ball.load()
 -- CHECK TOP FOR BOUNCE
 function topbounce()
 if ball.direction == "ull" then ball.direction = "dll"
 elseif ball.direction == "ul" then ball.direction = "dl"
 elseif ball.direction == "uul" then ball.direction = "ddl"
 elseif ball.direction == "u" then ball.direction = "d"
 elseif ball.direction == "uur" then ball.direction = "ddr"
 elseif ball.direction == "ur" then ball.direction = "dr"
 elseif ball.direction == "urr" then ball.direction = "drr"
 end
 end
end
------ UPDATE ------
function love.update(dt)
 if ball.cooldown > 0 then ball.cooldown = ball.cooldown - 1 end
 -- Player movement
 if love.keyboard.isDown("right") and player.x <= (width - player.width) then
 player.x = player.x + (dt * player.speed)
 elseif love.keyboard.isDown("left") and player.x >= 0 then
 player.x = player.x - (dt * player.speed)
 elseif love.keyboard.isDown("r") then
 ball.load()
 end
 -- Hitbox for player
 if ball.y >= player.y and ball.y <= height and ball.x >= player.x and
 ball.x <= (player.x + player.width) then
 if ball.x >= player.x and ball.x < (player.x + 10) then
 ball.direction = "ull"
 elseif ball.x >= (player.x + 10) and ball.x < (player.x + 20) then
 ball.direction = "ul"
 elseif ball.x >= (player.x + 20) and ball.x < (player.x + 30) then
 ball.direction = "uul"
 elseif ball.x >= (player.x + 30) and ball.x < (player.x + 40) then
 ball.direction = "u"
 elseif ball.x >= (player.x + 40) and ball.x < (player.x + 50) then
 ball.direction = "uur"
 elseif ball.x >= (player.x + 50) and ball.x < (player.x + 60) then
 ball.direction = "ur"
 elseif ball.x >= (player.x + 60) and ball.x < (player.x + 70) then
 ball.direction = "urr"
 end
 love.audio.play(bounce)
 end
 -- Hitbox for blocks
 for i,v in ipairs(blocks.draw) do
 if ball.y <= (v.y + v.height) and ball.y >= v.y then
 if ball.x <= (v.x + v.width) and ball.x >= v.x then
 topbounce()
 love.audio.play(hit)
 table.remove(blocks.draw, i)
 player.points = player.points + 1
 end
 end
 end
 -- Bounces ball off walls
 if (ball.x <= 0) or (ball.x >= width) then
 if ball.direction == "uur" then ball.direction = "uul"
 elseif ball.direction == "ur" then ball.direction = "ul"
 elseif ball.direction == "urr" then ball.direction = "ull"
 elseif ball.direction == "drr" then ball.direction = "dll"
 elseif ball.direction == "dr" then ball.direction = "dl"
 elseif ball.direction == "ddr" then ball.direction = "ddl"
 elseif ball.direction == "ddl" then ball.direction = "ddr"
 elseif ball.direction == "dl" then ball.direction = "dr"
 elseif ball.direction == "dll" then ball.direction = "drr"
 elseif ball.direction == "ull" then ball.direction = "urr"
 elseif ball.direction == "ul" then ball.direction = "ur"
 elseif ball.direction == "uul" then ball.direction = "uur"
 end
 love.audio.play(bounce)
 end
 -- Bounce ball off ceiling
 if ball.y <= 0 then topbounce() end
 -- Move ball
 if ball.cooldown == 0 then
 if ball.direction == "u" then
 ball.y = ball.y - 2 * (dt * ball.speed)
 elseif ball.direction == "uur" then
 ball.y = ball.y - 2 * (dt * ball.speed)
 ball.x = ball.x + 1 * (dt * ball.speed)
 elseif ball.direction == "ur" then
 ball.y = ball.y - 2 * (dt * ball.speed)
 ball.x = ball.x + 2 * (dt * ball.speed)
 elseif ball.direction == "urr" then
 ball.y = ball.y - 1 * (dt * ball.speed)
 ball.x = ball.x + 2 * (dt * ball.speed)
 elseif ball.direction == "drr" then
 ball.y = ball.y + 1 * (dt * ball.speed)
 ball.x = ball.x + 2 * (dt * ball.speed)
 elseif ball.direction == "dr" then
 ball.y = ball.y + 2 * (dt * ball.speed)
 ball.x = ball.x + 2 * (dt * ball.speed)
 elseif ball.direction == "ddr" then
 ball.y = ball.y + 2 * (dt * ball.speed)
 ball.x = ball.x + 1 * (dt * ball.speed)
 elseif ball.direction == "d" then
 ball.y = ball.y + 2 * (dt * ball.speed)
 elseif ball.direction == "ddl" then
 ball.y = ball.y + 2 * (dt * ball.speed)
 ball.x = ball.x - 1 * (dt * ball.speed)
 elseif ball.direction == "dl" then
 ball.y = ball.y + 2 * (dt * ball.speed)
 ball.x = ball.x - 2 * (dt * ball.speed)
 elseif ball.direction == "dll" then
 ball.y = ball.y + 1 * (dt * ball.speed)
 ball.x = ball.x - 2 * (dt * ball.speed)
 elseif ball.direction == "ull" then
 ball.y = ball.y - 1 * (dt * ball.speed)
 ball.x = ball.x - 2 * (dt * ball.speed)
 elseif ball.direction == "ul" then
 ball.y = ball.y - 2 * (dt * ball.speed)
 ball.x = ball.x - 2 * (dt * ball.speed)
 elseif ball.direction == "uul" then
 ball.y = ball.y - 2 * (dt * ball.speed)
 ball.x = ball.x - 1 * (dt * ball.speed)
 end
 end
 if ball.y >= height then
 love.audio.play(loss)
 player.lives = player.lives - 1; ball.load()
 end
 if player.lives < 0 then
 love.graphics.print("GAME OVER", width/2, height/2)
 love.load()
 end
end
------ DRAW ------
function love.draw()
 -- Cooldown
 if ball.cooldown > 0 then
 love.graphics.print("Get ready!", width/2, height/2)
 end
 -- Points/Lives
 love.graphics.print("Lives: " .. player.lives, 10, height/3)
 love.graphics.print("Points: " .. player.points, 10, height/3 + 20)
 -- Draw player
 love.graphics.setColor(255, 255, 255)
 love.graphics.rectangle("fill", player.x, player.y, player.width, player.height - 10)
 -- Draw blocks
 love.graphics.setColor(255, 0, 0)
 iter = 0
 for _,v in pairs(blocks.draw) do
 love.graphics.rectangle("fill", v.x, v.y, v.width, v.height)
 end
 -- Draw ball
 love.graphics.setColor(255, 255, 255)
 love.graphics.circle("fill", ball.x, ball.y, ball.radius)
end
Ethan Bierlein
15.9k4 gold badges59 silver badges146 bronze badges
asked Aug 5, 2015 at 23:25
\$\endgroup\$
1
  • \$\begingroup\$ This game is known as breakout \$\endgroup\$ Commented Sep 17, 2023 at 14:45

1 Answer 1

4
\$\begingroup\$

1) Instead of this:

if ball.direction == "uur" then ball.direction = "uul"
elseif ball.direction == "ur" then ball.direction = "ul"
elseif ball.direction == "urr" then ball.direction = "ull"
elseif ball.direction == "drr" then ball.direction = "dll"
elseif ball.direction == "dr" then ball.direction = "dl"
elseif ball.direction == "ddr" then ball.direction = "ddl"
elseif ball.direction == "ddl" then ball.direction = "ddr"
elseif ball.direction == "dl" then ball.direction = "dr"
elseif ball.direction == "dll" then ball.direction = "drr"
elseif ball.direction == "ull" then ball.direction = "urr"
elseif ball.direction == "ul" then ball.direction = "ur"
elseif ball.direction == "uul" then ball.direction = "uur"

You may want to use a table with all the values.

local WALL_BOUNCE = {
 uur = "uul",
 ur = "ul"
-- etc...
}

And in your function just use:

ball.direction = WALL_BOUNCE[ball.direction]

2) Another point:

if ball.direction == "u" then
 ball.y = ball.y - 2 * (dt * ball.speed)
elseif ball.direction == "uur" then
 ball.y = ball.y - 2 * (dt * ball.speed)
 ball.x = ball.x + 1 * (dt * ball.speed)
elseif ball.direction == "ur" then
 ball.y = ball.y - 2 * (dt * ball.speed)
 ball.x = ball.x + 2 * (dt * ball.speed)
elseif ball.direction == "urr" then
 ball.y = ball.y - 1 * (dt * ball.speed)
 ball.x = ball.x + 2 * (dt * ball.speed)
elseif ball.direction == "drr" then
 ball.y = ball.y + 1 * (dt * ball.speed)
 ball.x = ball.x + 2 * (dt * ball.speed)
elseif ball.direction == "dr" then
 ball.y = ball.y + 2 * (dt * ball.speed)
 ball.x = ball.x + 2 * (dt * ball.speed)
elseif ball.direction == "ddr" then
 ball.y = ball.y + 2 * (dt * ball.speed)
 ball.x = ball.x + 1 * (dt * ball.speed)
elseif ball.direction == "d" then
 ball.y = ball.y + 2 * (dt * ball.speed)
elseif ball.direction == "ddl" then
 ball.y = ball.y + 2 * (dt * ball.speed)
 ball.x = ball.x - 1 * (dt * ball.speed)
elseif ball.direction == "dl" then
 ball.y = ball.y + 2 * (dt * ball.speed)
 ball.x = ball.x - 2 * (dt * ball.speed)
elseif ball.direction == "dll" then
 ball.y = ball.y + 1 * (dt * ball.speed)
 ball.x = ball.x - 2 * (dt * ball.speed)
elseif ball.direction == "ull" then
 ball.y = ball.y - 1 * (dt * ball.speed)
 ball.x = ball.x - 2 * (dt * ball.speed)
elseif ball.direction == "ul" then
 ball.y = ball.y - 2 * (dt * ball.speed)
 ball.x = ball.x - 2 * (dt * ball.speed)
elseif ball.direction == "uul" then
 ball.y = ball.y - 2 * (dt * ball.speed)
 ball.x = ball.x - 1 * (dt * ball.speed)
end

You can use a table here too, it will have a format

local VELOCITY = {
 u = {0, -2},
 uur = {1, -2}
-- etc... 
-- direction = {velocity_x, velocity_y}
}
local velocity = VELOCITY[ball.direction]
ball.x = ball.x + velocity[1] * dt * ball.speed
ball.y = ball.y + velocity[2] * dt * ball.speed

3) Use local variables wherever possible. However for a simple project like this one this is not obligatory

answered Aug 6, 2015 at 11:44
\$\endgroup\$
7
  • \$\begingroup\$ What does the local keyword do? I'm guessing it extends the variable scope outside of the function, but as I am new to Lua, I don't really know. And thanks for the tables idea! do you think I could just make one table that stores the directions as keys and the value at index 1 will be the opposite direction and the value at index 2 will be the x and y values \$\endgroup\$ Commented Aug 6, 2015 at 15:27
  • \$\begingroup\$ 1) On the contrary, it limits the variable scope to that of the lexical block. It helps you avoid namespace pollution and variable names clashing. \$\endgroup\$ Commented Aug 6, 2015 at 15:29
  • \$\begingroup\$ 2) You can even write a function that will count direction characters in strings like "uur" and return the resulting velocity. But the table lookup will be faster, though it won't be obvious in this pong example. I think, however, that the explicit table mapping string directions and velocities is the better, than two tables with directions and opposites. It is just more readable. \$\endgroup\$ Commented Aug 6, 2015 at 15:34
  • \$\begingroup\$ if it keeps variable names from clashing does that mean theres no variable scope in Lua? if there was then why would you have to use local to keep variable names from crashing. Also I don't exactly know what a lexical block is or a namespace. This terminology is confusing a beginner like me haha. \$\endgroup\$ Commented Aug 6, 2015 at 15:38
  • \$\begingroup\$ So could i do something like for "u" in ball.direction do y = y-1 end or for "d" in ball.direction y=y+1 \$\endgroup\$ Commented Aug 6, 2015 at 15:41

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.