Touch Handling Optimisation Troubles

Hi there,

I’m currently making a game which uses a isometric tiled grid as a map. The problem I’m having is with my touch handling. Every time the user touches a road it replaces that image with a lighter version of the original image to show that it has been “walked on” by the user. Everything works fine first time round (note I havent added any restrictions on movement between road tiles yet). But after I call my reset() function, which resets the road network after the user has completed the maze, the touch handling seems to be abit jumpy. It works on some tiles without a problem but then it completely skips others. The reason for which is a bit beyond me. Anyone have any ideas? I can attached a screenshot of the map if needed. Any general coding tips are more than welcome also. My code is as follows:

[code]

– Hides status bar –
display.setStatusBar(display.HiddenStatusBar)
– BACKGROUND IMAGE –
local background = display.newImage( “_images/brown.png” )

– TILE IMAGES –
scrub = “_images/scrub.png” --1
grass = “_images/GRASS3.png” --2
road = “_images/roaddark.png” --4
path = “_images/path.png” --5
roadWalked = “_images/roadlight.png” --6
tree = “_images/trees3.png” --7
house = “_images/house1.png” --8
blank = “_images/blank.png” --9
start = “_images/start.png” --10
finish = “_images/finish.png” --11

------------------- Display Hierarchy -----------------------

------------- last drawn = first to be seen -----------------

Map = display.newGroup() – background tiles
roadNetwork = display.newGroup() – roads/paths
enviroment = display.newGroup() – trees/buildings etc




– Global x,y coordinates to keep groups correctly positioned relative to eachother.
globalX = -60;
globalY = -18;

Map.x = globalX; Map.y = globalY;
roadNetwork.x = globalX; roadNetwork.y = globalY;
enviroment.x = globalX; enviroment.y = globalY;

Map:setReferencePoint(display.TopRightReferencePoint);
roadNetwork:setReferencePoint(display.TopRightReferencePoint);
enviroment:setReferencePoint(display.TopRightReferencePoint);

local currentTile
local previousTile

– Tile dimensions
local tileWidth = 60
local tileHeight = 18

– Our Map to be generated –
local level = {}

– number of rows and cols in our level.
local levelCols = 18
local levelRows = 44


---- IF COPY AND PASTING MAKE SURE FIRST ROW IS ALIGNED -----
---- LEFT IN ORDER TO KEEP IT MATCHED TO THE SCREEN GRID ----

