Need help with (big) Table iteration

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
Stigma
Prole
Posts: 2
Joined: Wed Feb 21, 2018 5:37 pm

Need help with (big) Table iteration

Post by Stigma » Wed Feb 21, 2018 6:41 pm

Firstly i'd like to greet all of you and introduce myself as this is my first post.

I've been using LOVE for quite a few years now but i've never quite got into the community as i have never been an active member on forums and for some reason i avoid trying to get help on them, I usually just search for other people's issues and responses and it has been great until several days ago.

I aspire to be a programmer, Game dev being the prefered field i'd say.

So i will initiate the problem with an example, and a few questions for which i'd like to explore new answers.

(I'd also want to start by saying that my english may not be trusted as it isn't my home language and I find it hard to judge myself on any aspect. Ask me directly if you don't understand some expression I may type so that i can try to use another word.)

It begins with the following concepts: An Object class, a World Table, and a Loaded World table

Code: Select all

-- I initialize by creating a world composed by XX by YY chunks, each with 16 by 16 tiles.
local chunk = 16
local XX, YY = 10, 10 -- I intend to set how many chunks in each axis i want to exist in the world

local world = {}
local loadedMap = {}

for i=1,xx do
	world[i] = {} -- Here i set the table on chunk XX to contain the chunks YY in
	for j=1,yy do
		world[i][j] = {}
		for x=1,chunk do
			world[i][j][x] = {}			 -- here i start the tile's table for the X axis
			for y=1,chunk do
				world[i][j][x][y] = {}		-- Y axis.
				for z=1,2 do			-- i intend to add more layers later
					world[i][j][x][y][z] = {
					{type = 'surface', tbl = {...} }	-- Setting a table inside Z's table to represent one initial object, there shall be more objects inside this same dimensions. This initial object is the Surface object, tbl contains everything that individualizes this particular surface tile, like the XX,YY,X,Y,Z position in the world so it can be updated and drawn as an instance.
					}
				end
			end
		end
	end
end

-- Everything above ,in theory, and in practice did work well and does the job pretty great, simply creating the whole world filled with equal Surface instances on their rightful positions which will then pass the variables needed to create the object through the ...[z][1]['tbl'] var.

-- I will now load the map by actually creating the instances

for xx,v in ipairs(world) do
	for yy,v in ipairs(world[xx]) do
		for x,v in ipairs(world[xx][yy] do
			for y,v in ipairs(world[xx][yy][x]) do
				for z,v in ipairs(world[xx][yy][x][y]) do
					for k,v in ipairs(world[xx][yy][x][y][z]) do
						if v.type = 'surface' then
							loadedMap[#loadedMap +1] = ObjSurface:new(v.tbl)	--Creates the instance with the customized variables inside v.tbl
							loadedMap[#loadedMap]:init() 	-- Initiates the instance to perform some calculations before it can 'exist'
						end
					end
				end
			end
		end
	end
end

-- Nothing wrong in here either as it works like how it should.
-- First creates the world, with chunks so i can better control which tiles should be on the loadedMap later.
-- I also did this so i could save the world with the Binser lib as i can't save directly instances because i cant seem to load them after...

function love.update(dt)
	--updates each instance
	for k,v in ipairs(loadedMap) do
		v:update()
	end
end

function love.draw()
	--draws each instance
	for k,v in ipairs(loadedMap) do
		v:draw()
	end
end

My actual code, which follows this pattern, does quite work the way i intended.

I did not, however, intend to have such a low Frame rate with such a basic world grid. It is isometric and it is supposed to be a very customized world with construction and destruction but a simple tile filled world is so slow..

I managed to improve a bit by only having the objects drawn if they are near the player (anywhere the player would be, only 9 chunks would be drawn, the chunk where the player is obviously, and the 8 chunks around it.)

But still having less rendered stuff, it would only improve frame rate to around a mere 25 fps while it isnt affected by frame limiters on my mid-end gaming computer and pointless 5 fps on my Hybrid ideapad, which for its complexity and size should still have a typical frame rate of 60.

What i'm asking here is how can use my objects to have individual update cycles and still have a proper frame rate.
It looks as it takes too long drawing cause it is iterating through many objects.

In the objSurface:draw() itself, it is pretty optimized already, it simply backups current color, sets a new one, and draws a polygon based on self.points which is set only once on objSurface:init() and stays constant on that tile.

I also want to have different objects capable of interaction with the world's objects either by collision or telepathy(lol) with different draw and update states, but since i can't seem to even have just a couple of them, completly static, to lag out the whole game, it gets difficult.

I don't see spritebatch as an option and Canvases is quite nasty to update every second it might as well do worse.

I would post original code but It isn't at the state i above tried to replicate as i am currently exploring different stuff and i just currently gave up using love.thread as i can't pass objects through and i had an emotional breakdown around this issues ahah.

Thank you so much in advance for following down this, there are probably many ways to do this exactly but I for the first time hit the state where I can't find what i'm looking for.

User avatar
sefan
Prole
Posts: 22
Joined: Fri Jul 31, 2015 7:03 am
Contact:

Re: Need help with (big) Table iteration

Post by sefan » Thu Feb 22, 2018 9:36 am

Welcom to the forum.

Please upload a .love file of your code. It makes it easier if you want people to help you.
It's hard to see on this code whats slowing your game down. Because I can't see whats happening in v:update() and v:draw().
To save some startup time you could put all the loadedMap code from the second big for loop into the first big for loop.

Edit:
Why do you make a 5D table and the put everything in to a 1D table?
If you keep the 5D table you can easier update and draw the chunks you want to update and draw. Like:

Code: Select all

for i=player.xx-1,player.xx+1 do
	for j=player.yy-1,player.yy+1 do
		--Draw/update stuff here
	end
end

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

Re: Need help with (big) Table iteration

Post by zorg » Thu Feb 22, 2018 10:47 am

If anything, i'd remove that 5D table completely, simply tracking where the player (or camera) is with two coordinates, compute how many chunks relative to that coordinate pair is visible (plus a few more on the edges for safety), and what they are, and then dynamically load only those, and remove those that are outside that safety margin.

You could use one helper array, containing keys denoting a combined x and y chunk as string, for example ('XX:YY'), and the value would be the start index of the tiles in that specific chunk; if all chunks are the same size, then this can speed up the removal of tiles from now-inactive chunks. (Since, that table we're talking about is 1-dimensional, so it should be fast enough... although benchmarking whether this would be faster, or a 2D-table where the first dimension is just the loaded chunks, and the second is all the included times might be faster with removal of chunk-sub-tables; it wouldn't be necessary to move values around. (and i'm not sure if table.remove can remove a certain range from the middle of a table, let's say)

And also, only update and draw loaded chunks, which would be easy if you did the above mentioned optimization.

If it's still slow, you really should invest in either spritebatches, canvases, or both; having this many separate draw calls is not something that will ever be fast; even modern games don't do millions of them. Even if the game is isometric, you could store and or calculate how things may block one another, and only draw the "topmost" visible things, with possible exceptions for semi-transparent or non-concave shapes or whatever. Iteration through the visible world could build up the scene based on tiles' y coordinate (depth, semi-vertical axis) and their true height, for example.
Me and my stuff :3True 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.

Stigma
Prole
Posts: 2
Joined: Wed Feb 21, 2018 5:37 pm

Re: Need help with (big) Table iteration

Post by Stigma » Thu Feb 22, 2018 6:06 pm

sefan wrote:
Thu Feb 22, 2018 9:36 am
Welcom to the forum.

Please upload a .love file of your code. It makes it easier if you want people to help you.
It's hard to see on this code whats slowing your game down. Because I can't see whats happening in v:update() and v:draw().
...
Hey! Thank you for replying.

Yes, i do realize that, its just as i said, the actual state of my project isn't as the one described 100% as i am testing out new solutions.

I'd say i perhaps want to know how to manage to update and draw many tile objects per frame. Also every tile will matter inside the screen even those behind, lets say, a wall.

It is meant to be able to easily have objects and entities in there and when unloading chunks, save entities and their states back to that world/map table.

I tend to tackle optimization of startup way after as it is far easier, so even though i know it isn't optimized and also know how exactly to do it optimized, i first do it in a way that is easy for me to comprehend by dividing those parts, like all those for nested loops, so i can change them for each particular loop so when it works the way it should or i simply think i won't need any more changes, i optimize it.

I'd also like to explaina little bit more of the objective here:
I want terrain, objects and entities as dynamic as it can be. II'm aiming for a 2.5D voxel-like sandbox with survival gameplay, so building and destroying structures is the way. That is why i want to update those individual instances.

I also am having trouble serializing instances as unserializing them after isn't getting me nowhere, even if it works with normal nD tables. I am sure that Binser works fine with table lookups so i can't really find out what can i do or what am i doing wrong there so thats why when i generate the world i set a TBL with the individual variables of the objects and only then creating the instance with that said variable. Saving the world after, or unloading chunks should be quite easy to do the reverse (grab instance's vars and set to the world chunk XX,YY,x,y,z table)

I will soon roll back to the state i described, where everything worked just like how i said.

User avatar
pgimeno
Party member
Posts: 1372
Joined: Sun Oct 18, 2015 2:58 pm

Re: Need help with (big) Table iteration

Post by pgimeno » Fri Feb 23, 2018 12:18 pm

Try adding [url=viewtopic.php?f=5&t=82562] to see if that helps. If it does, you may want to invest some time looking into spritebatches.
Thrust II Reloaded - GifLoad for Löve - GSpöt GUI - My NotABug.org repositories - portland (mobile orientation)
The MS-Github repositories I had have been closed after the acquisition announcement and will be removed in the near future.

Post Reply

Who is online

Users browsing this forum: St. Cosmo and 2 guests