# Basic Touch zone detection, how should it be re-written to optimise the code

I am just getting my feet wet with Codea and don’t fully grasp the concept of creating separate classes and passing information where the code refers to nnnnn.self etc.

I have written my simple method of zone detection on a 5 x 5 matrix of squares. It provide the correct output, however looking at other examples it looks like I need to get my head round other concepts before I try to take my idea further.

Anyone who has any suggestion as to how the code should be written, feel free to comment. All the code below exists in the main routine.

---- Touch Detection

– Use this function to perform your initial setup
function setup()
print(“Hello World!”)
end

– This function gets called once every frame
function draw()
background(40, 40, 50)

``````strokeWidth(5)
noFill()
x = -5
y = -5
z = 0
regiona = {}
regionb = {}
regionc = {}
regiond = {}

for j = 1,5 do
y = y + 105
for i = 1,5 do
x = x + 105
rect(x,y,100,100)
z = z + 1
regiona[z] = x + 20
regionb[z] = y + 20
regionc[z] = x + 80
regiond[z] = y + 80
end
x = -5
end
end

function touched(touch)
if touch.state == ENDED then
print("x = "..touch.x.." y = "..touch.y)
text(touch.x,touch.x,touch.y)

--check touch zones
z = 0
for z=1,25 do
if touch.x > regiona[z] and touch.x < regionc[z] and touch.y > regionb[z] and touch.y < regiond[z] then
print("zone "..z)
break
end
end
end

end
``````

@time2innov8 Here’s another version. Tap a square. The size of the squares can be changed by changing size.

``````
displayMode(FULLSCREEN)

function setup()
size=100    -- size of the squares
tab={}    -- table for square x,y coordinates
for x=1,5 do     -- create table
for y=1,5 do
table.insert(tab,vec2(x*size,y*size))
end
end
zone=0    -- variable for touched zone
end

function draw()
background(40,40,50)
strokeWidth(2)
stroke(255)
for a,b in pairs(tab) do  -- loop thru table
noFill()
if a==zone then    -- square touched, fill with color
fill(255, 0, 0)
end
rect(b.x,b.y,size,size)    -- draw squares
end
end

function touched(touch)
if touch.state == ENDED then
for a,b in pairs(tab) do   --check touch zones
if touch.x > b.x and touch.x < b.x+size and
touch.y > b.y and touch.y < b.y+size then
zone=a  -- save zone
break
end
end
end
end

``````

As an alternative for checking the touch zones you could use:

``````
if math.abs(touch.x-b.x)<size and math.abs(touch.y-b.y)<size then

``````

This reduces the number of times you type each variable and each comparator reducing the chance of getting a typo in either.

@time2innov8 - see the posts on classes in the index on this page, they try to explain the whole self thing. I found it very confusing at first, too!

http://coolcodea.wordpress.com/2013/06/19/index-of-posts/#more-8884

Thanks @West, I always like to see easier way of doing something.

@West I tried your simplified code along with code from @dave1707 which I modified to keep a track of the touched areas by keeping them green. A strange issue is happening with the simplified, I am getting multiple iterations of the touch loop for one contact. I added a loop counter to check what was happening, can’t explain why its occuring. The code is listed below.

``````-- testcode

function setup()
size=100    -- size of the squares
tab={}    -- table for square x,y coordinates
tempzone={}
for y=1,5 do     -- create table
for x=1,5 do
table.insert(tab,vec2(x*size,y*size))
end
end
for c=1,25 do
tempzone[c]=0
end
zone=0    -- variable for touched zone
loopcount = 0

end

function draw()
background(40,40,50)

strokeWidth(2)
stroke(255)
for a,b in pairs(tab) do  -- loop thru table
noFill()
if tempzone[a] == 1 then
fill(0,255,0)
end
if a == zone then    -- square touched, fill with color
fill(255, 0, 0)
end

rect(b.x,b.y,size,size)    -- d
end
end

function touched(touch)

if touch.state == ENDED then
for a,b in pairs(tab) do   --check touch zones

--  if math.abs(touch.x-b.x)<size and math.abs(touch.y-b.y)<size then
-- causes multiple loop iterations on touch

if touch.x > b.x and touch.x < b.x+size and touch.y > b.y and touch.y < b.y+size then
-- works correctly

zone = a
if tempzone[a] == 0 then
tempzone[a] = 1
else
tempzone[a] = 0
break
end
loopcount = loopcount + 1
print("start"..loopcount)
print(a)
end
end
end
end
``````

@time2innov8 You were missing a break in the for loop and weren’t exiting correctly. See the code below where I added the break and comment.

EDIT: Or you could remove the 2 break statements and put 1 break after loopcount=loop count+1 .

``````
-- testcode

function setup()
size=100 -- size of the squares
tab={} -- table for square x,y coordinates
tempzone={}
for y=1,5 do -- create table
for x=1,5 do
table.insert(tab,vec2(x*size,y*size))
end
end
for c=1,25 do
tempzone[c]=0
end
zone=0 -- variable for touched zone
loopcount = 0
end

function draw()
background(40,40,50)

strokeWidth(2)
stroke(255)
for a,b in pairs(tab) do -- loop thru table
noFill()
if tempzone[a] == 1 then
fill(0,255,0)
end
if a == zone then -- square touched, fill with color
fill(255, 0, 0)
end
rect(b.x,b.y,size,size) -- d
end
end

