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