General discussion about LÖVE, Lua, game development, puns, and unicorns.
bobbymcbobface
Citizen
Posts: 50
Joined: Tue Jun 04, 2019 8:31 pm

Hay i was wondering if it's possible to create a custom map loading system
how this would work:
it would load a map styled like this

#############
#############
#############
#############

red = on screen
black = off screen

if the player moves to the left 1 tile would remove behind him and one would load ahead of him like this

~############+
~############+
~############+
~############+

~ = deleted

and if he moves back vice versa is there any way to do this and store the data so if the player goes back the same tiles will load back in

EDIT: also is it possible to make it so if the player reaches the border of the top of the map the players co-ordinates change to the bottom of the map

-thankyou
I make games that run on potatoes :P

raidho36
Party member
Posts: 1919
Joined: Mon Jun 17, 2013 12:00 pm

It's possible to create literally anything - that's what programming is for.

Unless your map takes several gigabytes of memory, you should keep the entire thing loaded. Frustum culling takes care of the "not rendering offscreen stuff" problem, and the same technique allows checking logic against specific objects on the map based on coordinates rather than against every single one of them.

To answer your questions, you can do the rolling map update by simply checking if an offscreen row/column is far enough to be removed, and in such case do so (and create a row/column on the opposite side at the same time, because both operations are triggered by the same condition). And to implement wrapping, you simply check if a coordinate exceeds certain limits, and then set it to such value that the entity will appear on the other side - usually by adding/subtracting map width or height as appropriate.

sphyrth
Party member
Posts: 108
Joined: Mon Jul 07, 2014 11:04 am
Contact:

Tutorial: Efficient Tile-based Scrolling seems to cover that one up.

I don't really remember if it "deletes" tiles outside of the screen (because learning about Spritebatch was enough for me), but I assume that it also does that.

zorg
Party member
Posts: 2717
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Do note that frustum culling doesn't include your own logic things being applied to things outside the current viewport, as in, the part of your map that's currently visible in the window, so that's another thing you might want to implement, or not, depending on what your goals are.

That said, most games i know of don't partition the map into singular tiles, rather into larger clusters of them called chunks (e.g. minecraft), or into "complete" areas that need to be transitioned from and to, (e.g. earlier pokemon games), since it's faster to load the data in that way, and you don't need to play "lets killkeep the user's ssd/harddrive busy" by continuously loading in rows/columns of tiles as the player moves around the world.
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.

bobbymcbobface
Citizen
Posts: 50
Joined: Tue Jun 04, 2019 8:31 pm

Ok here's what I've got so far:
tileset.png (114.42 KiB) Viewed 2763 times

Code: Select all

local map -- stores tiledata
local mapWidth, mapHeight -- width and height in tiles

local mapX, mapY -- view x,y in tiles. can be a fractional value like 3.25.

local tilesDisplayWidth, tilesDisplayHeight -- number of tiles to show
local zoomX, zoomY

local tilesetImage
local tileSize -- size of tiles in pixels
local tileQuads = {} -- parts of the tileset used for different tiles
local tilesetSprite

setupMap()
setupMapView()
setupTileset()
end

function setupMap()
mapWidth = 2000  ------------------------------------------------------------
mapHeight = 2000 -----------------------------------------------------------

map = {}
for x=0,mapWidth do
map[x] = {}
for y=0,mapHeight do
map[x][y] = love.math.random(0,3)
end
end
end

function setupMapView()
mapX = 1
mapY = 1
tilesDisplayWidth = 26
tilesDisplayHeight = 20

zoomX = 1
zoomY = 1
end

function setupTileset()
tilesetImage = love.graphics.newImage( "tileset.png" )
tilesetImage:setFilter("nearest", "linear") -- this "linear filter" removes some artifacts if we were to scale the tiles
tileSize = 32

