String2Tiles

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

String2Tiles

Post by kikito »

Using arrays for tile-based maps is kind of a pain.

Code: Select all

local tiles = {
  { ' ', ' ', ' ', ' ', ' ' },
  { ' ', ' ', ' ', ' ', ' ' },
  { '1', '*', '*', '*', '2' },
  { '*', ' ', ' ', ' ', '*' },
  { '*', ' ', '0', ' ', '*' },
  { '*', ' ', ' ', ' ', '*' },
  { '3', '*', '*', '*', '4' },
  { ' ', ' ', ' ', ' ', ' ' },
  { ' ', ' ', ' ', ' ', ' ' }
}
The problems I see:
  • There are way too many commas and quotes/apostrophes and {s and }s
  • x and y coordinates are switched: you have to choose between doing map[y][x] instead of map[x][y], or drawing the map 'sideways'
Strings, on the other hand, are easier to 'draw' (type):

Code: Select all

local str = [[
  1***2  
  *   *  
  * 0 *  
  *   *  
  3***4  
]]
... but they are a pain to use! - you can't easily do str[x][y] or similar. You have to rely on regular expressions and other nonsense.

Here's an attempt at taking the best from both worlds: string2Tiles.

Code: Select all

function string2Tiles(str)
  local tiles = {}

  local row_length = #(str:match("[^\n]+"))

  for x = 1,row_length,1 do
    tiles[x] = {}
  end

  local x,y = 1,1
  for row in str:gmatch("[^\n]+") do
    assert(#row == row_length, 'Map is not squared: length of row ' .. tostring(y) .. ' should be ' .. tostring(row_length) .. ', but it is ' .. tostring(#row))
    x = 1
    for tile in row:gmatch(".") do
      tiles[x][y] = tile
      x = x + 1
    end
    y=y+1
  end
  
  setmetatable(tiles, { __call = function(self, x,y) return self[x][y] end })

  return tiles
end
This function:
  • Accepts an easy-to-draw string
  • Transforms it onto a table. The table is 'flexed', so you can index it like this: table[x][y]
  • For more ease of use, it can also be indexed as a function: table(x,y)
Example:

Code: Select all

 -- prints the tiles on the console
local function printTiles(tiles)
  local buffer = {}
  for x,column in ipairs(tiles) do
    table.insert(buffer, "\n { '" .. table.concat(column, "', '") .. "' }")
  end
  print( '{' .. table.concat(buffer, ',\n') .. '\n}' )
end

local str = [[
  1***2 
  *   * 
  * 0 * 
  *   * 
  3***4 
]]

local tiles = string2Tiles(str)

print('string:')
print(str)

print('tiles:')
printTiles(tiles)

print('tiles[5][3]:', tiles[5][3])
print('tiles(5,3):', tiles(5,3))
And here's the output:

Code: Select all

string:
  1***2 
  *   * 
  * 0 * 
  *   * 
  3***4 

tiles:
{
{ ' ', ' ', ' ', ' ', ' ' },

{ ' ', ' ', ' ', ' ', ' ' },

{ '1', '*', '*', '*', '3' },

{ '*', ' ', ' ', ' ', '*' },

{ '*', ' ', '0', ' ', '*' },

{ '*', ' ', ' ', ' ', '*' },

{ '2', '*', '*', '*', '4' },

{ ' ', ' ', ' ', ' ', ' ' },

{ ' ', ' ', ' ', ' ', ' ' }
}
tiles[5][3]: 0
tiles(5,3): 0
]]
I hope this helps. Feel free to comment / add things.
When I write def I mean function.
User avatar
zac352
Party member
Posts: 496
Joined: Sat Aug 28, 2010 8:13 pm
Location: In your head.
Contact:

Re: String2Tiles

Post by zac352 »

:o Awesome
Hello, I am not dead.
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: String2Tiles

Post by vrld »

This looks mighty helpful.
Only two small additions:
For convenience the dimensions could be saved into the tiles table and the __call should check for bounds:

Code: Select all

function string2Tiles(str)
[...]
    tiles.widht = #tiles
    tiles.height = #tiles[1]

    setmetatable(tiles, { __call = function(self, x,y) 
        assert(x > 0 and x <= tiles.width, "Index x="..x.." out of bounds")
        assert(y > 0 and y <= tiles.height, "Index y="..y.." out of bounds")
        return self[x][y]
    end })
    return tiles
end
Last edited by thelinx on Thu Nov 11, 2010 2:50 pm, edited 1 time in total.
Reason: fify
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: String2Tiles

Post by kikito »

vrld wrote:This looks mighty helpful.
Only two small additions:
For convenience the dimensions could be saved into the tiles table and the __call should check for bounds:

Code: Select all

function string2Tiles(str)
[...]
    tiles.widht = #tiles
    tiles.height = #tiles[1]

    setmetatable(tiles, { __call = function(self, x,y) 
        assert(x > 0 and x <= tiles.width, "Index x="..x.." out of bounds")
        assert(y > 0 and y <= tiles.height, "Index y="..y.." out of bounds")
        return self[x][y]
    end })
    return tiles
