Page 1 of 1

Is roguelike a reasonable task for LOVE?

Posted: Sat Nov 08, 2014 12:37 pm
by pacman
Hi o/

I was thinking about trying to make a simple roguelike.
Years ago I knew there is no way I can achieve that but today I'm not so sure :)

Let's try to create some map

Code: Select all

map = {}
for i=1, 45, 1 do
	map[i] = {}
	for j=1, 27, 1 do
		map[i][j] = insert_tile('stone_floor')
	end
end
I didn't even realise how much operations it is... Now I want my map to look dope so I need random characters for floors ( , . ' ` ; : ) and few random colors.

Code: Select all

function insert_tile(type)
	local tile, rand, color
	if		type == 'stone_floor' then
		-- make a copy of the tile
		tile = deepcopy(tile_type.stone_floor)
		-- choose random character
		rand = math.random(1, #tile.char_pool)
		tile.char = tile.char_pool[rand]
		-- and random color
		rand = math.random(1, #tile.pallete)
		tile.color = tile.pallete[rand]
It takes ages on my wooden PC but that's fine. Generating maps isn't something you do every 5 seconds and it would be nice reason to learn how to loading bar :o:

Now the real struggle is with drawing the map.
Drawing this simple rectangle of characters gives me 60-100 fps.
What if I want colors, background colors, custom font?
I can't update only changed positions because not drawing equals black screen. Canvases are not supported.
I'm not looking for Dwarf Fortress sized maps.. just the tip :(

Re: Is roguelike a reasonable task for LOVE?

Posted: Sat Nov 08, 2014 3:20 pm
by jannn
You can improve your map generation speed greatly by looping over some pre-generated tables of random numbers. You don't really need something like the look of floor tiles to be truly random, do you? (well pseudorandom, but you get the point)

Additionally, if you're talking about a true turn-based roguelike, then a slight framerate drop is a non-issue for the end user.

Re: Is roguelike a reasonable task for LOVE?

Posted: Mon Nov 10, 2014 8:22 am
by Kadoba
LOVE is perfectly capable of handling roguelikes. In fact there are a few examples in the projects forums.

The freezing at the start is likely because the window is being resized right after it was created using love.window.setMode(). You can avoid this by using a [wiki]conf.lua[/wiki] file. Also you should avoid copying static data to all of your tiles. Try using __index or a reference instead.

I've uploaded a modified .love that might help explain.

Re: Is roguelike a reasonable task for LOVE?

Posted: Thu Nov 13, 2014 8:00 pm
by pacman
The freezing is because my pc can't handle all that table copying :crazy:

Your example works like a charm. Really impressive how metatables make it fast and furious!
The only problem is with my understanding of what happens :D

Code: Select all

tile = setmetatable({}, tile_type.stone_floor)
Does it mean that if I will look for tile.color it will check the empty {} and then it will look in tile_type.stone_floor?
If no:
Please explain D:
If yes:
It requires

Code: Select all

for k,v in pairs(tile_type) do
   v.__index = v 
end
So stone_floor.__index = stone_floor
How does it work? What is the relation between tile = setmetatable and putting __index that points to the table with same name?
How computer sees it?

Re: Is roguelike a reasonable task for LOVE?

Posted: Sat Nov 15, 2014 6:07 am
by Kadoba
pacman wrote:

Code: Select all

tile = setmetatable({}, tile_type.stone_floor)
Does it mean that if I will look for tile.color it will check the empty {} and then it will look in tile_type.stone_floor?
You're only setting the metatable with that line. The magic happens with the metatable's __index. When you try and get a value does not exist for a table, it will check its metatable's __index next. Setting the index to the metatable itself is just for convenience. It can be any table or alternatively a function.

Some examples may help. All of these are functionally the same:

Code: Select all

-- Create the table, metatable, and index seperately then assign the metatable
i = { number = 5 }
mt = { __index = i }
t = {}
setmetatable( t, mt )
print( t.number )  -- prints 5

-- Use the metatable itself as an index
mt = { number = 5 }
mt.__index = mt
t = setmetatable( {}, mt )
print( t.number ) -- prints 5

-- Creates the table, metatable, and index in one line
t = setmetatable( {},  { __index = { number = 5 } } )
print( t.number )  -- prints 5

Re: Is roguelike a reasonable task for LOVE?

Posted: Sat Nov 15, 2014 3:12 pm
by pacman
So the shortest way to do it would be:

Code: Select all

tile = setmetatable({}, {__index = tile_type.stone_floor})
It works so fast I can't even...
Thank you very much \c", )/

Re: Is roguelike a reasonable task for LOVE?

Posted: Thu Nov 20, 2014 1:58 pm
by desadoc
I working on an roguelike game and I achieved decent performance with BSP trees. I use them to query what to update and what to draw.

A nice trick I do on my update is to first query the subtree that covers the screen then use it instead of using the original tree directly, as I only update dynamic entities that are visible and each of them make their own queries.

Currently I achieve between 0.8 ~1.6 ms of draw + update time per frame (running on an amd @3.2ghz). Scene size doesn't impact it much, if at all. But levels are a bit slow to generate, though it only becomes painful when I hit scene sizes like 1000x1000 tiles (it takes around 10s), so I'm not worried about it (yet).