Update: just changed title of discussion to better reflect subject matter…
Hi everyone, hope you’re all well. After my first successful go at a Codea game, I went back to basics and thought I’d practise by coding a simple touchscreen snap game. Turned out to be more confusing than the scrolling shoot-em-up but I finally got the game to work. It’s the settings page that’s going bug crazy! I’ve set up the options to change speed of transition, amount of cards, etc which just about works ok except that the numbers just don’t stop increasing after only one touch (it’s only supposed to go up one touch at a time!) I’m at a total loss as to why it’s doing this, although am pretty certain it’s something to do with the speed at which Codea draws… Anyone else got any ideas?
Here’s the relevant section of code (the whole program is about 200 odd lines):
if state == settings then
timebetween = timebetween + 1
sprite("Dropbox:Settings1", WIDTH/2, HEIGHT*0.25, 400)
pushStyle()
font("MarkerFelt-Thin")
fontSize(30)
fill(41, 36, 36, 255)
text(winnum, WIDTH/2+120, HEIGHT*0.25)
popStyle()
if CurrentTouch.x > WIDTH/2-200 and CurrentTouch.y > HEIGHT*0.25-60 then
if CurrentTouch.x < WIDTH/2+125 and CurrentTouch.y < HEIGHT*0.25+60 then
if timebetween > 80 then
if winnum == 50 then
winnum = 5
timebetween = 0
else winnum = winnum + 5
timebetween = 0
end
end
end
end
I presume that this is in draw. If so, it gets run every 60s, and CurrentTouch holds the most recent touch event, regardless of whether or not there has been a recent touch. It’s better to put this logic in the touched function so that it responds to actual touch events.
As a data point, I’ve been teaching Codea to young children (age 7 to 11) for the past year or so. For input I started with “currentTouch” thinking it would be easier than the “touched(t)” handler function, but it turned out to be confusing and when I showed the “touched(t)” alternative they got it fairly quickly and solidly.
Thanks @Andrew_Stacey@daveedvdv - appreciate you taking the time to answer; yes, this is in draw under the settings game state and is repeated for each of the three settings option. Funnily enough, I’ve tried both touched function and current touch and it happens with both. That said, I used the touched function by storing it in a variable and then using that in the conditional statement so might that have made it operate in the same way perhaps? It’s kind of weird because the game bit is working fine, it’s just the settings page that’s a bit buggy!
(Incidentally, what is the actual difference between the two functions? Would I be best to use touch.state? Pretend you’re talking to one of your 7-11 year olds if you like!)
@Andrew_stacey: Just my children and their friends. Lua is the new BASIC My youngest daughter just proudly presented her implementation of a Connect4-like game at her school’s science fair!
@ScottDafydd: What I teach the kids is that draw() should only draw and not process input or update state in any way. This correspond to what various programming models call the “Model-View” or “Model-View-Controller” approach to writing apps (e.g., Apple’s recommendation).
In that world, the update of timebetween right after the if state == settings test is suspect in the sense that it looks like timebetween is a state variable that lives between invocations of draw(), but I might understand better if I saw the whole code or if you could describe what the purpose of time between is (or maybe what a “snap game” is ;-).
@ScottDafydd - as Andrew said above, CurrentTouch holds the most recent state, however long ago it happened (so it can mislead your program into thinking the touch continues), whereas the touched function is only triggered by current touches.
When using touched, you should check the state property, which can be BEGAN, MOVING or ENDED. If you’re just trapping a touch on the screen, then either BEGAN or ENDED will do.
So for example, you can set a flag when you get a BEGAN state, then do your increment in draw and reset the flag to nil. Or do the increment in touched, like so
function touched(t)
if t.state==BEGAN then
if CurrentTouch.x > WIDTH/2-200 and CurrentTouch.y > HEIGHT*0.25-60 and
CurrentTouch.x < WIDTH/2+125 and CurrentTouch.y < HEIGHT*0.25+60
then
if timebetween > 80 then
if winnum == 50 then
winnum = 5
timebetween = 0
else winnum = winnum + 5
timebetween = 0
end
end
end
end
end
@ScottDafydd: I’m not sure whether it’s relevant, but to time things the tween functions can be useful. From memory (away from the iPad at this moment):
function timer_expired()
-- Called when the time is up
-- ... update some stet here
end
function touched(t)
if t.state == ENDED then
-- ...
tween.delay(1.2, timer_expired) -- timer_expired will be called in 1.2 seconds
end
end
The tween functions are described in the Animation section of the Codea reference, but they’re usually for all kinds of timing purposes in addition to pure animation.
@daveedvdv I’d be interested in hearing what the steps were in getting your daughter and her friends to that stage. My kids are of a similar age and I’d like to get them in to programming, but thus far haven’t hit on the right strategy.
(Maybe a separate thread for this discussion, if you’d be willing and have the time to share.)
@daveedvdv - yes, that’s VERY relevant. Thanks! One of the questions I’ve been meaning to ask for the last few days was regarding a more efficient way of handling time-delays between touches and output etc (in fact this is exactly what timebetween was attempting to do). I’m kind of working my way through the major Codea functions and haven’t yet reached tweening. It might just change my life.
(Btw, ‘snap’ is a children’s card game where you shout “snap” when you see a pair. Apologies for the confusion - I thought it was one of those cultural universals like Connect 4!)
And thanks too @Ignatz - I never thought to put the whole condition in touched. This is something that I’m still a little confused about when coding my own stuff from scratch, and has led me back to your book on more than one occasion!
I’m a bit ill at the moment so will engage with all the code posted when I can concentrate a bit better but thanks again all. As an ex-academic myself, I’m also quite interested in the other discussion taking place…
Ok, so I’ve finally felt well enough to give this some attention and, although it’s just a simple game, I’d really like to get the principals sorted in my own head. The idea of setup-draw-touched mirroring Apple’s principal of model-view-controller makes a lot of sense. In which case, does that mean that best practice is to put all potential touch conditions in the touched function regardless of game state (eg settings, game playing, intro etc)? If so, does that mean I store every touch in a different variable using a different condition and then just use that variable in the draw function if needed? Happy for anyone to weigh in on this one… I’m almost there!
@ScottDafydd the way I do it is create a table in setup called touches, then make a touch state began if statement at the start then insert the touch in to table touches inside that statement, in the middle have something like this:
for k,v in pairs(touches) do
if v.id == t.id then
touches[k] = v
if v.state == ENDED then
table.remove(touches,k)
end
end
end
This will update each touch inside touches with the corresponding touch ID and remove them on touch end.
With this you can do the same loop in draw like so
for k,v in pairs(touches) do
ellipse(v.x,v.y,vec2(v.deltaX,v.deltaY):len()+20)
end
This will make circles at each touch point that get bigger with faster movement.
If you create a Touch class (a table works too) which holds all the attributes as a touch does (.x, .y, .deltaX, .deltaY, .prevX etc) then you can manipulate these attributes using code as well, for example scaling touches according to zooming and panning requires this.
Also in my app I use a lot of what I take out of touch and use it in the draw function, it is needed in a lot of cases. But you will need all things that require touch no matter what state in a touch function, but if you use a state machine it will only load these individual functions instead of running through them all and trying to pick out touches from multiple states.
Hi @Luatee, thanks so much for this. Very helpful. And apologies for not replying sooner. My health is not great at the moment and I find I need a lot of concentration to read even the simplest code.
Effectively, you’re storing the touches in a table which has been set up in setup and then removing when the touch ended. Think I get it. I take it this still needs linked up somehow with what goes on in the touched function and then any responding action drawn out I the draw function right?
I’m still not clear as to what or how to use the pairs statement. Is there an easy way to understand it that also explains why the letters k and v are always involved?
@ScottDafydd - The pairs “for” loop simply loops through all the items in a table. Every item is a pair consisting of a key and a value. The key is used to look up the value.
In a sequential table like t[1], t[2] etc, the numbers 1,2,3 are the keys, and you can do a for loop like “for i=1,#t do”
However, if you store named values in your table, as in t={a=3,b=4,…etc}, then the letters a,b etc are the keys. How do you loop through a table with named keys rather than number keys?
The answer is pairs. This method loops through every item in the table - in no particular order! - and gives you two values for each one - surprise, surprise, they are the key and the value - hence the usual choice of k and v.
so “for k,v in pairs(t) do” loops through all items in table t, and gives you the key and value for each, to do with as you wish.
@Ignatz - ahh, I think the fog is lifting. It’s amazing how many times you have to read the same thing again and again in different ways until you get it! So K and V are used for Key and Value. Makes sense. Which I guess is why in ipairs, I and v are used - I meaning integer right? Tables and pairs seem so important I really want to get this cracked… Thanks everyone for helping me!