-- grass
tilesetImage:getWidth(), tilesetImage:getHeight())
-- kitchen floor tile
tilesetImage:getWidth(), tilesetImage:getHeight())
-- parquet flooring
tilesetImage:getWidth(), tilesetImage:getHeight())
-- middle of red carpet
tilesetImage:getWidth(), tilesetImage:getHeight())

tilesetBatch = love.graphics.newSpriteBatch(tilesetImage, tilesDisplayWidth * tilesDisplayHeight)

updateTilesetBatch()
end

function updateTilesetBatch()
tilesetBatch:clear()
for x=0, tilesDisplayWidth-1 do
for y=0, tilesDisplayHeight-1 do
x*tileSize, y*tileSize)
end
end
tilesetBatch:flush()

if mapHeight == 0 or mapHeight == 2000 then
mapHeight = 0
end
end

-- central function for moving the map
function moveMap(dx, dy)
oldMapX = mapX
oldMapY = mapY
mapX = math.max(math.min(mapX + dx, mapWidth - tilesDisplayWidth), 1)
mapY = math.max(math.min(mapY + dy, mapHeight - tilesDisplayHeight), 1)
-- only update if we actually moved
if math.floor(mapX) ~= math.floor(oldMapX) or math.floor(mapY) ~= math.floor(oldMapY) then
updateTilesetBatch()
end
end

function love.update(dt)
if love.keyboard.isDown("up")  then
moveMap(0, -0.2 * tileSize * dt)
end
if love.keyboard.isDown("down")  then
moveMap(0, 0.2 * tileSize * dt)
end
if love.keyboard.isDown("left")  then
moveMap(-0.2 * tileSize * dt, 0)
end
if love.keyboard.isDown("right")  then
moveMap(0.2 * tileSize * dt, 0)
end
end

function love.draw()
love.graphics.draw(tilesetBatch,
math.floor(-zoomX*(mapX%1)*tileSize), math.floor(-zoomY*(mapY%1)*tileSize),
0, zoomX, zoomY)
love.graphics.print("FPS: "..love.timer.getFPS(), 10, 20)
end
2 questions though
1. how can i remove the weird black square moving across the screen
2. can anyone edit my code so it delete's any tiles left behind and adds one ahead (so basically my previous example) because i'm stuck on how i would achieve this

btw thank you for replying so quick this forum is a lot better than stack overflow

edit: as well as that would i need to store previous tile or hide them for if the player wants to go back and since there's a lot of trees would the physics handling cause lag?

editX2 (sorry for so many edits i'm just eager to get the right result): basing of zorg's comment how can i load in chunks of a map i.e has anyone got an example code they could show me

also for anyone who wants to know what my goals are:

i need to create a random map that the player can roam around and structures such as tombs will appear with weapons inside and these will be used to fight off enemies that are generated across the map at random and if the player exceeds the boarder he will loop back to the opposite side making the map seem "infinite"

I make games that run on potatoes :P

sphyrth
Party member
Posts: 108
Joined: Mon Jul 07, 2014 11:04 am
Contact:

Okay, I think I have to review the tutorial to know what you are talking about (Weird Moving Square).

When it comes to what zorg is talking about, it's a technique used by a lot of Adventure RPGs. I'm not sure how many games have been made, but they are in the Games and Creations section.

In your particular case, I'm currently trying to clone this game. It's similar to what you're trying to accomplish except for the Random Generating part. Getting the maths done is still rattling my brain. Maybe I'll try to share them when it's basically done.

sphyrth
Party member
Posts: 108
Joined: Mon Jul 07, 2014 11:04 am
Contact:

Okay, try this code. I stripped it down as much as I could to leave out the unimportant bits. I personally don't recommend depending on it as it's for discussion purposes (meaning that it's very rough and therefore inefficient for serious game prototyping).

I assume this is how you want it to work.

Code: Select all

local tilesetImage
local tileSize = 32 -- size of tiles in pixels
local tileQuads = {} -- parts of the tileset used for different tiles
local tilesetSprite

local map -- stores tiledata
local mapX, mapY -- view x,y in tiles. can be a fractional value like 3.25.
local mapWidth, mapHeight -- width and height in tiles

setupMap()
setupTileset()
updateTilesetBatch()
end

function setupMap()
-- We only need a tiny map for this example
mapWidth = 15
mapHeight = 15

--Leaving a space on the right and topsides so we know if the tiles are being "deleted"
mapX = 32
mapY = 32

map = {}
for x=0, mapWidth do
map[x] = {}
for y=0, mapHeight do
map[x][y] = { --Let's turn this into a table that stores 3 things:
tile = love.math.random(0,3),
x = x * tileSize,
y = y * tileSize
}
end
end
end

function setupTileset()
tilesetImage = love.graphics.newImage( "tileset.png" )
tilesetImage:setFilter("nearest", "linear")

-- Tree
tilesetImage:getWidth(), tilesetImage:getHeight())
-- Grass
tilesetImage:getWidth(), tilesetImage:getHeight())
-- Grass with Stone
tilesetImage:getWidth(), tilesetImage:getHeight())
-- Grass (Yup the same Grass as 1
tilesetImage:getWidth(), tilesetImage:getHeight())