level={
{7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 4 , 7 , 7 , 4 , 7 , 7 , 7 , 7 , 7 },
{ 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 4 , 4 , 7 , 7 , 4 , 1 , 1 , 4 , 7 , 7 },
{7 , 7 , 1 , 7 , 7 , 1 , 1 , 1 , 4 , 1 , 4 , 7 , 4 , 4 , 1 , 4 , 4 , 7 },
{ 7 , 1 , 1 , 7 , 1 , 1 , 1 , 4 , 1 , 1 , 4 , 4 , 1 , 4 , 4 , 11, 4 , 7 },
{7 , 1 , 1 , 1 , 1 , 1 , 1 , 4 , 1 , 1 , 1 , 4 , 1 , 1 , 4 , 1 , 1 , 4 },
{ 7 , 1 , 1 , 1 , 1 , 1 , 4 , 1 , 1 , 1 , 4 , 1 , 1 , 4 , 1 , 1 , 4 , 7 },
{7 , 7 , 1 , 1 , 1 , 1 , 1 , 4 , 1 , 1 , 4 , 1 , 1 , 4 , 1 , 1 , 4 , 7 },
{ 7 , 1 , 1 , 1 , 1 , 1 , 1 , 4 , 1 , 1 , 4 , 1 , 1 , 4 , 1 , 1 , 4 , 7 },
{7 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 4 , 1 , 1 , 4 , 1 , 1 , 4 , 1 , 1 , 4 },
{ 7 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 4 , 1 , 1 , 4 , 1 , 1 , 1 , 1 , 1 , 4 },
{7 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 4 , 1 , 4 , 1 , 1 , 1 , 1 , 1 , 4 },
{ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 4 , 4 , 4 , 1 , 1 , 1 , 4 , 4 , 7 },
{7 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 4 , 1 , 4 , 1 , 1 , 4 , 4 , 7 },
{ 1 , 1 , 1 , 1 , 1 , 1 , 4 , 1 , 1 , 4 , 1 , 1 , 4 , 1 , 4 , 8 , 7 , 7 },
{7 , 1 , 1 , 1 , 1 , 1 , 4 , 4 , 1 , 4 , 1 , 1 , 4 , 1 , 4 , 4 , 8 , 7 },
{ 1 , 1 , 1 , 4 , 1 , 4 , 8 , 4 , 4 , 1 , 1 , 4 , 1 , 4 , 1 , 4 , 8 , 7 },
{7 , 1 , 1 , 1 , 4 , 4 , 7 , 7 , 4 , 1 , 1 , 4 , 1 , 1 , 1 , 4 , 8 , 7 },
{ 7 , 1 , 1 , 1 , 4 , 7 , 7 , 7 , 4 , 1 , 4 , 1 , 4 , 1 , 4 , 8 , 4 , 7 },
{7 , 7 , 1 , 1 , 1 , 4 , 8 , 7 , 7 , 4 , 4 , 4 , 1 , 4 , 4 , 4 , 4 , 4 },
{ 7 , 1 , 1 , 1 , 1 , 4 , 8 , 8 , 7 , 4 , 1 , 4 , 4 , 4 , 1 , 4 , 8 , 4 },
{7 , 1 , 1 , 1 , 1 , 1 , 4 , 8 , 7 , 8 , 1 , 1 , 4 , 1 , 1 , 4 , 8 , 7 },
{ 7 , 1 , 1 , 1 , 1 , 1 , 4 , 8 , 4 , 1 , 1 , 4 , 1 , 1 , 4 , 4 , 7 , 7 },
{7 , 7 , 1 , 1 , 1 , 1 , 4 , 4 , 4 , 4 , 1 , 4 , 8 , 4 , 4 , 8 , 4 , 7 },
{ 7 , 7 , 1 , 1 , 1 , 4 , 2 , 4 , 2 , 4 , 1 , 4 , 8 , 4 , 8 , 4 , 7 , 7 },
{7 , 7 , 1 , 1 , 1 , 4 , 2 , 2 , 2 , 2 , 4 , 1 , 4 , 8 , 8 , 4 , 4 , 7 },
{ 7 , 1 , 1 , 1 , 4 , 2 , 2 , 2 , 2 , 4 , 1 , 4 , 4 , 8 , 4 , 1 , 4 , 7 },
{7 , 1 , 1 , 1 , 4 , 8 , 2 , 2 , 2 , 4 , 4 , 4 , 1 , 4 , 4 , 1 , 1 , 4 },
{ 1 , 1 , 1 , 1 , 4 , 8 , 2 , 2 , 4 , 1 , 4 , 1 , 1 , 4 , 1 , 1 , 4 , 7 },
{7 , 1 , 1 , 1 , 1 , 4 , 8 , 8 , 4 , 1 , 1 , 4 , 1 , 1 , 1 , 1 , 4 , 7 },
{ 1 , 1 , 4 , 1 , 4 , 8 , 8 , 4 , 1 , 1 , 1 , 4 , 1 , 1 , 1 , 1 , 4 , 7 },
{7 , 1 , 4 , 4 , 4 , 8 , 8 , 4 , 1 , 1 , 1 , 1 , 4 , 1 , 1 , 1 , 1 , 4 },
{ 1 , 4 , 10, 4 , 2 , 8 , 4 , 1 , 1 , 1 , 1 , 4 , 1 , 1 , 1 , 1 , 4 , 7 },
{7 , 1 , 4 , 4 , 2 , 2 , 8 , 4 , 1 , 4 , 1 , 4 , 1 , 1 , 1 , 1 , 4 , 8 },
{ 7 , 1 , 4 , 2 , 2 , 2 , 8 , 4 , 4 , 4 , 1 , 4 , 1 , 1 , 4 , 4 , 8 , 7 },
{7 , 7 , 4 , 2 , 2 , 2 , 4 , 8 , 4 , 2 , 4 , 1 , 4 , 1 , 4 , 4 , 8 , 7 },
{ 7 , 4 , 8 , 4 , 2 , 4 , 4 , 8 , 2 , 2 , 4 , 1 , 4 , 4 , 8 , 8 , 8 , 7 },
{7 , 4 , 8 , 2 , 4 , 4 , 8 , 4 , 8 , 2 , 2 , 4 , 1 , 4 , 4 , 8 , 8 , 8 },
{ 4 , 8 , 2 , 2 , 4 , 8 , 8 , 4 , 2 , 2 , 2 , 4 , 1 , 1 , 4 , 8 , 8 , 4 },
{7 , 4 , 8 , 2 , 8 , 4 , 8 , 8 , 4 , 2 , 2 , 4 , 1 , 1 , 4 , 4 , 8 , 4 },
{ 7 , 4 , 8 , 8 , 4 , 8 , 8 , 4 , 2 , 2 , 4 , 1 , 1 , 4 , 2 , 4 , 4 , 7 },
{7 , 8 , 4 , 8 , 4 , 8 , 8 , 4 , 4 , 2 , 4 , 4 , 1 , 4 , 2 , 2 , 4 , 7 },
{ 7 , 8 , 4 , 4 , 2 , 4 , 4 , 2 , 4 , 4 , 2 , 4 , 4 , 2 , 2 , 2 , 2 , 7 },
{7 , 7 , 8 , 4 , 2 , 2 , 4 , 2 , 2 , 4 , 2 , 2 , 4 , 2 , 7 , 7 , 2 , 7 },
{ 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 2 , 7 },

}




