Show off clean code examples
Posted: Tue Nov 04, 2014 9:29 am
Hello boys and girls!
As a hobby programmer and aspring Game Designer I would like to see examples on how clean code should look like in Löve2D/Lua.
Sometimes I'm not very good keeping an eye on what different parts of the code does so I guess it would be beneficial not only for me but for others to see how clean code should look like.
Personally I would like to see how you Löve user code looks like, articles are good and all but I think it's more interesting to see others and it's entirely up to you if you want to show of your code or not.
I guess I start with a example on a not so clean and in my opinion confusing code from a game that I made:
I also want to mention that I have a better idea to keep check on my code by commenting on how different parts of the code works and as I mention above I would love to see your take on clean code.
As a hobby programmer and aspring Game Designer I would like to see examples on how clean code should look like in Löve2D/Lua.
Sometimes I'm not very good keeping an eye on what different parts of the code does so I guess it would be beneficial not only for me but for others to see how clean code should look like.
Personally I would like to see how you Löve user code looks like, articles are good and all but I think it's more interesting to see others and it's entirely up to you if you want to show of your code or not.
I guess I start with a example on a not so clean and in my opinion confusing code from a game that I made:
Code: Select all
local isSpacebarPressed
local frameNum
local colorList
local numLives
local maxTrailSize
local isPpressed
local isMpressed
local isRpressed
local SHOW_COLLISION_BOX
local ship
local shiplives
local smallAsteroid
local mediumAsteroid
local largeAsteroid
local menuImage
local gameoverImage
local numAsteroids
local asteroids
local isUpHeld
local isLeftHeld
local isRightHeld
local score
local sfx
local sfx2
local sfx3
local expSound
local trailPos
local state
local maxVelocity
local trailSprite
local highScore = 0
function resetGame()
print("in function resetGame")
isSpacebarPressed = false
frameNum = 1
colorList = {}
numLives = 5
maxTrailSize = 20
isPpressed = false
isMpressed = false
isRpressed = false
-- debug
SHOW_COLLISION_BOX = false
--Ship--
ship = {}
ship.xPos = 400
ship.yPos = 300
ship.theta = 4.71
ship.xVelocity = 0
ship.xAccel = 0.15
ship.w = 32
ship.h = 32
ship.sprite = love.graphics.newImage("ship2.png")
trailSprite = love.graphics.newImage("ship.png")
shipIcon = love.graphics.newImage("shiplives.png")
maxVelocity = 5.25
--Asteroid images--
smallAsteroidImage = love.graphics.newImage("asteroid16.png")
mediumAsteroidImage = love.graphics.newImage("asteroid32.png")
largeAsteroidImage = love.graphics.newImage("asteroid64.png")
menuImage = love.graphics.newImage("menu.png")
gameoverImage = love.graphics.newImage("gameoverMenu.png")
-- asteroid sfx
smallAsteroidSound = love.audio.newSource("pickup.wav")
mediumAsteroidSound = love.audio.newSource("pickup2.wav")
largeAsteroidSound = love.audio.newSource("pickup3.wav")
expSound = love.audio.newSource("deathSfx.wav")
--Asteroids--
numAsteroids = 20
asteroids = {}
--Asteroid spawner--
for i = 1, numAsteroids do
local rand = math.random(1,3)
asteroids[i] = {}
if rand == 1 then
asteroids[i].W = 16
asteroids[i].H = 16
asteroids[i].sprite = smallAsteroidImage
asteroids[i].v = 2.5
asteroids[i].pointValue = 10
asteroids[i].sfx = smallAsteroidSound
elseif rand == 2 then
asteroids[i].W = 32
asteroids[i].H = 32
asteroids[i].sprite = mediumAsteroidImage
asteroids[i].v = 1.3
asteroids[i].pointValue = 50
asteroids[i].sfx = mediumAsteroidSound
else
asteroids[i].W = 64
asteroids[i].H = 64
asteroids[i].sprite = largeAsteroidImage
asteroids[i].v = 1
asteroids[i].pointValue = 100
asteroids[i].sfx = largeAsteroidSound
end
rand = math.random(1,4)
if rand == 1 then
asteroids[i].X = math.random(-400, -64)
asteroids[i].Y = math.random(0, 600)
asteroids[i].theta = -0.785 + (math.random() * 1.57 )
elseif rand == 2 then
asteroids[i].X = math.random(864, 2000)
asteroids[i].Y = math.random(0, 600)
asteroids[i].theta = 2.35 + (math.random() * 1.57 )
elseif rand == 3 then
asteroids[i].X = math.random(0, 800)
asteroids[i].Y = math.random(-400, -64)
asteroids[i].theta = 0.398 + (math.random() * 1.57 )
else
asteroids[i].X = math.random(0, 800)
asteroids[i].Y = math.random(700, 2000)
asteroids[i].theta = 4.71 + (math.random() * 1.57 )
end
end
-- controls
isUpHeld = false
isLeftHeld = false
isRightHeld = false
--other
score = 0
-- pick some random colors
trailPos = {}
for i = 1, maxTrailSize do
local c = {}
c.r = math.random(255)
c.g = math.random(255)
c.b = math.random(255)
colorList[i] = c
end
--Check state
state = "menuState"
end
function love.load()
print( "in function love.load" )
resetGame()
end
function love.draw()
if state == "menuState" then
drawMenu()
elseif state == "gameState" then
drawGame()
elseif state == "gameoverState" then
drawGameover()
end
end
function love.update()
mainFont = love.graphics.newFont("Mojang-Regular.ttf", 20)
love.graphics.setFont(mainFont)
if state == "menuState" then
updateMenu()
elseif state == "gameState" then
updateGame()
elseif state == "gameoverState" then
updateGameover()
end
end
function updateMenu()
if isPpressed then
state = "gameState"
end
end
function updateGameover()
if isRpressed then
resetGame()
state = "gameState"
elseif isMpressed then
resetGame()
state = "menuState"
end
end
function updateGame()
-- stick the pos structure into the *front* of our trail list
if frameNum % 5 == 0 then
-- create a pos structure that represents where the ship is right now
local pos = {}
pos.x = ship.xPos
pos.y = ship.yPos
pos.theta = ship.theta
table.insert(trailPos, 1, pos)
if #trailPos > maxTrailSize then
table.remove(trailPos)
end
if not isSpacebarPressed then
table.remove(trailPos)
end
end
for i = 1, numAsteroids do
-- update position
asteroids[i].X = asteroids[i].X + math.cos(asteroids[i].theta) * asteroids[i].v
asteroids[i].Y = asteroids[i].Y + math.sin(asteroids[i].theta) * asteroids[i].v
-- check for asteroid going offscreen, if so then respawn
if asteroids[i].X > 900 or asteroids[i].Y > 700 or asteroids[i].X < -100 or asteroids[i].Y < -100 then
rand = math.random(1,4)
if rand == 1 then
asteroids[i].X = math.random(-100, -64)
asteroids[i].Y = math.random(0, 600)
asteroids[i].theta = -0.785 + (math.random() * 1.57 )
elseif rand == 2 then
asteroids[i].X = math.random(864, 900)
asteroids[i].Y = math.random(0, 600)
asteroids[i].theta = 2.35 + (math.random() * 1.57 )
elseif rand == 3 then
asteroids[i].X = math.random(0, 800)
asteroids[i].Y = math.random(-100, -64)
asteroids[i].theta = 0.398 + (math.random() * 1.57 )
else
asteroids[i].X = math.random(0, 800)
asteroids[i].Y = math.random(700, 900)
asteroids[i].theta = 4.71 + (math.random() * 1.57 )
end
end
end
for i = 1, numAsteroids do
---VVV SHIP TO ASTEROID COLLISION VVV
-- test each asteroid against our main ship...
if ship.xPos > asteroids[i].X and ship.xPos < asteroids[i].X + asteroids[i].W and ship.yPos > asteroids[i].Y and ship.yPos < asteroids[i].Y + asteroids[i].H then
asteroids[i].X = math.random(-100, -64)
asteroids[i].Y = math.random(0, 600)
asteroids[i].theta = -0.785 + (math.random() * 1.57 )
numLives = numLives - 1
ship.xPos = 400
ship.yPos = 300
trailPos = {}
love.audio.stop(expSound)
love.audio.play(expSound)
if numLives == 0 then
love.audio.stop(expSound)
love.audio.play(expSound)
if score > highScore then
highScore = score
end
state = 'gameoverState'
end
end
-- test each asteroid against every ship in the trail...
for j = 1, #trailPos do
if trailPos[j].x > asteroids[i].X and trailPos[j].x < asteroids[i].X + asteroids[i].W and trailPos[j].y > asteroids[i].Y and trailPos[j].y < asteroids[i].Y + asteroids[i].H then
asteroids[i].X = math.random(-100, -64)
asteroids[i].Y = math.random(0, 600)
asteroids[i].theta = -0.785 + (math.random() * 1.57 )
score = score + asteroids[i].pointValue
love.audio.stop(asteroids[i].sfx)
love.audio.play(asteroids[i].sfx)
end
end
end
-- Asteroid to asteroid collision
-- dont flip things twice!
local hasAlreadyFlipped = {}
for k = 1, numAsteroids do
hasAlreadyFlipped[k] = false
end
for i = 1, numAsteroids do
local curAsteroid = asteroids[i]
for j = 1, numAsteroids do
local isUpperLeftColliding = false
local isUpperRightColliding = false
local isLowerLeftColliding = false
local isLowerRightColliding = false
isUpperLeftColliding = curAsteroid.X > asteroids[j].X and
curAsteroid.X < asteroids[j].X + asteroids[j].W and
curAsteroid.Y > asteroids[j].Y and
curAsteroid.Y < asteroids[j].Y + asteroids[j].H
isUpperRightColliding = curAsteroid.X + curAsteroid.W > asteroids[j].X and
curAsteroid.X + curAsteroid.W < asteroids[j].X + asteroids[j].W and
curAsteroid.Y > asteroids[j].Y and
curAsteroid.Y < asteroids[j].Y + asteroids[j].H
isLowerLeftColliding = curAsteroid.X > asteroids[j].X and
curAsteroid.X < asteroids[j].X + asteroids[j].W and
curAsteroid.Y + curAsteroid.H > asteroids[j].Y and
curAsteroid.Y + curAsteroid.H < asteroids[j].Y + asteroids[j].H
isLowerRightColliding = curAsteroid.X + curAsteroid.W > asteroids[j].X and
curAsteroid.X + curAsteroid.W < asteroids[j].X + asteroids[j].W and
curAsteroid.Y + curAsteroid.H > asteroids[j].Y and
curAsteroid.Y + curAsteroid.H < asteroids[j].Y + asteroids[j].H
local isCurOnscreen = curAsteroid.X > 0 and curAsteroid.X < 800 and curAsteroid.Y > 0 and curAsteroid.Y < 600
local isOtherOnscreen = asteroids[j].X > 0 and asteroids[j].X < 800 and asteroids[j].Y > 0 and asteroids[j].Y < 600
if isCurOnscreen and isOtherOnscreen then
if isUpperLeftColliding or isUpperRightColliding or isLowerLeftColliding or isLowerRightColliding then
if hasAlreadyFlipped[i] == false then
curAsteroid.theta = curAsteroid.theta + math.pi
hasAlreadyFlipped[i] = true
end
if hasAlreadyFlipped[j] == false then
asteroids[j].theta = asteroids[j].theta + math.pi
hasAlreadyFlipped[j] = true
end
end
end
end
end
if isUpHeld == true then
ship.xVelocity = ship.xVelocity + 0.5
else
ship.xVelocity = ship.xVelocity - 0.075
end
if isLeftHeld == true then
ship.theta = ship.theta - 0.1
end
if isRightHeld == true then
ship.theta = ship.theta + 0.1
end
if ship.xVelocity < 0 then
ship.xVelocity = 0
end
if ship.xVelocity > maxVelocity then
ship.xVelocity = maxVelocity
end
ship.xPos = ship.xPos + math.cos(ship.theta) * ship.xVelocity
ship.yPos = ship.yPos + math.sin(ship.theta) * ship.xVelocity
if ship.xPos > 800 then
ship.xPos = 0
end
if ship.xPos < 0 then
ship.xPos = 800
end
if ship.yPos > 600 then
ship.yPos = 0
end
if ship.yPos < 0 then
ship.yPos = 600
end
frameNum = frameNum + 1
end
function drawMenu()
love.graphics.setColor(255, 255, 255)
love.graphics.draw(menuImage, 0, 0)
end
function drawGameover()
love.graphics.setColor(255, 255, 255)
love.graphics.draw(gameoverImage, 0, 0)
love.graphics.setColor(52, 89, 35)
love.graphics.print(score, 150, 240)
--love.graphics.print("best:"..highScore, 100, 340)
end
function drawGame()
love.graphics.setBackgroundColor(115, 138, 40)
for i = 1, numLives do
love.graphics.setColor(52, 89, 35)
love.graphics.draw( shipIcon, 32*i, 64, -math.pi/2 )
end
for i = #trailPos, 1, -1 do
local alpha = 255
love.graphics.setColor( colorList[i].r, colorList[i].g, colorList[i].b, alpha )
love.graphics.draw(trailSprite, trailPos[i].x, trailPos[i].y, trailPos[i].theta, 1, 1, 16, 16 )
end
love.graphics.setColor(255, 255, 255)
for i = 1, numAsteroids do
love.graphics.draw(asteroids[i].sprite, asteroids[i].X, asteroids[i].Y)
if SHOW_COLLISION_BOX then
love.graphics.setColor( math.random(255), math.random(255), math.random(255) )
love.graphics.rectangle( "line", asteroids[i].X, asteroids[i].Y, asteroids[i].W, asteroids[i].H )
love.graphics.setPointSize( 10 )
love.graphics.point( asteroids[i].X + asteroids[i].H, asteroids[i].Y + asteroids[i].H )
love.graphics.print( i, asteroids[i].X, asteroids[i].Y )
love.graphics.setColor( 255, 255, 255 )
end
end
love.graphics.setColor(52, 89, 35)
love.graphics.draw(ship.sprite, ship.xPos, ship.yPos, ship.theta, 1, 1, 16, 16)
if SHOW_COLLISION_BOX then
love.graphics.setColor( math.random(255), math.random(255), math.random(255) )
love.graphics.setPointSize( 3 )
love.graphics.point( ship.xPos, ship.yPos )
love.graphics.setColor( 255, 255, 255 )
end
love.graphics.setColor(52, 89, 35)
love.graphics.print(score, 45, 10, 0, 1, 1)
end
function love.keypressed(key)
if key == 'right' then
ship.theta = ship.theta + 0.1
end
if key == 'left' then
ship.theta = ship.theta - 0.1
end
if key == 'up' then
isUpHeld = true
end
if key == 'left' then
isLeftHeld = true
end
if key == 'right' then
isRightHeld = true
end
if key == 'escape' then
love.event.push( 'quit' )
end
if key == 'c' then
SHOW_COLLISION_BOX = not SHOW_COLLISION_BOX
end
if key == ' ' then
isSpacebarPressed = true
end
if key == 'p' then
isPpressed = true
end
if key == 'm' then
isMpressed = true
end
if key == 'r' then
isRpressed = true
end
end
function love.keyreleased(key)
if key == 'up' then
isUpHeld = false
end
if key == 'left' then
isLeftHeld = false
end
if key == 'right' then
isRightHeld = false
end
if key == ' ' then
isSpacebarPressed = false
end
if key == 'p' then
isPpressed = false
end
if key == 'm' then
isMpressed = false
end
if key == 'r' then
isRpressed = false
end
end