[Solved]Poor Map Drawing Performance

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
FlashFire
Prole
Posts: 20
Joined: Thu Sep 11, 2014 12:44 am

[Solved]Poor Map Drawing Performance

Post by FlashFire »

On the game I'm making, I'm getting pretty horrible frame rates while drawing the map, I was wondering if there would be a way to increase it.

Basicly, the map is a grid, 2 layers deep. Background is drawn, then the main map, and then lighting affects are put on after that. The lighting affects seem to be a large part of the issue. I'm getting around 15-30 fps if I render the light, and 60-130 if I don't render the light. Also, this part of the code takes about 90% of the games processing.

Is this since map is sorta big? I'd rather not go to a chunk system.

Code: Select all

----------------
---map

map = {}

map.background = {}
map.map = {}
map.data = {}
map.light = {}

local selectiveRender = true

function map:getData(x,y)
	if not map.data[x] then
		map.data = {}
	end
	return map.data[x][y]
end

local vectorTableHigh    = {Vector2.new(0,1),Vector2.new(0,-1),Vector2.new(-1 ,0),Vector2.new(1, 0)}
local vectorTableMed     = {Vector2.new(1,1),Vector2.new(-1,1),Vector2.new(-1,-1),Vector2.new(1,-1)}
local vectorTableLow     = {Vector2.new(2,0),Vector2.new(-2,0),Vector2.new( 0, 2),Vector2.new(0,-2)}
local vectorTableLowest  = {Vector2.new(2,2),Vector2.new(-2,2),Vector2.new( 2,-2),Vector2.new(2,-2)}

function map:checkAir(pos) --first call for light
	if not map.light[pos.X] then
		map.light[pos.X] = {}
	end
	if not map.light[pos.X][pos.Y] then
		map.light[pos.X][pos.Y] = map:getLight(pos)
	end
	return map.light[pos.X][pos.Y]
end

function map:updateLight(pos,value) -- helper function for light
	if map.light[pos.X] then
		map.light[pos.X][pos.Y] = nil
	end
	for i,v in pairs(vectorTableHigh) do
		local pos = pos+v
		if map.light[pos.X] then
			map.light[pos.X][pos.Y] = nil
		end
	end
	for i,v in pairs(vectorTableMed) do
		local pos = pos+v
		if map.light[pos.X] then
			map.light[pos.X][pos.Y] = nil
		end
	end
	for i,v in pairs(vectorTableLow) do
		local pos = pos+v
		if map.light[pos.X] then
			map.light[pos.X][pos.Y] = nil
		end
	end
	for i,v in pairs(vectorTableLowest) do
		local pos = pos+v
		if map.light[pos.X] then
			map.light[pos.X][pos.Y] = nil
		end
	end
end

function map:getLight(pos) -- helpter function for light
	if map[pos.X] and (map[pos.X][pos.Y] == 'air' or map[pos.X][pos.Y] == nil) then
		return 0
	end

	local detailMap = map:getMap()
	for i,v in pairs(vectorTableHigh) do
		local pos = pos+v
		local block = detailMap[pos.X][pos.Y]
		if block then
			if block == 'air' or data.itemInfo[block].solid == false then
				return .2
			end
		else
			return .2
		end
	end
	
	for i,v in pairs(vectorTableMed) do
		local pos = pos+v
		local block = detailMap[pos.X][pos.Y]
		if block then
			if block == 'air' or data.itemInfo[block].solid == false then
				return .5
			end
		else
			return .5
		end
	end
	

	for i,v in pairs(vectorTableLow) do
		local pos = pos+v
		local block = detailMap[pos.X][pos.Y]
		if block then
			if block == 'air' or data.itemInfo[block].solid == false then
				return .7
			end
		else
			return .7
		end
	end

	for i,v in pairs(vectorTableLowest) do
		local pos = pos+v
		local block = detailMap[pos.X][pos.Y]
		if block then
			if block == 'air' or data.itemInfo[block].solid == false then
				return .9
			end
		else
			return .9
		end
	end

	return 1
end

