Introduction

The Raspberry Pi isn't just a popular choice for learning about physical computing, but also game development. If you haven't already, check out the basics on how to install, set up and use LÖVE on the Raspberry Pi 4

In this guide, we'll show you how to build an endless runner/space shooter game on the Raspberry Pi 4. Instead of aliens and bullets, we'll create a talking nyan cat, grumpy cats, shooting hearts and lots of tasty treats. 

Complete this guide to create your own space shooters game. While doing so, learn about the three main callback functions in the LOVE framework, custom functions, conditional statements, for loops, and animations.
    • The Raspberry Pi is a popular choice for learning about physical computing, gaming, robotics, and a whole heap of other wondrous topics. It's  a fantastic time to tinker and play around with the Raspberry Pi 4 if you're a gaming enthusiast! After all, it's now possible to run the Dreamcast emulator, REDREAM on the Raspberry Pi 4. It's also possible to build your own games. If you haven't already, check out the basics on how to install, set up and use LÖVE on the Raspberry Pi 4

      In this guide, we'll show you how to build an endless runner/space shooter game on the Raspberry Pi 4. Instead of aliens and bullets, we'll create a talking nyan cat, grumpy cats, shooting hearts and lots of tasty treats. While doing so, learn about the three main callback functions in the LOVE framework, custom functions, conditional statements, for loops, and animations.

    • Open up your pixel art tool of choice and create some sprites. Using Aseprite, we created a start/menu screen, sprites for nyan cat and a rainbow trail (player), grumpy cat (obstacles), cake (items) and a tiny heart (projectile). 

    • In this guide, we've created a start/menu screen (800x600 pixels), a space background image (800x600 pixels), a spritesheet for nyan cat (320x64 pixels), static images (64x64 pixels) for the cake, grumpy cat, and heart (16x16 pixels).

  1. function love.load()
    	startscreen = love.graphics.newImage("startscreen.png")
    	startbtn = love.graphics.newImage("startbutton.png")
    	startblurb = love.graphics.newImage("startblurb.png")
    	background = love.graphics.newImage("mainbg.png")
    	cakeSprite = love.graphics.newImage("item.png")
    	enemySprite = love.graphics.newImage("grumpycat.png")
    end
    • Now that the sprites have been created, it's time to load them up into the game. The love.load function is called exactly once at the beginning of the game. This is where we load our image assets for the game.

    • For each sprite, load it with love.graphics.newImage and store it in a separately named variable. These variables will be used to refer to the sprite in the program.

    • A variable can be thought of as a word in which you can store a value. For example, using the variable enemySprite, the grumpycat.png sprite is stored to it by using the love.graphics.newImage function.

  2. function love.load()
    	startscreen = love.graphics.newImage("startscreen.png")
    	startbtn = love.graphics.newImage("startbutton.png")
    	startblurb = love.graphics.newImage("startblurb.png")
    	background = love.graphics.newImage("mainbg.png")
    	cakeSprite = love.graphics.newImage("item.png")
    	enemySprite = love.graphics.newImage("grumpycat.png")
    	font = love.graphics.newFont("Retro Gaming.ttf", 24)
    	love.graphics.setFont(font)
    end
    • The love.load function is also where we can load any custom fonts by using love.graphics.newFont 

    • Remember to set the font in the game by using love.graphics.setFont

  3. function love.load()
    	startscreen = love.graphics.newImage("startscreen.png")
    	startbtn = love.graphics.newImage("startbutton.png")
    	startblurb = love.graphics.newImage("startblurb.png")
    	background = love.graphics.newImage("mainbg.png")
    	cakeSprite = love.graphics.newImage("item.png")
    	enemySprite = love.graphics.newImage("grumpycat.png")
    	font = love.graphics.newFont("Retro Gaming.ttf", 24)
    	love.graphics.setFont(font)
    	currentScreen = 'menu'
    	Sx, Sy = love.graphics.getDimensions()
    	items = {}
    	enemies = {}
    end
    • You can do more than store sprites in variables. Create a new variable named currentScreen and set its value to the string menu

      This string will be used to check on the game state later on in our code.

    • To easily get the width and height in pixels of the game window within our code, this can be done by using the love.graphics.getDimensions function, and place them in variables Sx and Sy

    • Next, create a table and assign it to variable items to store the cakes.

    • Then create another empty table and assign it to the variable enemies which will be used to store the grumpy cats.

    • To create a table use the table constructor, which are defined by using curly brackets, i.e. { }.

      Tables are the main data structuring mechanism in Lua. We can use tables to represent lists, arrays, sets, and many other data structures.

      In fact, they are the only "container" type in Lua programming. These are associative which means they store key/value pairs. In a key/value pair, you can store a value under a key and then later retrieve the value by using that particular key. 

  4. local anim8 = require 'anim8'
    local playerSpritesheet, animation 
    • How can we implement animations into the game? One quick and easy way is to incorporate a library such as anim8 which helps you create animations for LÖVE.

      The latest version of anim8 can always be found on its github page, so navigate over to: https://github.com/kikito/anim8

    • Download the folder then copy the anim8.lua file into your project folder where main.lua is stored.

    • Then place this code at the very top of the program, before love.load

  5. function createPlayer()
    	player = {
    		x = 0,
    		y = 250, 
    		health = 3,
    		alive = true,
    		score = 0,
    		bullets = {},
    		bulletSprite = love.graphics.newImage("heartbullet.png"),
    		rainbow = love.graphics.newImage('rainbow-trails.png'),
    		cooldown = 20,
    		speed = 5,
    		dialogue = {},
    		sentences = {"FOOD!","NYAAAAN!","Cake!","Yay.","OM NOM NOM"},
    		fire = function()
    		if player.cooldown <= 0 then 
    			player.cooldown = 50
    			bullet = {}
    			bullet.x = player.x + 35
    			bullet.y = player.y + 25
    			table.insert(player.bullets, bullet)
    		end
    	end
    	}
    	playerSpritesheet = love.graphics.newImage('player-spritesheet.png')
    	g = anim8.newGrid(64,64,playerSpritesheet:getWidth(),playerSpritesheet:getHeight())
    	g2 = anim8.newGrid(64,64,player.rainbow:getWidth(),player.rainbow:getHeight())
    	-- animation for player sprite
    	animation = anim8.newAnimation(g('1-4',1),0.1)
    	-- animation for rainbow trail
    	animation2 = anim8.newAnimation(g2('1-1',1),0.1)
    end
    • Next, create a new function and name it createPlayer. Here, create a new table and name it player, then add various attributes of the player such as its x coordinate, y coordinate, health, score, and so on. 

    • So that nyan cat has multiple lines for dialogue, two tables were created. The first table was named sentences which holds five strings while the second table was empty and named dialogue. Every time a collision between nyan cat and cake sprite is detected, a random string from sentences is inserted into the dialogue table.

  6. function collision(x1, y1, width1, height1, x2, y2, width2, height2)
    	if x2 + width2 > x1 and x2 < x1 + width1 then
    		if y2 + height2 > y1 and y2 < y1 + height1 then
    			return true
    		end
    	end
    	return false
    end
    
    • To create a collision check function, we will be checking between "rectangles" or "collision boxes". Add the following function that will detect when collisions occur. 

  7. function newItem(x,y)
    	item = {}
    	item.x = x
    	item.y = y
    	function item.update(dt)
    		for i, item in pairs(items) do
    			if item.x < -10 then 
    				table.remove(items,i)
    			end
    			if collision(player.x, player.y, 64, 64, item.x, item.y, 16, 16) then 
    				table.remove(items, i)
    				player.score = player.score + 10
    				table.insert(player.dialogue,player.sentences[math.random(#player.sentences)])
    				player.speaking = true
    			end
    		end
    	end
    	table.insert(items,item)
    end
    • What's a game without some obstacles and items? Create a new function and name it newItem() 

  8. function newEnemy(x,y)
    	enemy = {}
    	enemy.x = x
    	enemy.y = y 
    	function enemy.update(dt)
    		for i, enemy in pairs(enemies) do
    			if enemy.x < -10 then
    				table.remove(enemies,i)
    			end
    			for i, b in pairs(player.bullets) do 
    				if collision(bullet.x,bullet.y,16,16,enemy.x,enemy.y,64,64) then
    					table.remove(enemies,i)
    					table.remove(player.bullets,i)
    					player.score = player.score + 100
    				end
    			end
    			if collision(player.x,player.y,64,64,enemy.x,enemy.y,32,32) then
    				table.remove(enemies,i)
    				if player.health > 0 then 
    					player.hit = true 
    					player.health = player.health - 1
    					animation = anim8.newAnimation(g('5-5',1),0.1)
    				end
    			end
    		end
    	end
    	table.insert(enemies,enemy)
    end
    • Create a new function and name it newEnemy()

  9. function love.load()
    	startscreen = love.graphics.newImage("startscreen.png")
    	startbtn = love.graphics.newImage("startbutton.png")
    	startblurb = love.graphics.newImage("startblurb.png")
    	background = love.graphics.newImage("mainbg.png")
    	enemySprite = love.graphics.newImage("grumpycat.png")
    	cakeSprite = love.graphics.newImage("item.png")
    	backgroundPosition = 0
    	currentScreen = 'menu'
    	font = love.graphics.newFont("Retro Gaming.ttf", 24)
    	love.graphics.setFont(font)
    	Sx, Sy = love.graphics.getDimensions()
    	items = {}
    	enemies = {}
    	time = 0
    	timeLimit = 3
    	createPlayer()
    	-- spawn items at start
    	for i = 1, math.random(0,10) do
    		newItem(math.random(0,700),math.random(0,500))
    	end
    end
    • Update love.load with the following code. Now, the createPlayer function will be called immediately when the game starts. Using a for loop and math.random function, a randomised number of cakes will be generated at random x and y coordinates.

    • We have created two very important variables : time and timeLimit 

      These variables will be crucial for the generation of cakes and grumpy cats throughout the game. 

  10. function love.update(dt)
    	if currentScreen == 'menu' then
    		menuUpdate(dt)
    	elseif currentScreen == 'game' then
    	    gameUpdate(dt)
    	    animation:update(dt)
    	end
    end
    • For our menu screen, we simply want to display the start/menu screen created earlier on, until the 'x' key has been pressed. Once the 'x' key is pressed, then the game starts. So go ahead and add a conditional statement if currentScreen == 'menu' then 

    • Although we have not yet created the menuUpdate(dt) function, it is within love.update(dt) where it will be called. So go ahead and call menuUpdate(dt). 

    • Then add another condition elseif currentScreen == 'game' then 

    • Again, these functions have not yet been created but it is here where they will be called: gameUpdate(dt) and animation:update(dt)

  11. function love.draw()
    	if currentScreen == 'menu' then
    		-- draw start menu
    		love.graphics.draw(startscreen, Sx/2,Sy/2, 0, 1, 1, startscreen:getWidth()/2, startscreen:getHeight()/2)
    		love.graphics.draw(startblurb, Sx/2+250,Sy/2+150, 0, 1, 1, startblurb:getWidth()/2, startblurb:getHeight()/2)
    		love.graphics.draw(startbtn, Sx/2+225,Sy/2+225, 0, 1, 1, startbtn:getWidth()/2, startbtn:getHeight()/2)
    	end
    	if currentScreen == 'game' then
    		-- draw the background
    		love.graphics.draw(background, backgroundPosition, 0, 0, 1, 1)
    		love.graphics.draw(background, backgroundPosition + 800, 0, 0, 1, 1)
    		-- draw the player
    		animation2:draw(player.rainbow,player.x-50,player.y)
    		animation2:draw(player.rainbow,player.x-100,player.y)
    		animation:draw(playerSpritesheet,player.x,player.y)
    		-- draw bullets
    		for _, b in pairs(player.bullets) do 
    			love.graphics.draw(player.bulletSprite,b.x,b.y,0,1,1)
    		end
    		-- draw items
    		for _, item in pairs(items) do
    			love.graphics.draw(cakeSprite,item.x,item.y)
    		end
    		-- draw enemies
    		for _,enemy in pairs(enemies) do
    			love.graphics.draw(enemySprite,enemy.x,enemy.y)
    		end
    		-- draw score
    		love.graphics.print("Score: " .. player.score,50,30,0,1,1)
    		-- draw player health
    		love.graphics.print("Health: " .. player.health,50,60,0,1,1)
    		-- draw player dialogue
    		if player.speaking == true then
    			playerDialogue()
    		end
    		-- if player goes off bottom of screen then game over condition reached 
    		if player.y > love.graphics.getHeight() or player.health == 0 then
    			animation = anim8.newAnimation(g('5-5',1),0.1)
    			love.graphics.print("GAME OVER. PRESS X TO RESTART.", 150,250)
    			player.alive = false
    			player.health = 0
    			if love.keyboard.isDown("x") then
    				love.load()
    			end
    		end
    	end
    end
    
    • Add the following code in love.draw function. As it was the case for love.load, the love.draw function is a callback function and it is used to draw on the screen every frame.

  12. function menuUpdate(dt)
    	if love.keyboard.isDown("x") then
    		currentScreen = 'game'
    	end
    end
    
    • All the menuUpdate function does is check to see if the 'x' key has been pressed. Once it has been pressed, the game starts and the value of currentScreen is changed to 'game'

  13. function playerUpdate(dt)
    -- all this code is required in gameUpdate(dt) function
    	player.cooldown = player.cooldown - 1
    	-- player's y position always moving by 2 every frame
    	player.y = player.y+2
    	-- player x coordinate shifts by 1 if it is less than 100 every frame
    	if player.x < 100 then
    		player.x = player.x+1
    	end
    	-- player controls: can move up or fire hearts
    	if player.alive == true then
    		if love.keyboard.isDown("up") then
    			player.y = player.y-player.speed
    		end
    		if love.keyboard.isDown("z") then 
    			player.fire()
    		end
    	end
    	-- update bullets table
    	for i, b in pairs(player.bullets) do
    		if b.x < 10 then 
    			table.remove(player.bullets, i)
    		end
    		b.x = b.x + 10
    	end
    	function playerDialogue()
    		if player.dialogue[1] then
    			if player.alive == true then 
    				love.graphics.print(player.dialogue[1],player.x+25,player.y-50)
    			end
    		end
    	end
    end
    
    • Now that we've got a function that creates the player, we still need one that contains all the code that will update the player throughout the game. So go ahead and create a new function and name it playerUpdate(dt)

  14. function gameUpdate(dt)
    	time = time + dt 
    
    	if time >= timeLimit then
    		-- generate items and enemies at random coordinates
    		for i = 1, math.random(0,10) do
    			newItem(800 + math.random(0,700),math.random(0,500))
    		end
    		for i =1, math.random(0,3) do
    			newEnemy(800 + math.random(0,700),math.random(0,500))
    		end
    		-- at the end of the time timit, remove string from dialogue table
    		table.remove(player.dialogue,1)
    		-- remove time = 0 for no repeats
    		time = 0
    	end
    	if time >= 1 then 
    		if player.hit == true then 
    			animation = anim8.newAnimation(g('1-4',1),0.1)
    			player.hit = false
    		end
    	end
    
    	-- items and enemies' x position always moving by 2 every frame
    	for i, item in ipairs(items) do
    		item.x = item.x - 2
    	end
    	for i, enemy in ipairs(enemies) do
    		enemy.x = enemy.x - 2
    	end
    
    	-- Update the player
    	playerUpdate()
    
    	-- parallax background
    	if backgroundPosition > -800 then
    		backgroundPosition = backgroundPosition - dt * 100
    	else
    	    backgroundPosition = 0
    	end
    
    	-- update items table
    	for i, item in ipairs(items) do
    		item.update(dt)
    	end
    
    	-- update enemies table
    	for i, enemy in ipairs(enemies) do
    		enemy.update(dt)
    	end
    end
    • While we could have added this chunk of code within love.update(dt), to organise it we have created a new function and named it gameUpdate(dt)

      Previously, a new variable time was created and set to 0 and a timeLimit was created and set to 5 in love.load

      These two variables will be used in a conditional statement within gameUpdate(dt) to create a timer for our game. As the comments in the code indicates, this timer is used to generate cakes and grumpy cats at random coordinates. It is also used to remove the latest added string from the dialogue table. Within tfunction is also where the playerUpdate function will be called, parallax scrolling created, and the items and enemies tables updated. 

    • dt stands for delta-time. It is the most common shorthand for delta-time, which is usually passed through love.update to represent the amount of time which has passed since it was last called. Although, the LOVE wiki does state: It is in seconds, but because of the speed of modern processors is usually smaller than 1, values like 0.01 are common

    • A frame refers to the image we see on screen, which gets updated a certain number of times a second. The frequency in which the frame is updated is known as frame rate, usually measured in frames per second (fps).

  15. local anim8 = require 'anim8'
    local playerSpritesheet, animation 
    
    function love.load()
    	startscreen = love.graphics.newImage("startscreen.png")
    	startbtn = love.graphics.newImage("startbutton.png")
    	startblurb = love.graphics.newImage("startblurb.png")
    	background = love.graphics.newImage("mainbg.png")
    	backgroundPosition = 0
    	currentScreen = 'menu'
    	font = love.graphics.newFont("Retro Gaming.ttf", 24)
    	love.graphics.setFont(font)
    	Sx, Sy = love.graphics.getDimensions()
    	items = {}
    	cakeSprite = love.graphics.newImage("item.png")
    	time = 0
    	timeLimit = 3
    	createPlayer()
    	enemies = {}
    	enemySprite = love.graphics.newImage("grumpycat.png")
    	-- spawn items at start
    	for i = 1, math.random(0,10) do
    		newItem(math.random(0,700),math.random(0,500))
    	end
    end
    
    function createPlayer()
    	player = {
    		x = 0,
    		y = 250, 
    		health = 3,
    		alive = true,
    		score = 0,
    		bullets = {},
    		bulletSprite = love.graphics.newImage("heartbullet.png"),
    		rainbow = love.graphics.newImage('rainbow-trails.png'),
    		cooldown = 20,
    		speed = 5,
    		dialogue = {},
    		sentences = {"FOOD!","NYAAAAN!","Cake!","Yay.","OM NOM NOM"},
    		fire = function()
    		if player.cooldown <= 0 then 
    			player.cooldown = 50
    			bullet = {}
    			bullet.x = player.x + 35
    			bullet.y = player.y + 25
    			table.insert(player.bullets, bullet)
    		end
    	end
    	}
    	playerSpritesheet = love.graphics.newImage('player-spritesheet.png')
    	g = anim8.newGrid(64,64,playerSpritesheet:getWidth(),playerSpritesheet:getHeight())
    	g2 = anim8.newGrid(64,64,player.rainbow:getWidth(),player.rainbow:getHeight())
    	animation = anim8.newAnimation(g('1-4',1),0.1)
    	animation2 = anim8.newAnimation(g2('1-1',1),0.1)
    end
    
    function playerUpdate(dt)
    -- all this code is required in gameUpdate(dt) function
    	player.cooldown = player.cooldown - 1
    	-- player's y position always moving by 2 every frame
    	player.y = player.y+2
    	-- player x coordinate shifts by 1 if it is less than 100 every frame
    	if player.x < 100 then
    		player.x = player.x+1
    	end
    	-- player controls: can move up or fire hearts
    	if player.alive == true then
    		if love.keyboard.isDown("up") then
    			player.y = player.y-player.speed
    		end
    		if love.keyboard.isDown("z") then 
    			player.fire()
    		end
    	end
    	-- update bullets table
    	for i, b in pairs(player.bullets) do
    		if b.x < 10 then 
    			table.remove(player.bullets, i)
    		end
    		b.x = b.x + 10
    	end
    	function playerDialogue()
    		if player.dialogue[1] then
    			if player.alive == true then 
    				love.graphics.print(player.dialogue[1],player.x+25,player.y-50)
    			end
    		end
    	end
    end
    
    
    function collision(x1, y1, width1, height1, x2, y2, width2, height2)
    	if x2 + width2 > x1 and x2 < x1 + width1 then
    		if y2 + height2 > y1 and y2 < y1 + height1 then
    			return true
    		end
    	end
    	return false
    end
    
    
    function newItem(x,y)
    	item = {}
    	item.x = x
    	item.y = y
    	function item.update(dt)
    		for i, item in pairs(items) do
    			if item.x < -10 then 
    				table.remove(items,i)
    			end
    			if collision(player.x, player.y, 64, 64, item.x, item.y, 16, 16) then 
    				table.remove(items, i)
    				player.score = player.score + 10
    				table.insert(player.dialogue,player.sentences[math.random(#player.sentences)])
    				player.speaking = true
    			end
    		end
    	end
    	table.insert(items,item)
    end
    
    
    function newEnemy(x,y)
    	enemy = {}
    	enemy.x = x
    	enemy.y = y 
    	function enemy.update(dt)
    		for i, enemy in pairs(enemies) do
    			if enemy.x < -10 then
    				table.remove(enemies,i)
    			end
    			for i, b in pairs(player.bullets) do 
    				if collision(bullet.x,bullet.y,16,16,enemy.x,enemy.y,64,64) then
    					table.remove(enemies,i)
    					table.remove(player.bullets,i)
    					player.score = player.score + 100
    				end
    			end
    			if collision(player.x,player.y,64,64,enemy.x,enemy.y,32,32) then
    				table.remove(enemies,i)
    				if player.health > 0 then 
    					player.hit = true 
    					player.health = player.health - 1
    					animation = anim8.newAnimation(g('5-5',1),0.1)
    				end
    			end
    		end
    	end
    	table.insert(enemies,enemy)
    end
    
    
    function menuUpdate(dt)
    	if love.keyboard.isDown("x") then
    		currentScreen = 'game'
    	end
    end
    
    function gameUpdate(dt)
    	time = time + dt 
    
    	if time >= timeLimit then
    		-- generate items and enemies at random coordinates
    		for i = 1, math.random(0,10) do
    			newItem(800 + math.random(0,700),math.random(0,500))
    		end
    		for i =1, math.random(0,3) do
    			newEnemy(800 + math.random(0,700),math.random(0,500))
    		end
    		table.remove(player.dialogue,1)
    		time = 0
    	end
    	if time >= 1 then 
    		if player.hit == true then 
    			animation = anim8.newAnimation(g('1-4',1),0.1)
    			player.hit = false
    		end
    	end
    	-- items and enemies' x position always moving by 2 every frame
    	for i, item in ipairs(items) do
    		item.x = item.x - 2
    	end
    	for i, enemy in ipairs(enemies) do
    		enemy.x = enemy.x - 2
    	end
    	-- Update the player
    	playerUpdate()
    	-- parallax background
    	if backgroundPosition > -800 then
    		backgroundPosition = backgroundPosition - dt * 100
    	else
    	    backgroundPosition = 0
    	end
    	-- update items table
    	for i, item in ipairs(items) do
    		item.update(dt)
    	end
    	-- update enemies table
    	for i, enemy in ipairs(enemies) do
    		enemy.update(dt)
    	end
    end
    
    function love.update(dt)
    	if currentScreen == 'menu' then
    		menuUpdate(dt)
    	elseif currentScreen == 'game' then
    	    gameUpdate(dt)
    	    animation:update(dt)
    	end
    end
    
    function love.draw()
    	if currentScreen == 'menu' then
    		-- draw start menu
    		love.graphics.draw(startscreen, Sx/2,Sy/2, 0, 1, 1, startscreen:getWidth()/2, startscreen:getHeight()/2)
    		love.graphics.draw(startblurb, Sx/2+250,Sy/2+150, 0, 1, 1, startblurb:getWidth()/2, startblurb:getHeight()/2)
    		love.graphics.draw(startbtn, Sx/2+225,Sy/2+225, 0, 1, 1, startbtn:getWidth()/2, startbtn:getHeight()/2)
    	end
    	if currentScreen == 'game' then
    		-- draw the background
    		love.graphics.draw(background, backgroundPosition, 0, 0, 1, 1)
    		love.graphics.draw(background, backgroundPosition + 800, 0, 0, 1, 1)
    		-- draw the player
    		animation2:draw(player.rainbow,player.x-50,player.y)
    		animation2:draw(player.rainbow,player.x-100,player.y)
    		animation:draw(playerSpritesheet,player.x,player.y)
    		-- draw bullets
    		for _, b in pairs(player.bullets) do 
    			love.graphics.draw(player.bulletSprite,b.x,b.y,0,1,1)
    		end
    		-- draw items
    		for _, item in pairs(items) do
    			love.graphics.draw(cakeSprite,item.x,item.y)
    		end
    		-- draw enemies
    		for _,enemy in pairs(enemies) do
    			love.graphics.draw(enemySprite,enemy.x,enemy.y)
    		end
    		-- draw score
    		love.graphics.print("Score: " .. player.score,50,30,0,1,1)
    		-- draw player health
    		love.graphics.print("Health: " .. player.health,50,60,0,1,1)
    		-- draw player dialogue
    		if player.speaking == true then
    			playerDialogue()
    		end
    		-- if player goes off bottom of screen then game over condition reached 
    		if player.y > love.graphics.getHeight() or player.health == 0 then
    			animation = anim8.newAnimation(g('5-5',1),0.1)
    			love.graphics.print("GAME OVER. PRESS X TO RESTART.", 150,250)
    			player.alive = false
    			player.health = 0
    			if love.keyboard.isDown("x") then
    				love.load()
    			end
    		end
    	end
    end
    
    • The complete code can be seen on the left.