I am new to Codea. I am trying to use Codea to write a simple game for my kids.
I have some words appear on the screen, and the kid gets to drag the words around by touching the screen.
If the kid touches a word, the word follows the kid’s finger around until the kid lifts her finger up.
Everything usually works, … except sometimes it doesn’t work.
As far as I can tell, the problem is that sometimes when my kid lifts her finger,
a touch with state ENDED isn’t created. I can always recreate the problem with
a multi-touch gesture, but sometimes the problem happens when there’s no multi-touch.
Sorry I don’t know how to get code out of Codea yet.
You can see something similar in the example app Anagrams that came with Codea.
Normally when you place a finger on a letter the letter turns red,
then when you lift the finger, the letter turns white again.
However, try this:
Touch a letter and keep a finger on it.
That letter will turn red.
Place a second finger on a different letter.
That second letter will not turn red.
You now have two fingers touching the screen.
Now, lift the first finger that is on the red letter.
Notice that the letter remains red.
Now lift the second finger.
Why doesn’t the first letter turn white when you lift the finger?
Aha! Welcome to the magical world of CurrentTouch! CurrentTouch is a variable which holds a touch datatype, but, CurrentTouch is the simplified version of a much more powerful tool… the touched(touch) function! By putting this function in your code, you can do so much more. It is a function that is automatically called by Codea when a finger is touching the screen. It can be called multiple times for multiple fingers. CurrentTouch is the last item passed to touched(touch) that frame. For a better understanding of this, go look at the Handling Touches and Multi Touch examples.
What is happening in your code is =
###1
Your code is getting a BEGAN event from CurrentTouch
###2
Your code is getting another BEGAN event (but maybe it was MOVING on the first touch), note that CurrentTouch.state is still BEGAN
###3
Your code is getting an ENDED state
###4
CurrentTouch.state is still ENDED, no way to determine if it is a separate touch unless you use the touched(touch) function
I am not using the variable CurrentTouch. I am using touch data types and the touched(touch) function. The Anagrams example also does not use CurrentTouch. So, I think the issue must be something else.
Thank you for taking the time to respond to my question.
I use touch.id. The Anagrams example that comes with Codea also uses touch.id. I think that my problem is the same one as appears in the Anagrams example.
Here’s another way to reproduce the issue in the Anagrams game. I start the game. then I do a four finger gesture as if I were switching apps, but I don’t compele the switch and go back to the game. The Anagrams game no longer responds to touches.
My game works 98% of the time. However, the weird instances when it doesn’t work really frustrate my kids when they are trying to play the game.
The Anagrams issue is subtle. Well spotted! I’ll have to update that. The problem in the Anagram code is that the test for a touch ending is only carried out if the Anagram object has a single touch. So if you touch it again before the first touch ends, the Anagram object never notices the ended touch because its gesture has two touches (in my code, touches can have an effect beyond their lifetime if their containing gesture is still alive).
The four finger thing is because Codea doesn’t get the signal that the touches have ended because the OS claims the touches once the multitasking gesture is recognised. In later versions of my code I’ve put in a “reset touches” button to compensate for this - I know of no way to guard against it other than to switch off these gestures.
But I don’t know if these relate to your issue without seeing the code. Can you cut-and-paste it here?
Andrew – thanks for spotting my question. I actually tried using your Touch handler class in one version of my game. (I copied it from the Anagram game. I hope that’s okay.) When I had problems, I tried making a much simpler touch handler but that didn’t solve the problems. (One problem was that while I could add a new handler using that controller, I couldn’t remove a handler. Eventually the list of handlers got really big and included mostly handlers that were no longer needed. At that point the touches in the game started behaving erratically.)
Taking into account my problem with removing handlers, and the two issues you explain in your post, I have some ideas on how to proceed.
Interesting idea on removing handlers. That could certainly be added - I just haven’t had the need for it as yet so hadn’t considered it.
By the way, you can get more recent versions of my code from my website: http://www.math.ntnu.no/~stacey/code/CodeaLibrary (all my code is PD where I can make it such - a couple of things are based on other code so inherit their licences). The touch handler hasn’t changed much, but it now allows an object to register a table as a handler which it can then change during the program. I use this now in the UI: the UI registers a table and then shuffles things around according to which UI element is in the foreground. This might help you a little. I also wrote an introduction to my Touch handler class which might be useful (or might not): http://loopspace.mathforge.org and follow the links to Codea.
The other thing that I do is that most of my isTouchedBy routines start with:
if not self.active then
return false
end
so that each object can effectively remove itself from consideration.
Thank you so much for your helping out this noobie!
With your advice I was able to figure out what was happening and fixed my touch handler. My touch handler is far simpler than yours, and I understand it, so I think that I will go with mine for now, as I don’t need the extra functionality that yours has.
I also added a bit to generate fake ended touches to take care of the situation with no ENDED touches due to the OS capturing the touches.
My touch handler is far simpler than yours, and I understand it, so I think that I will go with mine for now, as I don’t need the extra functionality that yours has.
That fits in very much with my own experiences in programming: if I didn’t write it, I don’t understand it, and if I don’t understand it, I can’t use it (to its full potential).
Mind you, I’m not adverse to stealling – I mean, sharing – others’ ideas and experiences. Is there anything you particularly like about your handler that might be useful for mine? I like the “remove handler” idea, anything else? How do you determine when to generate the fake ended touches?
Thanks. My handler is far simpler than yours, so I doubt anything in it would be useful for yours (other than a remove handler, and mayby some more documentation)
I’m glad that you like the idea of a removeHandler idea.
I generate the fake ended touches when there is no new touch for a given touch.id after 10 seconds. I figure that it is highly unusual for a person to keep a finger completely still (not generating even tiny MOVING touches) for that long. I tried holding my finger completely still and was unable to do it for longer than about 5 seconds without generating a MOVING touch.
I have a theory for why in some cases (particularly the case of having iOS gestures turned on) we don’t get the ENDED event. I took a look at the runtime, and in BasicRendererViewController.mm, in the touchesCancelled:withEvent: method (which is the method that should get called whenever iOS cancels a touch for any reason, such as a gesture being detected), the current touch’s state gets set to TOUCH_STATE_INACTIVE. Also, touchesCancelled:withEvent: calls the Lua state’s callTouchFunction:inView: method which sets the state of each current touch to TOUCH_STATE_INACTIVE.
I could be wrong, but from the Lua side, I’m pretty sure this would cause these touches to get “lost”. I’m thinking that either a) Codea’s touch objects should have an awareness of this situation, and a state for when touches are cancelled (TOUCH_STATE_CANCELLED, CANCELLED inside Codea), or b) Codea should set the state of these cancelled touches to TOUCH_STATE_ENDED (ENDED in Codea). Either way should allow us to gracefully recover from iOS “stealing” our touches without the need for hacks.
Andrew – I thought of another possible feature for your touch handler. How about when you ask a handler if it is touched, it can say yes, but direct the touch (and the rest of the gesture) to a different object. For example, suppose in a game you touch a sprite and it creates a copy of itself that you can drag around. I don’t need this functionality, but I think it would be easy to add while keeping the file backward compatible.
This might be covered by the newish functionality where an object can register a table of handlers instead of just a single handler. Then it can add or remove things to the handler dynamically (and they stay in the same place in the list).
I’m thinking about how best for something to remove a handler. I guess performance probably isn’t a major issue here so doing the obvious iteration through the list and removing the one that matches is simplest.
.@toadkick I think I’d go for an explicit “Cancelled” state (something is nagging me, I have a vague memory of this discussion before). If a touch (or series of touches) is claimed by the iOS then that’s different to them just ending and the application probably would want to take different actions under the circumstances.