Programming Fundamentals  
Lecture 06 – Arrays, Matrices, Animations and  
World Representations  
Edirlei Soares de Lima  
<edirlei.lima@universidadeeuropeia.pt>  
Arrays  
•
Arrays are sequences of items (like variables) of the same  
type.  
–
Each item is identified by an index (integer).  
•
With arrays we can store in memory sequences of values  
numbers, text, imagens, etc.), which are all associated with a  
single variable (the array).  
(
Arrays in Lua  
•
•
•
In Lua, are implemented through tables indexed by integer  
numbers.  
Different from many other programming languages, in Lua we  
don't need to define the maximum size of an array.  
Creating a new array:  
my_array = {}  
Arrays in Lua  
•
Initializing some positions of the array:  
my_array[1] = 5  
my_array[2] = 11  
my_array[5] = 0  
my_array[10] = 3  
Table Functions  
•
•
•
Size of an array:  
arr = {1, 2, 1, 6}  
size = #arr  
Add elements:  
arr = {1, 2, 1, 6}  
table.insert(arr, 8)  
table.insert(arr, 1, 10)  
Remove elements:  
arr = {1, 2, 1, 6}  
table.remove(arr, 4)  
table.remove(arr, 1)  
Example 1: Platforms, Arrays and Camera  
require "vector2"  
level.lua  
function CreatePlatform(world, x, y, w, h)  
local platform = {}  
platform.body = love.physics.newBody(world, x+(w/2), y+(h/2), "static")  
platform.shape = love.physics.newRectangleShape(w, h)  
platform.fixture = love.physics.newFixture(platform.body,  
platform.shape, 2)  
platform.fixture:setUserData("platform")  
return platform  
end  
function DrawLevel(level)  
for i = 1, #level, 1 do  
love.graphics.polygon("fill", level[i].body:getWorldPoints(  
level[i].shape:getPoints()))  
end  
end  
Example 1: Platforms, Arrays and Camera  
require "vector2"  
player.lua  
local player  
function CreatePlayer(world)  
player = {}  
player.body = love.physics.newBody(world, 200, 100, "dynamic")  
player.shape = love.physics.newRectangleShape(30, 60)  
player.fixture = love.physics.newFixture(player.body, player.shape, 1)  
player.maxvelocity = 200  
player.onground = false  
player.fixture:setFriction(1)  
player.fixture:setUserData("player")  
player.body:setFixedRotation(true)  
end  
function UpdatePlayer(dt)  
if love.keyboard.isDown("right") then  
local moveForce = vector2.new(700, 0)  
player.body:applyForce(moveForce.x, moveForce.y)  
end  
.
..  
Example 1: Platforms, Arrays and Camera  
..  
.
player.lua  
if love.keyboard.isDown("left") then  
local moveForce = vector2.new(-700, 0)  
player.body:applyForce(moveForce.x, moveForce.y)  
end  
if love.keyboard.isDown("up") and player.onground == true then  
local jumpForce = vector2.new(0, -500)  
player.body:applyLinearImpulse(jumpForce.x, jumpForce.y)  
player.onground = false  
end  
local velocity = vector2.new(player.body:getLinearVelocity())  
if velocity.x > 0 then  
player.body:setLinearVelocity(math.min(velocity.x,  
player.maxvelocity), velocity.y)  
else  
player.body:setLinearVelocity(math.max(velocity.x,  
player.maxvelocity), velocity.y)  
-
end  
end  
..  
.
Example 1: Platforms, Arrays and Camera  
..  
.
player.lua  
function DrawPlayer()  
love.graphics.polygon("fill", player.body:getWorldPoints(  
player.shape:getPoints()))  
end  
function BeginContactPlayer(fixtureA, fixtureB, contact)  
if fixtureA:getUserData() == "platform“ and  
fixtureB:getUserData() == "player" then  
local normal = vector2.new(contact:getNormal())  
if normal.y == -1 then  
player.onground = true  
end  
end  
end  
function GetPlayerPosition()  
return vector2.new(player.body:getPosition())  
end  
Example 1: Platforms, Arrays and Camera  
require "player"  
require "level"  
main.lua  
local world  
local level1  
function love.load()  
love.physics.setMeter(30)  
world = love.physics.newWorld(0, 9.81 * love.physics.getMeter(), true)  
world:setCallbacks(BeginContact, nil, nil, nil)  
level1 = {}  
level1[1] = CreatePlatform(world, 50, 550, 1200, 50)  
level1[2] = CreatePlatform(world, 500, 450, 50, 50)  
level1[3] = CreatePlatform(world, 750, 500, 100, 50)  
level1[4] = CreatePlatform(world, 1000, 420, 150, 50)  
CreatePlayer(world)  
end  
function BeginContact(fixtureA, fixtureB, contact)  
BeginContactPlayer(fixtureA, fixtureB, contact)  
end  
.
..  
Example 1: Platforms, Arrays and Camera  
function love.update(dt)  
world:update(dt)  
UpdatePlayer(dt)  
main.lua  
end  
function love.draw()  
love.graphics.push()  
local playerPosition = GetPlayerPosition()  
love.graphics.translate(-(playerPosition.x) + 380, 0)  
love.graphics.setColor(0,0,1)  
DrawPlayer()  
love.graphics.setColor(0,1,0)  
DrawLevel(level1)  
love.graphics.pop()  
love.graphics.setColor(1,1,1)  
love.graphics.print("UI Elements", 20, 20)  
end  
Example 2: Arrays and Enemies  
require "vector2"  
enemy.lua  
function CreateEnemy(world, x, y, t, i)  
local enemy = {}  
enemy.body = love.physics.newBody(world, x, y, "dynamic")  
enemy.shape = love.physics.newRectangleShape(30, 30)  
enemy.fixture = love.physics.newFixture(enemy.body, enemy.shape, 3)  
enemy.body:setFixedRotation(true)  
enemy.fixture:setFriction(1)  
enemy.fixture:setUserData({type = "enemy", index = i})  
enemy.type = t  
enemy.maxvelocity = 200  
enemy.direction = vector2.new(-1, 0)  
enemy.moveTimer = 3  
if t == 1 then  
enemy.timeToMove = 1.5  
elseif t == 2 then  
enemy.timeToMove = 3  
end  
return enemy  
end  
Example 2: Arrays and Enemies  
function UpdateEnemies(dt, enemies)  
for i = 1, #enemies, 1 do  
if enemies[i] then  
enemy.lua  
if enemies[i].type == 1 then  
local moveForce = vector2.mult(enemies[i].direction, 800)  
enemies[i].body:applyForce(moveForce.x, moveForce.y)  
enemies[i].moveTimer = enemies[i].moveTimer + dt  
if enemies[i].moveTimer > enemies[i].timeToMove then  
enemies[i].direction = vector2.mult(enemies[i].direction, -1)  
enemies[i].moveTimer = 0  
end  
local velocity = vector2.new(  
enemies[i].body:getLinearVelocity())  
if velocity.x > 0 then  
enemies[i].body:setLinearVelocity(math.min(velocity.x,  
enemies[i].maxvelocity), velocity.y)  
else  
enemies[i].body:setLinearVelocity(math.max(velocity.x,  
-
enemies[i].maxvelocity), velocity.y)  
end  
...  
Example 2: Arrays and Enemies  
.
elseif enemies[i].type == 2 then  
..  
enemy.lua  
enemies[i].moveTimer = enemies[i].moveTimer + dt  
if enemies[i].moveTimer > enemies[i].timeToMove then  
local jumpForce = vector2.new(0, -800)  
enemies[i].body:applyLinearImpulse(jumpForce.x, jumpForce.y)  
enemies[i].moveTimer = 0  
end  
end  
end  
end  
end  
function DrawEnemies(enemies)  
for i = 1, #enemies, 1 do  
if enemies[i] then  
if enemies[i].type == 1 then  
love.graphics.setColor(0.8, 0.0, 0.0)  
elseif enemies[i].type == 2 then  
love.graphics.setColor(0.8, 0.8, 0.0)  
end  
.
..  
Example 2: Arrays and Enemies  
.
..  
enemy.lua  
love.graphics.polygon("fill", enemies[i].body:getWorldPoints(  
enemies[i].shape:getPoints()))  
end  
end  
end  
require "player"  
require "level"  
require "enemy"  
main.lua  
local world  
local level1  
local enemies  
function love.load()  
love.physics.setMeter(30)  
world = love.physics.newWorld(0, 9.81 * love.physics.getMeter(), true)  
world:setCallbacks(BeginContact, nil, nil, nil)  
.
..  
Example 2: Arrays and Enemies  
.
level1 = {}  
..  
main.lua  
level1[1] = CreatePlatform(world, 50, 550, 1200, 50)  
level1[2] = CreatePlatform(world, 500, 450, 50, 50)  
level1[3] = CreatePlatform(world, 750, 500, 100, 50)  
level1[4] = CreatePlatform(world, 1000, 420, 150, 50)  
enemies = {}  
enemies[1] = CreateEnemy(world, 650, 500, 1, 1)  
enemies[2] = CreateEnemy(world, 1100, 350, 2, 2)  
CreatePlayer(world)  
end  
function BeginContact(fixtureA, fixtureB, contact)  
BeginContactPlayer(fixtureA, fixtureB, contact)  
BeginContactEnemy(fixtureA, fixtureB, contact)  
end  
.
..  
Example 2: Arrays and Enemies  
.
function BeginContactEnemy(fixtureA, fixtureB, contact)  
..  
main.lua  
if (fixtureA:getUserData().type == "enemy" and  
fixtureB:getUserData().type == "player") then  
local normal = vector2.new(contact:getNormal())  
if normal.y == -1 then  
enemies[fixtureA:getUserData().index] = nil  
fixtureA:getBody():destroy()  
fixtureA:getShape():release()  
fixtureA:destroy()  
else  
KillPlayer(false)  
end  
end  
end  
function love.update(dt)  
world:update(dt)  
UpdatePlayer(dt)  
UpdateEnemies(dt, enemies)  
end  
.
..  
Example 2: Arrays and Enemies  
.
..  
main.lua  
function love.draw()  
love.graphics.push()  
local playerPosition = GetPlayerPosition()  
love.graphics.translate(-(playerPosition.x) + 380, 0)  
love.graphics.setColor(0,0,1)  
DrawPlayer()  
love.graphics.setColor(0,1,0)  
DrawLevel(level1)  
DrawEnemies(enemies)  
love.graphics.pop()  
love.graphics.setColor(1,1,1)  
love.graphics.print("FPS:" ..  
love.timer.getFPS(), 20, 20)  
end  
Arrays and Animations  
•
Animations are created by sequences of images.  
–
Example:  
•
We can store animations as arrays of images!  
require "vector2"  
local hero = {  
walk = {}, -- array of images  
anim_frame = 1,  
position = vector2.new(100, 225),  
velocity = vector2.new(0, 0)  
}
function love.load()  
for i = 1, 4, 1 do -- load the animation frames  
hero.walk[i] = love.graphics.newImage("Hero_Walk_0" .. i .. ".png")  
end  
end  
function love.draw() -- draw the character using the animation index  
love.graphics.draw(hero.walk[hero.anim_frame], hero.position.x,  
hero.position.y)  
end  
.
..  
.
..  
function love.update(dt)  
if love.keyboard.isDown("right") then  
hero.velocity = vector2.new(100, 0)  
hero.anim_frame = hero.anim_frame + 1 -- increases the anim. index  
if hero.anim_frame > 4 then  
hero.anim_frame = 1  
end  
-- animation loop  
else  
hero.velocity = vector2.new(0, 0)  
end  
hero.position = vector2.add(hero.position,  
vector2.mult(hero.velocity, dt))  
end  
Example of Animation  
•
Problem: we did not control the speed of the animation!  
–
The faster the computer, the faster the animation will be played.  
function love.update(dt)  
if love.keyboard.isDown("right") then  
hero.velocity = vector2.new(100, 0)  
hero.anim_timer = hero.anim_timer + dt -- increases the time with dt  
if hero.anim_timer > 0.1 then  
-- when time gets to 0.1  
hero.anim_frame = hero.anim_frame + 1 -- increases the anim. index  
if hero.anim_frame > 4 then  
hero.anim_frame = 1  
end  
-- animation loop  
hero.anim_timer = 0  
-- reset the time counter  
end  
else  
hero.velocity = vector2.new(0, 0)  
end  
hero.position = vector2.add(hero.position,  
vector2.mult(hero.velocity, dt))  
end  
Exercise 1  
) Continue the implementation of the last example by adding  
the animations and movement of the character to all other  
directions. Use the following images:  
1
Texture Atlas  
•
•
A texture atlas (also called a  
sprite sheet or an image sprite) is  
an image containing a collection  
of smaller images, usually packed  
together to reduce the atlas size.  
It is often more efficient to store  
the textures in a texture atlas  
which is treated as a single unit  
by the graphics hardware.  
https://edirlei.com/aulas/gameprog/spritesheet_example.png  
require "vector2"  
local hero = {  
position = vector2.new(100, 225),  
velocity = vector2.new(0, 0),  
spritesheet = love.graphics.newImage("spritesheet_example.png"),  
spritesheetQuads = {},  
anim_frame = 1,  
anim_timer = 0  
}
function CreateSpriteSheetQuads(spritesheet, cols, rows, w, h)  
local quads = {}  
local count = 1  
for j = 0, rows - 1, 1 do  
for i = 0, cols - 1, 1 do  
quads[count] = love.graphics.newQuad(i * w , j * h, w, h,  
spritesheet:getWidth(), spritesheet:getHeight())  
count = count + 1  
end  
end  
return quads  
end  
.
..  
function love.load()  
hero.spritesheetQuads = CreateSpriteSheetQuads(hero.spritesheet, 4, 4,  
64, 64)  
end  
function love.draw()  
love.graphics.draw(hero.spritesheet,  
hero.spritesheetQuads[hero.anim_frame],  
hero.position.x, hero.position.y)  
end  
function love.update(dt)  
if love.keyboard.isDown("down") then  
hero.velocity = vector2.new(0, 100)  
hero.anim_timer = hero.anim_timer + dt  
if hero.anim_timer > 0.1 then  
hero.anim_frame = hero.anim_frame + 1  
if hero.anim_frame > 4 then  
hero.anim_frame = 1  
end  
hero.anim_timer = 0  
end  
.
..  
.
..  
elseif love.keyboard.isDown("right") then  
hero.velocity = vector2.new(100, 0)  
hero.anim_timer = hero.anim_timer + dt  
if hero.anim_timer > 0.1 then  
if hero.anim_frame < 9 or hero.anim_frame > 12 then  
hero.anim_frame = 9  
end  
hero.anim_frame = hero.anim_frame + 1  
if hero.anim_frame >= 12 then  
hero.anim_frame = 9  
end  
hero.anim_timer = 0  
end  
else  
hero.velocity = vector2.new(0, 0)  
end  
hero.position = vector2.add(hero.position,  
vector2.mult(hero.velocity, dt))  
end  
Matrices  
•
•
Matrices are two-dimensional arrays.  
A matrix stores data in an organized form with rows and  
columns.  
3
7
1
5
6
1 8 6 1  
2 5 4 9  
9 3 1 2  
8 6 7 3  
4 9 2 1  
Matrices in Lua  
•
Declaring and initializing a matrix:  
my_matrix = {}  
-- new matrix  
for i=1, 10, 1 do  
my_matrix[i] = {} -- new row  
for j=1, 10, 1 do  
my_matrix[i][j] = 0  
end  
end  
–
We are defining and initializing a matrix with 10 columns e 10 rows.  
Matrices in Lua  
•
We can access the values stored in the matrix using their two-  
dimensional indexes.  
1
2 3  
1
5
? ?1  
?
?
?
? ?  
?8 ?  
2
3
my_matrix[1][1] = 5;  
my_matrix[2][3] = 8;  
my_matrix[3][1] = 1;  
Matrices and Game Worlds  
•
We can use matrices to represent 2D game worlds.  
–
Example:  
Matrices and Game Worlds – Example 1  
•
Generating a random matrix and drawing its elements on  
screen using colors.  
local world = {}  
function love.load()  
for i=1, 26, 1 do -- initializes a random matrix (26 x 20)  
world[i] = {}  
for j=1, 20, 1 do  
world[i][j] = love.math.random(0, 3)  
end  
end  
end  
function love.draw()  
for i=1, 26, 1 do -- iterates through the matrix and draw the elements  
for j=1, 20, 1 do  
if (world[i][j] == 0) then  
love.graphics.setColor(1, 0, 0)  
elseif (world[i][j] == 1) then  
love.graphics.setColor(0, 1, 0)  
elseif (world[i][j] == 2) then  
love.graphics.setColor(0, 0, 1)  
elseif (world[i][j] == 3) then  
love.graphics.setColor(1, 1, 0)  
end  
love.graphics.rectangle("fill", (i * 30)-20, (j * 30)-30, 30, 30)  
end  
end  
end  
Matrices and Game Worlds – Example 1  
Matrices and Game Worlds – Example 2  
•
Reading a matrix from a file and drawing its elements  
on screen using colors.  
World1.txt  
GGGGGGAGGGGGGG  
GGGGGGAGGGGGGG  
GGGGGGAGGGGGGG  
GGGGGGAGGGGGGG  
GGGGGGAAAGGGGG  
GGGGGGGGAGGGGG  
GGGGGGGGAGGGGG  
PPPPPPPPAPPPPP  
AAAAAAAAAAAAAA  
AAAAAAAAAAAAAA  
Matrices and Game Worlds – Example 2  
local world = {}  
function LoadMap(filename) –- reads the content of the file  
local file = io.open(filename)  
local i = 1  
for line in file:lines() do  
world[i] = {}  
for j=1, #line, 1 do  
world[i][j] = line:sub(j,j)  
end  
i = i + 1  
end  
file:close()  
end  
function love.load()  
LoadMap("World1.txt")  
end  
.
.
.
Matrices and Game Worlds – Example 2  
.
.
.
function love.draw()  
for i=1, 10, 1 do -- iterates through the matrix and draw the elements  
for j=1, 14, 1 do  
if (world[i][j] == "P") then  
love.graphics.setColor(0.901, 0.921, 0.525)  
elseif (world[i][j] == "G") then  
love.graphics.setColor(0.149, 0.6, 0)  
elseif (world[i][j] == "A") then  
love.graphics.setColor(0.250, 0.490, 0.909)  
end  
love.graphics.rectangle("fill", (j * 50), (i * 50), 50, 50)  
end  
end  
end  
Matrices and Game Worlds – Example 2  
Matrices and Game Worlds – Example 3  
•
Reading a matrix from a file and drawing its elements  
on screen using images.  
World1.txt  
Images:  
GGGGGGAGGGGGGG  
GGGGGGAGGGGGGG  
GGGGGGAGGGGGGG  
GGGGGGAGGGGGGG  
GGGGGGAAAGGGGG  
GGGGGGGGAGGGGG  
GGGGGGGGAGGGGG  
PPPPPPPPAPPPPP  
AAAAAAAAAAAAAA  
AAAAAAAAAAAAAA  
Matrices and Game Worlds – Example 3  
local world = {}  
local tile_grass  
local tile_water  
local tile_sand  
function LoadMap(filename) –- reads the content of the file  
local file = io.open(filename)  
local i = 1  
for line in file:lines() do  
world[i] = {}  
for j=1, #line, 1 do  
world[i][j] = line:sub(j,j)  
end  
i = i + 1  
end  
file:close()  
end  
.
.
.
.
.
.
function love.load()  
LoadMap("World1.txt")  
tile_grass = love.graphics.newImage("grass.png")  
tile_water = love.graphics.newImage("water.png")  
tile_sand = love.graphics.newImage("sand.png")  
end  
function love.draw()  
for i=1, 10, 1 do -- iterates through the matrix and draw the elements  
for j=1, 14, 1 do  
if (world[i][j] == "P") then  
love.graphics.draw(tile_sand, (j * 50), (i * 50))  
elseif (world[i][j] == "G") then  
love.graphics.draw(tile_grass, (j * 50), (i * 50))  
elseif (world[i][j] == "A") then  
love.graphics.draw(tile_water, (j * 50), (i * 50))  
end  
end  
end  
end  
Matrices and Game Worlds – Example 3  
Exercise 2  
) Implement a program to display the world of a platform game,  
2
which is stored in a text file.  
Exercise 3  
) Continue the implementation of the last exercise and code a  
virtual camera to allow the player to move and see the entire  
environment.  
3
–
Important: don’t draw parts of world that are not visible in the screen.  
Texture Atlas  
•
•
A texture atlas (also called a  
sprite sheet or an image sprite) is  
an image containing a collection  
of smaller images, usually packed  
together to reduce the atlas size.  
It is often more efficient to store  
the textures in a texture atlas  
which is treated as a single unit  
by the graphics hardware.  
Texture Atlas – Example  
World  
Tileset  
XXXXXXXXXXXXXX  
XXXXXXXXXXXXXX  
XXXXXXXXXXXXXX  
XXXXXXXXXXXXXX  
XXXXXXXXXXXXXX  
XXXBXXXXXXXXXX  
XXBBBXXXXXXXXX  
GGGGGGGAAGGGGG  
TTTTTTTPPTTTTT  
TTTTTTTPPTTTTT  
http://www.inf.puc-rio.br/~elima/intro-eng/plataform_map1.zip  
Texture Atlas – Example  
local world = {}  
local tilesetImage  
local tileQuads = {}  
local tileSize = 64  
function LoadTiles(filename, nx, ny)  
tilesetImage = love.graphics.newImage(filename)  
local count = 1  
for i = 0, nx, 1 do  
for j = 0, ny, 1 do  
tileQuads[count] = love.graphics.newQuad(i * tileSize ,  
j * tileSize, tileSize, tileSize,  
tilesetImage:getWidth(),  
tilesetImage:getHeight())  
count = count + 1  
end  
end  
end  
.
.
.
.
.
.
function LoadMap(filename)  
local file = io.open(filename)  
local i = 1  
for line in file:lines() do  
world[i] = {}  
for j=1, #line, 1 do  
world[i][j] = line:sub(j,j)  
end  
i = i + 1  
end  
file:close()  
end  
function love.load()  
LoadMap("plataform_map.txt")  
LoadTiles("plataform_tileset.png", 2, 2)  
love.graphics.setBackgroundColor(0.6, 0.819, 0.980)  
end  
.
.
.
.
.
.
function love.draw()  
for i=1, 10, 1 do  
for j=1, 14, 1 do  
if (world[i][j] == "G") then  
love.graphics.draw(tilesetImage, tileQuads[1],  
(
j * tileSize) - tileSize, (i * tileSize) - tileSize)  
elseif (world[i][j] == "T") then  
love.graphics.draw(tilesetImage, tileQuads[4],  
(
j * tileSize) - tileSize, (i * tileSize) - tileSize)  
elseif (world[i][j] == "A") then  
love.graphics.draw(tilesetImage, tileQuads[7],  
(
j * tileSize) - tileSize, (i * tileSize) - tileSize)  
elseif (world[i][j] == "P") then  
love.graphics.draw(tilesetImage, tileQuads[8],  
(
j * tileSize) - tileSize, (i * tileSize) - tileSize)  
elseif (world[i][j] == "B") then  
love.graphics.draw(tilesetImage, tileQuads[6],  
(
j * tileSize) - tileSize, (i * tileSize) - tileSize)  
end  
end  
end  
end  
Texture Atlas – Example  
Tile-Based Scrolling – Example  
XXXXXXXXXXXXXXXXXXXXXXXXXXXX  
XXXXXXXXXXXXXXXXXXXXXXXXXXXX  
XXXXXXXXXXXXXXXXXXXXXXXXXXXX  
XXXXXXXXXXXXXXXXXXXXXXXXXXXX  
XXXXXXXXXXXXXXXXXXXXXXXXXXXX  
XXXBXXXXXXXXXXXXXBXXXXXXXXXX  
XXBBBXXXXXXXXXXXBBBXXXXXXXXX  
GGGGGGGAAGGGGGGGGGGGGAAGGGGG  
TTTTTTTPPTTTTTTTTTTTTPPTTTTT  
TTTTTTTPPTTTTTTTTTTTTPPTTTTT  
http://www.inf.puc-rio.br/~elima/intro-eng/plataform_map2.zip  
Tile-Based Scrolling – Example  
local world = {}  
local tilesetImage  
local tileQuads = {}  
local tileSize = 64  
local world_config = {  
worldSize_x = 28,  
worldSize_y = 10,  
worldDisplay_x = 14,  
worldDisplay_y = 10  
}
local camera = {  
pos_x = 1,  
pos_y = 1,  
speed = 120  
}
function LoadTiles(filename, nx, ny)  
tilesetImage = love.graphics.newImage(filename)  
local count = 1  
for i = 0, nx, 1 do  
for j = 0, ny, 1 do  
tileQuads[count] = love.graphics.newQuad(i * tileSize, j *  
tileSize, tileSize, tileSize,  
tilesetImage:getWidth(),  
tilesetImage:getHeight())  
count = count + 1  
end  
end  
end  
function LoadMap(filename)  
local file = io.open(filename)  
local i = 1  
for line in file:lines() do  
world[i] = {}  
for j=1, #line, 1 do  
world[i][j] = line:sub(j,j)  
end  
i = i + 1  
end  
file:close()  
end  
function love.load()  
LoadMap("plataform_map.txt")  
LoadTiles("plataform_tileset.png", 2, 2)  
love.graphics.setBackgroundColor(0.6, 0.819, 0.980)  
end  
function love.update(dt)  
if love.keyboard.isDown("right") then  
camera.pos_x = camera.pos_x + (camera.speed * dt)  
elseif love.keyboard.isDown("left") then  
camera.pos_x = camera.pos_x - (camera.speed * dt)  
end  
if camera.pos_x < 0 then  
camera.pos_x = 0  
elseif camera.pos_x > world_config.worldSize_x * tileSize -  
world_config.worldDisplay_x * tileSize - 1 then  
camera.pos_x = world_config.worldSize_x * tileSize -  
world_config.worldDisplay_x * tileSize - 1  
end  
end  
function love.draw()  
offset_x = math.floor(camera.pos_x % tileSize)  
first_tile_x = math.floor(camera.pos_x / tileSize)  
for y=1, world_config.worldDisplay_y, 1 do  
for x=1, world_config.worldDisplay_x, 1 do  
if (world[y][first_tile_x + x] == "G") then  
love.graphics.draw(tilesetImage, tileQuads[1],  
(
(x -1)*tileSize) - offset_x ,((y-1)*tileSize))  
elseif (world[y][first_tile_x + x] == "T") then  
love.graphics.draw(tilesetImage, tileQuads[4],  
(
(x-1)*tileSize) - offset_x ,((y-1)*tileSize))  
elseif (world[y][first_tile_x + x] == "A") then  
love.graphics.draw(tilesetImage, tileQuads[7],  
(
(x-1)*tileSize) - offset_x ,((y-1)*tileSize))  
elseif (world[y][first_tile_x + x] == "P") then  
love.graphics.draw(tilesetImage, tileQuads[8],  
(
(x-1)*tileSize) - offset_x ,((y-1)*tileSize))  
elseif (world[y][first_tile_x + x] == "B") then  
love.graphics.draw(tilesetImage, tileQuads[6],  
(
(x-1)*tileSize) - offset_x ,((y-1)*tileSize))  
end  
end  
end  
end  
Tile-Based Scrolling – Example  
Loading and Drawing Tiled Levels  
•
•
Tiled:  
–
https://www.mapeditor.org/  
–
Export levels in .lua format  
Tiled Love2D Library:  
–
https://github.com/karai17/Simple-Tiled-Implementation  
Tiled Levels – Example  
require "vector2"  
require "player"  
main.lua  
local sti = require "sti"  
local level1  
local world  
local player  
function love.load()  
love.physics.setMeter(64)  
world = love.physics.newWorld(0, 9.81 * love.physics.getMeter(), true)  
world:setCallbacks(BeginContact, nil, nil, nil)  
player = CreatePlayer(world)  
level1 = sti("level1.lua", {"box2d"})  
level1:box2d_init(world)  
love.graphics.setBackgroundColor(0.309, 0.721, 0.972)  
end  
function BeginContact(fixtureA, fixtureB, contact)  
PlayerBeginContact(player, fixtureA, fixtureB, contact)  
end  
Tiled Levels – Example  
function love.update(dt)  
UpdatePlayer(player, level1, dt)  
level1:update(dt)  
main.lua  
world:update(dt)  
end  
function love.draw()  
love.graphics.setColor(1, 1, 1)  
local playerposition = vector2.new(player.body:getPosition())  
level1:draw(-playerposition.x + 380, -650)  
DrawPlayer(player)  
end  
Tiled Levels – Example  
require "vector2"  
player.lua  
function CreatePlayer(world)  
local player = {}  
player.body = love.physics.newBody(world, 100, 650, "dynamic")  
-
-polygon to avoid getting stuck in tiles (rectangle (32, 80))  
player.shape = love.physics.newPolygonShape(-16, -40, 16, -40, 16, 38, 2, 40,  
2, 40, -16, 38)  
-
player.fixture = love.physics.newFixture(player.body, player.shape, 1)  
player.fixture:setFriction(0.8)  
player.fixture:setCategory(1)  
player.body:setFixedRotation(true)  
player.maxvelocity = 200  
player.jumped = false  
player.onground = false  
return player  
end  
function DrawPlayer(player)  
love.graphics.setColor(0.2, 0.2, 0.9)  
local playerposition = vector2.new(player.body:getPosition())  
love.graphics.rectangle("fill", 380 - 16, playerposition.y - 40 - 650, 32, 80)  
end  
Tiled Levels – Example  
function UpdatePlayer(player, level, dt)  
player.lua  
if love.keyboard.isDown("right") then  
local moveForce = vector2.new(700, 0)  
player.body:applyForce(moveForce.x, moveForce.y)  
end  
if love.keyboard.isDown("left") then  
local moveForce = vector2.new(-700, 0)  
player.body:applyForce(moveForce.x, moveForce.y)  
end  
if love.keyboard.isDown("up") and (player.onground == true) then  
local moveForce = vector2.new(0, -300)  
player.body:applyLinearImpulse(moveForce.x, moveForce.y)  
player.onground = false  
end  
local velocity = vector2.new(player.body:getLinearVelocity())  
if velocity.x > 0 then  
player.body:setLinearVelocity(math.min(velocity.x, player.maxvelocity),  
velocity.y)  
else  
player.body:setLinearVelocity(math.max(velocity.x, -player.maxvelocity),  
velocity.y)  
end  
end  
Tiled Levels – Example  
function PlayerBeginContact(player, fixtureA, fixtureB, contact)  
local categoryA = fixtureA:getCategory()  
player.lua  
local categoryB = fixtureB:getCategory()  
if (categoryA == 1 and categoryB == 2) then  
local normal = vector2.new(contact:getNormal())  
if (normal.y == 1) then  
player.onground = true  
end  
elseif (categoryA == 2 and categoryB == 1) then  
local normal = vector2.new(contact:getNormal())  
if (normal.y == -1) then  
player.onground = true  
end  
end  
end