function map:render() -- actually drawing
	local mapObj = map
	local background = map:getBackground()
	local map = map:getMap()
	love.graphics.setColor(0,0,0)
	--love.graphics.rectangle('fill',0,Camera.Y+300,screenSize.X,screenSize.Y)

	local xStart = -(Camera.X-Camera.X%50)/50
	local yStart = -(Camera.Y-Camera.Y%50)/50

	local xExtend = (screenSize.X-screenSize.X%50)/50
	local yExtend = (screenSize.Y-screenSize.Y%50)/50

	love.graphics.setColor(100,100,100)

	for xIndex = xStart-1,xStart+xExtend do  --  Draw background
		for yIndex = yStart-yExtend,yStart+yExtend do
			if background[xIndex] and background[xIndex][yIndex] then
				local value = background[xIndex][yIndex]
				if images[value .. 'Dark'] then
					local pos = Vector2.new(xIndex*50+Camera.X,yIndex*50+Camera.Y+450)
					love.graphics.draw(images[value .. 'Dark'],pos.X,pos.Y,nil,.5,.5)
				else
					print('ERROR: Unable to load the dark version of ' .. value)
				end
			end
		end
	end

	love.graphics.setColor(255,255,255)

	for xIndex = xStart-1,xStart+xExtend do  -- Draw foreground, or main map
		for yIndex = yStart-yExtend,yStart+yExtend do
			local value = map[xIndex] and map[xIndex][yIndex]
			if value ~= 'air' and value then
				local pos = Vector2.new(xIndex*50+Camera.X,yIndex*50+Camera.Y+450)
				if pos.Y >= -100 and pos.Y < screenSize.Y then
					if value and string.sub(value,1,1) ~= '_' then
						if data.itemInfo[value].animation ~= true then
							love.graphics.draw(images[value],pos.X,pos.Y,nil,.5 * (data.itemInfo[value].scale and data.itemInfo[value].scale or 1),.5 * (data.itemInfo[value].scale and data.itemInfo[value].scale or 1))
						else
							blockAnimation.playAnimation(value,pos.X,pos.Y,.5,.5,Vector2.new(xIndex,yIndex))
						end
					end
					if coreFunctions.mine.block.X == xIndex and coreFunctions.mine.block.Y == yIndex then			
						love.graphics.draw(images.breakingAnimation['breaking'..tostring(math.ceil(coreFunctions.mine.frame/30))],pos.X,pos.Y,nil,.5,.5)
					end	
				end
			end
		end
	end

	if selectiveRender then  --  Draw the lighting, this is where the main slow down is.
		love.graphics.setColor(0,0,0,200)
		for xIndex = xStart-1,xStart+xExtend do
			for yIndex = yStart-yExtend,yStart+yExtend do
				local pos = Vector2.new(xIndex*50+Camera.X,yIndex*50+Camera.Y+450)
				if pos.Y >= -100 and pos.Y < screenSize.Y then
					love.graphics.setColor(0,0,0,255*mapObj:checkAir(Vector2.new(xIndex,yIndex)))
					love.graphics.rectangle('fill',pos.X,pos.Y,50,50)
				end
			end
		end
	end
end
Last edited by FlashFire on Wed Apr 22, 2015 10:16 pm, edited 1 time in total.
User avatar
arampl
Party member
Posts: 248
Joined: Mon Oct 20, 2014 3:26 pm

Re: Poor Map Drawing Performance

Post by arampl »

Are you sure you need "Vector2.new()" and similar functions? Maybe better would be to simplify this.
I've already read something about using "beautiful" mathematical libraries, that it is bad for performance.

EDIT:
Excerpt from "Lua programming gems":

Limit the use of complex types
Strings, tables, or metatables used for temporary variables are not recommended,
because they will fire the memory allocator. Prefer using simple types like
booleans, numbers, or lightuserdatas. For example using a vector class imple-
mented in Lua with metatables will surely be very elegant, but not encouraged
if you are looking for the best performances. In general all syntax sugars are
not good for speed, or must be preprocessed. So for example to perform a dot
product between two vectors, prefer using this solution:

Code: Select all

local x1, y1, z1 = 1.0, 0.0, 0.0
local x2, y2, z2 = 0.0, 1.0, 0.0
local dot = math.dotProduct ( x1, y1, z1, x2, y2, z2 )
Than this more elegant but slower one:

Code: Select all

local v1 = Vector3:new ( 1.0, 0.0, 0.0 )
local v2 = Vector3:new ( 0.0, 1.0, 0.0 )
local dot = v1:dotProduct ( v2 )
Separate values of the first version will be stored on top of the Lua stack,
but tables used for the syntax sugar of the second one, will require at least two
memory allocations. Multiplied by the number of such operations needed to
represent your behavior, and then by the number of active AIModel instances at
a time, those two versions of the same code will have a small but sometimes not
negligible difference, in term of execution speed.[/i]

EDIT: Though it can doesn't matter at all because LÖVE uses JIT...
FlashFire
Prole
Posts: 20
Joined: Thu Sep 11, 2014 12:44 am

Re: Poor Map Drawing Performance

Post by FlashFire »

Thanks, I changed the code to that, and the FPS went from an unstable 15, to a very stable 65(Without vsync)
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 8 guests