local movingLegal = false

function main()
buildGrid()
end

– builds our grid –
function buildGrid()

– For loops go through the level array to
– determine what image to display
for row = 1,levelRows do
for col = 1,levelCols do

– offset is used to create the diagonal grid
if (row/2) ~=math.floor(row/2) then
xOffset = 0;
else
xOffset = 30;
end

if level[row][col] ~= nil then

– if statements to match the array number to its
– respective tile.
if level[row][col] == 1 then
image = scrub
tileType = “scrub”

elseif level[row][col] == 2 then
image = grass
tileType = “grass”

elseif level[row][col] == 4 then
image = road
tileType = “road”

elseif level[row][col] == 5 then
image = path
tileType = “path”

elseif level[row][col] == 6 then
image = roadWalked
tileType = “roadWalked”

elseif level[row][col] == 7 then
image = tree
tileType = “tree”

elseif level[row][col] == 8 then
image = house
tileType = “house”

elseif level[row][col] == 9 then
image = blank
tileType = “blank”

elseif level[row][col] == 10 then
image = start
tileType = “start”

elseif level[row][col] == 11 then
image = finish
tileType = “finish”
end

– X and Y position of currentTile including
– the required X offset.
xPosition = (col*tileWidth) + xOffset;
yPosition = (row*tileHeight);

– Initializes the tile as an image
currentTile = display.newImage(image);

currentTile.type = tileType;

currentTile.x = xPosition; currentTile.y = yPosition;
currentTile:setReferencePoint(display.CenterReferencePoint)

if level[row][col] == 8 or level[row][col] == 7 or level[row][col] == 10 or level[row][col] == 11 then
currentTile:setReferencePoint(display.BottomCenterReferencePoint)
currentTile.y = yPosition + 18
end

– Sets both a row, col, x and y attributes to
– the display object for later use.
currentTile.row = row;
currentTile.col = col;
–currentTile.xPosition = xPosition;
–currentTile.yPosition = yPosition;

– If statements which determine which group to place
– each tile in and which touch handler to attach to
– the tile. ie scrub would go in map group with map listener
–while house tile would go in enviroment group with enviroment listener.
if level[row][col] == 1 then
currentTile:addEventListener(“touch”, touchHandlerMap);
Map:insert(currentTile)