end
Mmm ... very good idea!
When I write def I mean function.
User avatar
arquivista
No longer with us
Posts: 266
Joined: Tue Jul 06, 2010 8:39 am
Location: Insert Geolocation tag here
Contact:

Re: String2Tiles

Post by arquivista »

Oh, only now noticed this interesting post. That's was very good function idea that could help some people, Thx kikito and vrld
For the value of it you should add this to Snippets Wiki.

btw, just an suggestion, why you don't wrap it with a loading/save function to plain txt?
Last edited by arquivista on Thu Nov 18, 2010 12:55 pm, edited 1 time in total.
--------------------------------------------------------
To Do: Insert Signature Here
--------------------------------------------------------
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: String2Tiles

Post by kikito »

arquivista wrote:btw, just an suggestion why you don't wrap it with a loading/save function to plain txt?
But... it is already plain text! Not sure of what you mean.

Regarding the wiki, my plan is creating a better tile tutorial. The 3 ones that are there are too confusing.

But I'll wait until 0.7 goes out.
When I write def I mean function.
User avatar
arquivista
No longer with us
Posts: 266
Joined: Tue Jul 06, 2010 8:39 am
Location: Insert Geolocation tag here
Contact:

Re: String2Tiles

Post by arquivista »

kikito wrote: But... it is already plain text! Not sure of what you mean.

Regarding the wiki, my plan is creating a better tile tutorial. The 3 ones that are there are too confusing.

But I'll wait until 0.7 goes out.
You probably right. Just was thinking in instead of load a .lua file with

Code: Select all

local str = [[
  1***2  
  *   *  
  * 0 *  
  *   *  
  3***4  
]]
have imbued a straight/clean loading/saving function without the variable table name and "limits" markers.

Code: Select all

1***2  
 *   *  
 * 0 *  
 *   *  
 3***4
Thanx, I agree with that tiles tutorials were a bit confusing (at least when I started and didn't knew which to head on). BTW do you will apply "translate" on them? I haven't see till now examples with that.
--------------------------------------------------------
To Do: Insert Signature Here
--------------------------------------------------------
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: String2Tiles

Post by kikito »

arquivista wrote:

Code: Select all

1***2  
 *   *  
 * 0 *  
 *   *  
 3***4
Oh. Well, I'm not sure about that. You see, normally when you load maps you want to load more stuff than just the tiles.

For example, enemy locations. Triggers. That kind of thing (explained better on this forum post). You would need a tiles.txt file for the tiles themselves, and a map.lua file pointing to that tiles.txt file. And this setup would probably confuse newbies.
arquivista wrote: Thanx, I agree with that tiles tutorials were a bit confusing (at least when I started and didn't knew which to head on). BTW do you will apply "translate" on them? I haven't see till now examples with that.
Yeah, for a tutorial translate is the thing to use. A more advanced solution would involve translate + drawing only the tiles that fit on the screen.

I'd probably separate it into two tutorials - Tilemap loading & drawing, and then scrolling.
When I write def I mean function.
User avatar
arquivista
No longer with us
Posts: 266
Joined: Tue Jul 06, 2010 8:39 am
Location: Insert Geolocation tag here
Contact:

Re: String2Tiles

Post by arquivista »

kikito wrote: Oh. Well, I'm not sure about that. You see, normally when you load maps you want to load more stuff than just the tiles.

For example, enemy locations. Triggers. That kind of thing (explained better on this forum post). You would need a tiles.txt file for the tiles themselves, and a map.lua file pointing to that tiles.txt file. And this setup would probably confuse newbies.
Ah,ok, I aware of that complications and understand your reasons and dillemas. I just was trying to left things concise to a generic string2tiles table with map/one table only. I for example prefer to separate content types. Why? Cause of other "complications" when keeping all the data in same file because we will load things we don't want sometimes. For example that you have different "levels/dungeons" but the tile info is common to all dungeons so is not necessary load all that basic/common again and because is increasing file size too. Also things in that way must be so well organized that we dont suffer the risk of loading data that will erase like for example altered properties of a terrain/objects during gameplay. Is the fear and danger of reload/reset some unwanted data that was changed meanwhile.
kikito wrote:
Yeah, for a tutorial translate is the thing to use. A more advanced solution would involve translate + drawing only the tiles that fit on the screen.

I'd probably separate it into two tutorials - Tilemap loading & drawing, and then scrolling.
Thx, all of us will thank that! :)
--------------------------------------------------------
To Do: Insert Signature Here
--------------------------------------------------------
User avatar
arquivista
No longer with us
Posts: 266
Joined: Tue Jul 06, 2010 8:39 am
Location: Insert Geolocation tag here
Contact:

Re: String2Tiles

Post by arquivista »

kikito sorry to post this here because is a bit off-topic but is a doubt related with your string2Tiles. I know that this could seem so basic... ermm...
well, I was trying to quickly use your example program that use console and prints. I'm on mac and using console to see messages it's not friendly. There is a way of use "print" commands directly in app window without have to transform them all to love.graphics.print and have to put coordinates (instead of "flow" the text as in a console/terminal)?

thanks.
--------------------------------------------------------
To Do: Insert Signature Here
--------------------------------------------------------
Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests