Page 1 of 1

Problem with map-functions

Posted: Sun Jul 22, 2012 11:47 am
by MalNeige
Alright, so I've been making some more progress. However, I'm stuck again. I'm trying to create a grid system like I had done earlier. The only problem is that I can't seem to use the perimeter "tileString". I need to use it for the map that I want to use (basic_test).

Edit: Before you ask, yes, this is the same topic where I asked for player help. I just didn't want to take up more forum space by making another post.

Re: Problem with player-functions

Posted: Sun Jul 22, 2012 4:36 pm
by Menniss
I've only been working with LÖVE for a day, but it looks to me like your love.draw() is the problem. You draw the player in newMap(), but love.draw() only calls drawMap(), which only ... draws the map.

Re: Problem with map-functions

Posted: Sun Jul 22, 2012 4:57 pm
by dreadkillz
Two problems I noticed. You're trying to call tileString in testMap, but it's not working because tileString is locally scoped in basic_test.lua. You'll have to make it a global variable. Second, you're trying to index tileString as a table, but it is just a long string so that will fail as well. Can't comment on the other stuff as I'm not familiar with tile systems.

Re: Problem with map-functions

Posted: Sun Jul 22, 2012 5:01 pm
by MalNeige
@dreadkillz So how could I possibly reference it as a string rather then a table? Perhaps that might fix it?

Re: Problem with map-functions

Posted: Sun Jul 22, 2012 6:54 pm
by Robin
MalNeige wrote:@dreadkillz So how could I possibly reference it as a string rather then a table? Perhaps that might fix it?
For getting a substring, you use string.sub.

Code: Select all

("hello"):sub(2, 2) == "e"
("hello"):sub(2, 4) == "ell"

Re: Problem with map-functions

Posted: Sun Jul 22, 2012 10:48 pm
by Santos
(I added "down" to love.keypressed by the way.)

Code: Select all

elseif key == "down" then
	 if testMap(0, 1) then
	 	 player.grid_y = player.grid_y + 16
	 end
Now, on to testMap!

Code: Select all

function testMap(x, y)
	if tileString[(player.grid_y / 16) + y][(player.grid_x / 16) + x] == '-' then
		return false
	elseif tileString[(player.grid_y / 16) + y][(player.grid_x / 16) + x] == 'x' then
		return false
	end
	return true
end
First of all, I'm not sure whether you want to be checking for "x", as it's the sky! :ultraglee:

Instead of using tileString, try using TileTable. TileTable is structured like TileTable[x][y], not like TileTable[y][x].