elseif level[row][col] == 2 then
currentTile:addEventListener(“touch”, touchHandlerMap);
Map:insert(currentTile)

elseif level[row][col] == 4 then
currentTile:addEventListener(“touch”, touchHandlerMap);
roadNetwork:insert(currentTile)

elseif level[row][col] == 5 then
currentTile:addEventListener(“touch”, touchHandlerMap);
roadNetwork:insert(currentTile)

elseif level[row][col] == 6 then
currentTile:addEventListener(“touch”, touchHandlerMap);
roadNetwork:insert(currentTile)

elseif level[row][col] == 7 then
enviroment:insert(currentTile)

elseif level[row][col] == 8 then
enviroment:insert(currentTile)

elseif level[row][col] == 9 then
currentTile:addEventListener(“touch”, touchHandlerMap);
Map:insert(currentTile)

elseif level[row][col] == 10 then
currentTile:addEventListener(“touch”, touchHandlerEnviroment);
enviroment:insert(currentTile)

elseif level[row][col] == 11 then
currentTile:addEventListener(“touch”, touchHandlerEnviroment);
enviroment:insert(currentTile)

end

end
end
end
end

– Function called when a touch event occurs
function touchHandlerMap(event)
local target = event.target

if event.phase == “moved” then
if previousTile == “road” or previousTile == “start” then
– road touch event
if target.type == “road” and movingLegal == true then
newTile = display.newImage(roadWalked)
newTile.x = target.x;
newTile.y = target.y;
newTile.type = “roadWalked”;
newTile:addEventListener(“touch”, touchHandlerMap);

target:removeEventListener(“touch”, touchHandlerMap)
target:removeSelf()

previousTile = “road”
roadNetwork:insert(newTile)
return true

end
end
end

return true
end

function touchHandlerEnviroment(event)
local target = event.target

if event.phase == “began” then

if target.type == “start” then
movingLegal = true
previousTile = “start”
return true
end

elseif event.phase == “ended” and movingLegal == true then

if target.type == “finish” then
print(“you win”)
reset()
return true

end
movingLegal = false;

end
return true
end

function reset()

for i = roadNetwork.numChildren, 1, -1 do
target = roadNetwork[i]
newTile = display.newImage(road)
newTile.x = target.x; newTile.y = target.y;
newTile.type = “road”;
newTile:addEventListener(“touch”, touchHandlerMap);

target:removeEventListener(“touch”, touchHandlerMap)
target:removeSelf()

roadNetwork:insert(newTile)
end
end

– gets the ball rolling –
main();

[/code] [import]uid: 134131 topic_id: 24046 reply_id: 324046[/import]

Check that new and old tiles are having their handlers removed at the right time. Are the original tiles being removed properly or sitting under the new? Put in lots of debug print statements. [import]uid: 8271 topic_id: 24046 reply_id: 97031[/import]

thanks for that, got it working now. I have another problem now which is annoying me a lot. I dont see what is wrong with what I am trying to do, let me fill you in.
I am now adding restrictions to tile movement. When I initalise a new tile I set a properties .row and .col to the row and col of the tile position in the level array. But when I try to access these properties in a method it keeps throwing back a null value, even when I print out the value straight before I try to access the property, no problems printing the value, so im stumped … any ideas?

