Page 1 of 4
Custom map loading technique [Solved]
Posted: Sun Jul 07, 2019 11:25 am
by bobbymcbobface
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
+ = added
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
Re: Custom map loading technique
Posted: Sun Jul 07, 2019 12:55 pm
by raidho36
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.
Re: Custom map loading technique
Posted: Sun Jul 07, 2019 1:09 pm
by sphyrth
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.
Re: Custom map loading technique
Posted: Sun Jul 07, 2019 1:12 pm
by zorg
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.
Re: Custom map loading technique
Posted: Sun Jul 07, 2019 2:30 pm
by bobbymcbobface
Ok here's what I've got so far:
- tileset.png (114.42 KiB) Viewed 9593 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
function love.load()
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
tileQuads[0] = love.graphics.newQuad(2 * tileSize, 20 * tileSize, tileSize, tileSize,
tilesetImage:getWidth(), tilesetImage:getHeight())
-- kitchen floor tile
tileQuads[1] = love.graphics.newQuad(0 * tileSize, 20 * tileSize, tileSize, tileSize,
tilesetImage:getWidth(), tilesetImage:getHeight())
-- parquet flooring
tileQuads[2] = love.graphics.newQuad(0 * tileSize, 20 * tileSize, tileSize, tileSize,
tilesetImage:getWidth(), tilesetImage:getHeight())
-- middle of red carpet
tileQuads[3] = love.graphics.newQuad(0 * tileSize, 20 * tileSize, tileSize, tileSize,
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
tilesetBatch:add(tileQuads[map[x+math.floor(mapX)][y+math.floor(mapY)]],
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"
thankyou for your help!
Re: Custom map loading technique
Posted: Sun Jul 07, 2019 10:38 pm
by sphyrth
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.
Re: Custom map loading technique
Posted: Mon Jul 08, 2019 11:05 am
by sphyrth
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
function love.load()
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
tileQuads[0] = love.graphics.newQuad(2 * tileSize, 20 * tileSize, tileSize, tileSize,
tilesetImage:getWidth(), tilesetImage:getHeight())
-- Grass
tileQuads[1] = love.graphics.newQuad(0 * tileSize, 20 * tileSize, tileSize, tileSize,
tilesetImage:getWidth(), tilesetImage:getHeight())
-- Grass with Stone
tileQuads[2] = love.graphics.newQuad(1 * tileSize, 20 * tileSize, tileSize, tileSize,
tilesetImage:getWidth(), tilesetImage:getHeight())
-- Grass (Yup the same Grass as 1
tileQuads[3] = love.graphics.newQuad(0 * tileSize, 20 * tileSize, tileSize, tileSize,
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
tilesetBatch:add(tileQuads[map[x][y].tile], map[x][y].x, map[x][y].y)
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
Re: Custom map loading technique
Posted: Mon Jul 08, 2019 6:41 pm
by bobbymcbobface
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?
Re: Custom map loading technique
Posted: Mon Jul 08, 2019 10:24 pm
by sphyrth
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.
Re: Custom map loading technique
Posted: Tue Jul 09, 2019 6:55 am
by bobbymcbobface
sphyrth wrote: ↑Mon Jul 08, 2019 10:24 pm
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.
It might have been due to my graphics card sometimes it has bad days or it could be a pixels difference between the tilset images height and width - I'll get back to you when I solve it