I think this code will be easier to read if the tests are joined with and, and the positions to test are stored in their own local variables (local meaning they won't be able to be seen outside the function they are defined in).

Code: Select all

function testMap(x, y)
	local testX = player.grid_x / 16 + x
	local testY = player.grid_y / 16 + y
	if TileTable[testX][testY] == '-' or
	   TileTable[testX][testY] == '#' then
		return false
	end
	return true
end
Well this kind of works... but it crashes sometimes and doesn't seem to work quite right. So, what can we do? It may be helpful to know more about what's going on than what is shown on the screen. We can use Lua's print function to print variable values to the screen. If you're using Windows, check out t.console, otherwise you can run LÖVE from the command line to see output from print.

Code: Select all

function testMap(x, y)
	local testX = player.grid_x / 16 + x
	local testY = player.grid_y / 16 + y

	print('player.grid_y: '..player.grid_y)
	print('player.grid_x: '..player.grid_x)
	print('x: '..x)
	print('y: '..y)
	print('testX: '..testX)
	print('testY: '..testY)
	print('TileTable[testX][testY]: '..TileTable[testX][testY])

	if TileTable[testX][testY] == '-' or
	   TileTable[testX][testY] == '#' then
		return false
	end
	return true
end
The top-left corner of TileTable is TileTable[1][1].

Let's say player.grid_x is at 16 (the second tile from the left of the screen, also the starting position) and the player moves left. What happens?

Code: Select all

local testX = player.grid_x / 16 + x
testX will be 0... which isn't quite what we want. Let's add 1 to testX and testY.

Code: Select all

local testX = player.grid_x / 16 + x
local testY = player.grid_y / 16 + y
It works! Well, unless the player goes off the screen, meaning TileTable[testX][testY] doesn't exist. To check this, we need to test whether TileTable[testX][testY] is true (which it will be if it isn't nil or false), and before that, whether TileTable[testX] is true (because if testX is out of range, TileTable[testX][testY] will be looking for testY in something which doesn't exist, TileTable[testX].)

Code: Select all

function testMap(x, y)
	local testX = player.grid_x / 16 + x + 1
	local testY = player.grid_y / 16 + y + 1

	print('player.grid_y: '..player.grid_y)
	print('player.grid_x: '..player.grid_x)
	print('x: '..x)
	print('y: '..y)
	print('testX: '..testX)
	print('testY: '..testY)

	if not TileTable[testX] or
	   not TileTable[testX][testY] then
		print(string.format('TileTable[%s][%s] doesn\'t exist!', testX, testY))
	else
		print('TileTable[testX][testY]: '..TileTable[testX][testY])
	end

	if not TileTable[testX] or
	   not TileTable[testX][testY] or
	   TileTable[testX][testY] == '-' or
	   TileTable[testX][testY] == '#' then
		return false
	end
	return true
end
(For more information on string.format as well as other string functions, check out String Library Tutorial on the lua-users wiki.)

For understandability, instead of having the number 16 everywhere, you can give it a name and use that instead, perhaps in ALL CAPS to signify that it's a global variable which won't change.

Code: Select all

TILESIZE = 16
You may or may not, depending on what the rest of your game will be like, also like to store the player's position as tile co-ordinates rather than an absolute position. For example, instead of the player being at player.grid_x being 16 and player.grid_y being 32, they would be 1 and 2 respectively.

Here are some changes you could make to do this:

Code: Select all

player = { grid_x = 2, grid_y = 2, act_x = 32, act_y = 32, speed = 10 }

Code: Select all

function updatePlayer(dt)
    player.act_y = player.act_y - ((player.act_y - player.grid_y * TILESIZE) * player.speed * dt)
    player.act_x = player.act_x - ((player.act_x - player.grid_x * TILESIZE) * player.speed * dt)
end

Code: Select all

function testMap(x, y)
	local testX = player.grid_x + x
	local testY = player.grid_y + y 

Code: Select all

if testMap(0, -1) then
	player.grid_y = player.grid_y - 1
end

etc.

Code: Select all

function love.draw()
	drawMap()
	love.graphics.rectangle("fill", player.act_x - TILESIZE, player.act_y - TILESIZE, TILESIZE, TILESIZE)
end
Depending on what else you're doing this might be easier. Or, it might not be. :ultraglee:

I hope this helps! ^^

Re: Problem with map-functions

Posted: Sun Jul 22, 2012 11:30 pm
by coffee
Before:
Santos wrote:I recommend kikito's love-tile-tutorial. (It even has a section on for loops!)
Now
Santos wrote: Instead of using tileString, try using TileTable.
Santos, see now the problems in what you involved MalNeige? I warned for that danger didn't I? ;)

I know that your intentions were good trying to give the best tutorial possible to MalNeige but I hope you understood now the evidence that Kikito's tile tutorial and his strings map concept (even that awesome) is not very suitable at all for starters.

Anyway very nice work and effort "cleaning the mess" Santos! :)

Re: Problem with map-functions

Posted: Mon Jul 23, 2012 11:45 am
by MalNeige
@Santos Thank you for your help. I'll constantly be referring to your guide as well as kikkito's guide to make sure I have a firm grasp on the code. I'm currently not sure how the code will effect things later on, but the nice thing is that I can fix it in post if need be. Again, thanks for the help.