....  
-- For loops go through the level array to  
 -- determine what image to display  
 for row = 1,levelRows do  
 for col = 1,levelCols do  
  
 -- offset is used to create the diagonal grid  
 if (row/2) ~=math.floor(row/2) then  
 xOffset = 0;  
 else  
 xOffset = 30;  
 end  
  
  
 if level[row][col] ~= nil then  
  
 -- if statements to match the array number to its  
 -- respective tile.  
 if level[row][col] == 1 then  
 image = scrub  
 tileType = "scrub"  
  
 elseif level[row][col] == 2 then  
 image = grass  
 tileType = "grass"  
  
 elseif level[row][col] == 4 then  
 image = road  
 tileType = "road"  
  
 elseif level[row][col] == 5 then  
 image = path  
 tileType = "path"  
  
 elseif level[row][col] == 6 then  
 image = roadWalked  
 tileType = "roadWalked"  
  
 elseif level[row][col] == 7 then  
 image = tree  
 tileType = "tree"  
  
 elseif level[row][col] == 8 then  
 image = house  
 tileType = "house"  
  
 elseif level[row][col] == 9 then  
 image = blank  
 tileType = "blank"  
  
 elseif level[row][col] == 10 then  
 image = start  
 tileType = "start"  
  
 elseif level[row][col] == 11 then  
 image = finish  
 tileType = "finish"  
 end   
  
  
 -- X and Y position of currentTile including  
 -- the required X offset.  
 xPosition = (col\*tileWidth) + xOffset;  
 yPosition = (row\*tileHeight);  
  
 -- Initializes the tile as an image  
 currentTile = display.newImage(image);   
  
 currentTile.type = tileType;  
  
 currentTile.x = xPosition; currentTile.y = yPosition  
 currentTile:setReferencePoint(display.CenterReferencePoint)  
  
 if level[row][col] == 8 or level[row][col] == 7 or level[row][col] == 10 or level[row][col] == 11 then  
 currentTile:setReferencePoint(display.BottomCenterReferencePoint)  
 currentTile.y = yPosition + 18  
 end  
  
 -- Sets both a row, col, x and y attributes to  
 -- the display object for later use.  
 currentTile.row = row;  
 currentTile.col = col;  
  
..........  
.....  
-- Function called when a touch event occurs   
function touchHandlerWalk(event)  
 local target = event.target  
 print (target.row) --works fine  
  
 if checkValidMove(target.row, target.col) then  
 if event.phase == "moved" then  
 if previousTile == "road" or previousTile == "start" then  
 -- road touch event  
 if target.type == "road" and movingLegal == true then  
 newTile = display.newImage(roadWalked)  
 newTile.x = target.x;  
 newTile.y = target.y;  
 newTile.type = "roadWalked";  
 newTile:addEventListener("touch", touchHandlerWalk);  
  
 target:removeEventListener("touch", touchHandlerWalk)  
 target:removeSelf()  
  
 previousTile = "road"  
 roadNetwork:insert(newTile)   
 return true  
  
 end  
 end  
 end  
 end  
  
 return true  
end  
.......  
....  
function checkValidMove(row, col)  
  
 if (row/2) ~= math.floor(row/2) then  
  
 if level[row - 1][col] == 4 then  
 return true  
 elseif level[row - 1][col - 1] == 4 then  
 return true  
 elseif level[row + 1][col] == 4 then  
 return true  
 elseif level[row + 1][col - 1] == 4 then  
 return true  
 end  
  
 elseif (row/2) == math.floor(row/2) then  
  
 if level[row - 1][col] == 4 then  
 return true  
 elseif level[row - 1][col + 1] == 4 then  
 return true  
 elseif level[row + 1][col] == 4 then  
 return true  
 elseif level[row + 1][col + 1] == 4 then  
 return true  
 end  
  
 else  
 return false;  
 end  
  
end  
.......  

the error:
main.lua:337: attempt to perform arithmic on local ‘row’ (a nil value) [import]uid: 134131 topic_id: 24046 reply_id: 97193[/import]

You are not setting the row and col values on the object which is referenced at line 337 of main.lua

First check: If the object at line 337 nil? (not null - this isn’t java :wink:
Second check: Are you creating the display object twice?
Third check: Find ALL the places you are loading this image
Fourth check: Lots of print statements leading up to the call of the checkValidMove

Let me know how you get on [import]uid: 8271 topic_id: 24046 reply_id: 97275[/import]

I got it sorted, thanks for your help :slight_smile: I was doubling up with event listeners on replaced tiles. The first handler caught the touch and replaced the tile, then the second listener tried to access the tile but it was no longer available, hence the nil (!) value. [import]uid: 134131 topic_id: 24046 reply_id: 97906[/import]