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
Custom map loading technique [Solved]
- bobbymcbobface
- Citizen
- Posts: 78
- Joined: Tue Jun 04, 2019 8:31 pm
Custom map loading technique [Solved]
Last edited by bobbymcbobface on Sun Dec 01, 2019 10:54 am, edited 1 time in total.
I make games that run on potatoes :P
Re: Custom map loading technique
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.
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
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.
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: 3465
- Joined: Thu Dec 13, 2012 2:55 pm
- Location: Absurdistan, Hungary
- Contact:
Re: Custom map loading technique
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 "letskillkeep the user's ssd/harddrive busy" by continuously loading in rows/columns of tiles as the player moves around the world.
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
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: 78
- Joined: Tue Jun 04, 2019 8:31 pm
Re: Custom map loading technique
Ok here's what I've got so far:
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!
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
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!
I make games that run on potatoes :P
Re: Custom map loading technique
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.
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
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.
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
- bobbymcbobface
- Citizen
- Posts: 78
- Joined: Tue Jun 04, 2019 8:31 pm
Re: Custom map loading technique
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 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
Re: Custom map loading technique
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: 78
- Joined: Tue Jun 04, 2019 8:31 pm
Re: Custom map loading technique
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
I make games that run on potatoes :P
Who is online
Users browsing this forum: No registered users and 3 guests