function touched(touch)
if touch.state == ENDED then
for a,b in pairs(tab) do --check touch zones
if math.abs(touch.x-b.x)<size and math.abs(touch.y-b.y)<size then
--if touch.x > b.x and touch.x < b.x+size and
--touch.y > b.y and touch.y < b.y+size then
zone = a
if tempzone[a] == 0 then
tempzone[a] = 1
break                        -- break added here
else
tempzone[a] = 0
break
end
loopcount = loopcount + 1
--print("start"..loopcount)
--print(a)
end
end
end
end

``````

@dave1707 I was getting confused regarding the usage of the break command, I was thinking it would exit the if statement as opposed to the for loop.

All part of the learning experience However if I take all the breaks out of the touched function, I still get the multiple positive iterations, given the the if statement is a shortened form I cannot understand whats going on. The reason it works with the additional breaks you identified is the first contact logged is correct. There should be no reason why checking every zone with the shortened if sequence causes the incorrect response.

``````-- testcode

function setup()
size=100 -- size of the squares
tab={} -- table for square x,y coordinates
tempzone={}
for y=1,5 do -- create table
for x=1,5 do
table.insert(tab,vec2(x*size,y*size))
end
end
for c=1,25 do
tempzone[c]=0
end
zone=0 -- variable for touched zone
loopcount = 0
end

function draw()
background(40,40,50)

strokeWidth(2)
stroke(255)
for a,b in pairs(tab) do -- loop thru table
noFill()
if tempzone[a] == 1 then
fill(0,255,0)
end
if a == zone then -- square touched, fill with color
fill(255, 0, 0)
end
rect(b.x,b.y,size,size) -- d
end
end

function touched(touch)
if touch.state == ENDED then
for a,b in pairs(tab) do --check touch zones

if math.abs(touch.x-b.x)<size and math.abs(touch.y-b.y)<size then
-- multiple loop interations for single contact

--    if touch.x > b.x and touch.x < b.x+size and touch.y > b.y and touch.y < b.y+size then
-- works correctly
zone = a
if tempzone[a] == 0 then
tempzone[a] = 1
else
tempzone[a] = 0
end
loopcount = loopcount + 1
print("loop"..a)
end
end
end
end
``````

@time2innov8 The shortened version isn’t as restrictive as the long version I used in my original example. The short version actually matches 4 conditions for each touch. The break forces an exit after the 1st match. The short version would probably work for touch areas that aren’t close to each other, but in your example where the touch areas are next to each other, you’ll get 4 conditions that match. In the long version, the break is used just to exit the loop because there won’t be another match, so there’s no reason to continue to keep checking. The break in the short version is used to not give you the wrong touch match after the 1st match. I haven’t tried this yet with the short version, but I think that if I set up a for loop going in the reverse order, doing a break on the first match will be the wrong match. Hope that makes sense.

EDIT: I changed the for loop to go in the reverse order and the short version with the break always matched the wrong square.

@time2innov8 @West I wanted to figure out what was wrong with the short version of the touch area code. I put together this demo to illustrate what is actually happening. After I saw what was going on, I made a modification to the short version of code to make it work. Run this program and keep moving your finger around and over the green squares. A white dot will show where each version of the touch code thinks is a valid x,y position. You’ll see on the short version that the valid touch area is beyond the edge of the square. For the modified short version, I just divided size by 2.

``````
supportedOrientations(LANDSCAPE_ANY)

function setup()
tab1={}
tab2={}
tab3={}
x1=200
y1=600
x2=400
y2=400
x3=200
y3=200
size=100
end

function draw()
background(40,40,50)

-- draw square and dots for short version
fill(0, 255, 0, 255)
rectMode(CENTER)
rect(x1,y1,size,size)
fill(255)
for a,b in pairs(tab1) do
ellipse(b.x,b.y,8)
end
text("short version",400,600)

-- draw square and dots for long version
fill(0, 255, 0, 255)
rectMode(CORNER)
rect(x2,y2,size,size)
fill(255)
for a,b in pairs(tab2) do
ellipse(b.x,b.y,8)
end
text("long version",600,450)

-- draw square and dots for modified short version
fill(0, 255, 0, 255)
rectMode(CENTER)
rect(x3,y3,size,size)
fill(255)
for a,b in pairs(tab3) do
ellipse(b.x,b.y,8)
end
text("modified short version",400,200)
end

function touched(t)
if t.state == MOVING then
-- touch area short version
if math.abs(t.x-x1)<size and math.abs(t.y-y1)<size then
table.insert(tab1,vec2(t.x,t.y))
end

-- touch area long version
if t.x>x2 and t.x<x2+size and t.y>y2 and t.y<y2+size then
table.insert(tab2,vec2(t.x,t.y))
end

-- touch area modified short version
if math.abs(t.x-x3)<size/2 and math.abs(t.y-y3)<size/2 then
table.insert(tab3,vec2(t.x,t.y))
end
end
end

``````

@dave1707 I’m glad I wasn’t going mad thinking something was wrong with the original short code. Your example code proves exactly what was going on.

Oops sorry - my mistake. Trying to do it from memory rather than testing on ipad.
@dave1707, not sure if it is an easier way… 