tilesetBatch = love.graphics.newSpriteBatch(tilesetImage, mapWidth * mapHeight)
end

function updateTilesetBatch()
tilesetBatch:clear()
for x=1, mapWidth do
for y=1, mapHeight do
end
end
tilesetBatch:flush()
end

-- central function for moving the map
function moveMap(dx, dy)
for x = 1, mapWidth do
for y = 1, mapHeight do
map[x][y].x = map[x][y].x + dx
map[x][y].y = map[x][y].y + dy

-- Okay so I'm not "deleting" the tiles, but transferring their x and y coordinates

--X
if map[x][y].x < mapX - (tileSize / 2) then
map[x][y].x = map[x][y].x + (tileSize * mapWidth)
end
if map[x][y].x > mapX + (mapWidth * tileSize) - (tileSize / 2) then
map[x][y].x = map[x][y].x - (tileSize * mapWidth)
end

--Y
if map[x][y].y < mapY - (tileSize / 2) then
map[x][y].y = map[x][y].y + (tileSize * mapHeight)
end
if map[x][y].y > mapY + (mapHeight * tileSize) - (tileSize / 2) then
map[x][y].y = map[x][y].y - (tileSize * mapHeight)
end
end
end
updateTilesetBatch()
end

function love.update(dt)
if love.keyboard.isDown("up")  then
moveMap(0, - 50 * dt)
end
if love.keyboard.isDown("down")  then
moveMap(0, 50 * dt)
end
if love.keyboard.isDown("left")  then
moveMap(-50 * dt, 0)
end
if love.keyboard.isDown("right")  then
moveMap(50 * dt, 0)
end
end

function love.draw()
love.graphics.draw(tilesetBatch)
love.graphics.print("FPS: "..love.timer.getFPS(), 10, 20)
end


bobbymcbobface
Citizen
Posts: 50
Joined: Tue Jun 04, 2019 8:31 pm

thank you sphyrth although the code is a bit laggy it has boosted me a whole lot closer to my goal thank you
I will still leave this topic unsolved due to the fact i still want to ask some questions on this topic later on and resolve some more problems but thank you for all your help so far and I'll probably be back asking for help soon

edit (yeh i'm back already ) : how can i fix the lines going across the screen when travelling up?
I make games that run on potatoes :P

sphyrth
Party member
Posts: 108
Joined: Mon Jul 07, 2014 11:04 am
Contact:

I'm not really sure. I also saw that effect and I assumed that it's because of the code's quirkiness. Maybe moving the image up and down behaves differently with moving it left and right. But then again, the original Tutorial doesn't have that problem. Anyway, that's my limit. I might try to solve that later on.

bobbymcbobface
Citizen
Posts: 50
Joined: Tue Jun 04, 2019 8:31 pm