Trouble toggling the userInteractionEnabled property in iOS - ios

I am developing a tic tac toe game for iOS and I am using a combination of UIButtons and UIImageViews to allow for user interaction and to display the moves made. My problem is that the buttons continue to accept user input before the cpu makes it's move, which breaks my game logic. I have made several attempts to toggle the userInteractionEnabled property, but I have only been able to turn it off. The engine that gets everything started in the game is my buttonPressed method. I also toggle the userInteractionEnabled property within this method and therein lies my problem: How do I re-enable the property after disabling user interaction? Is there a method that is called in between events that I can overwrite?
I have searched the web and I have searched through the developer documentation provided by Apple and I found information on the touchesBegan and touchesEnded methods. However, from what I understand, those methods need to be explicitly called which brings me back to my original problem of not being able to call those functions without the user's interaction.
If anyone can help, I would greatly appreciate it! I have been racking my brain over this for the past couple of weeks and I am just not seeing a solution.

I'd think that for a game like tic-tac-toe, calculating the countermove should be so fast that it can be done immediately in response to the first button press. If you're doing something complicated to calculate the next move, like kicking off a thread, you might want to reconsider that.
Let's say, though, that your game is something like chess or go, where coming up with a countermove might take a bit longer. Your view controller should have a method to make a move for the current player, let's call it -makeMove:. Your -buttonPressed action should call that method to make a move for the user. In response, -makeMove: should update the state of the game, switch the current player to the next player. If the new current player is the computer, it should then disable the controls and start the process of calculating the next move. Let's imagine that's done by invoking some NSOperation, so that coming up with the next move is an asynchronous task. Once the operation has come up with a move, it should again invoke -makeMove: (by calling -performSelectorOnMainThread:), which will again update the game state and the current player. This time, though, it should see that the new current player is not the computer, and so it should re-enable the controls.

Related

How iOS handles events that occurs just right before the background?

First of all I'd like to say sorry in case my question is dummy, I'm really new to iOS and what to understand how thing are going on. Imagine such a situation - user taps on home button and the app starts to collapse, but immediately after taping on home button user taped on some UI element. So, I'm wondering how the iOS will handle this? I tried to do some tests using breakpoints, but since it just test I can't be 100% sure. It seems that if the UI interaction event will happen before the system will call willResignActive then the event will be fully processed and if the system will call willResignActive first, then the even will be discarded and won't be handled at all. Is this correct, or I missed something? Thanks
First, why do you want to use this in your app? If a user presses a button exactly in this time, it's okay that the action is not handled.
The only thing you have to keep track of is that whenever the button gets pressed and let's say you store a file without a completion handler it could be that you present an alert which is saying that everything went well but you actually not saved the file because the user left the app in this time.
But since you're never doing critical actions without completion handlers, in my opinion, there's no need to make sure that this doesn't happen.
If I got you wrong, just comment!

Game programming in Xcode and Sprite-builder. Display while computer "thinks"

I am working on an app for a physical boardgames I have produced in the past. Everything is working fine (for now). But the app "freezes up" when the code for the computer "thinking" kicks in.
This is understandable, the computer needs time to make it's turn.
My question is. Is there any way I can simultaneously set an animation to run (like a progress icon), while the computer continues to "think" over it's turn?
Thank You.
You can't make something like a progress bar which indicates exactly when the computer will finish 'thinking' exactly because the computer does not know when it will be done.
However, you can create an animation that will run as long as the computer 'thinks'.
In your Gameplay file in Spritebuilder, create the animation that you want shown while the user waits. Chain this animation timeline to itself. Let's call the default timeline animation 'default' and the 'computer is thinking' timeline animation 'think'.
Inside the method you use to start the computer's turn, add a line of code that warns cocos2d to run the 'think' animation sequence; it would also be good to make any user interaction with the game impossible at this time (example below is given in Swift):
animationManager.runAnimationsForSequenceNamed("think")
self.userInteractionEnabled = false
Since the 'think' timeline was chained to itself, it will run in an infinite loop, only stopping once cocos2d receives an instruction to break that timeline and start executing another one, so, just inside the method you execute once the computer's turn is over, add these two lines in order to stop the 'think' animation from running and to enable user interaction once again:
animationManager.runAnimationsForSequenceNamed("default")
self.userInteractionEnabled = true
Not knowing where you are building your actual game in, using different threads is the way to go. What are you building your game in? Which language, framework, platform?

Getting touches at launch on iOS

On Mac, one can always get the location of the mouse "outside the event stream" (ie, even if you've not subscribed to any delegate methods for mouseUp: et al) by calling [NSEvent mouseLocation].
Is there any way on iOS to get current touch events without listening to touchesBegan:?
I ask because there is at least one situation in which touchesBegan is not called: at app launch, if a touch is already in progress, touchesBegan is never called. In fact, neither are any of the touch-related UIEvent methods called as near as I can tell (nor UIApplication's / UIWindow's sendEvent:, apparently).
I would like to vary the behavior of my app slightly based on whether a touch is in progress at launch. Is there any way to detect an in-progress touch at app launch?
This cannot be done. The simple reason: The touch events don't belong to your app. Each touch belongs to some UI element (or responder). As you already know, this element gets the began, moved, ended, cancelled messages.
This is even true within a properly programmed app: All events regarding one touch are delivered to the very same object. After all, how would another object know what to do with that event, and how should the first object properly finish its expected behavior?
While you can (or could, but probably shouldn't) find a work around within your app, there's just no way for cross-app-touch passings.
And on the Mac you may query the mouse position, but in normal application flow there'll always be a mouse down before you get a mouse up event.
To be honest, I don't see any reason why this would be needed anyway... oh wait... I could split my app icon into several areas... not sure if it would already break privacy laws, though, if you get to know where the user has his icon on screen.
I think you could simply "extend" the application launch. When I had time consuming tasks during my application launch, I used to show the same splash screen with a UIActivityIndicator while the action was being carried out.
You could simply create a NSTimer, wait for about 2 seconds and during this time, check for touches, while the splash screen will still be showing.
To do this, in applicationDidFinishLaunch, push a ViewController that looks exactaly like the splash screen and check for touches in this ViewController. After those 2 seconds, proceed with normal initialisation. This behaviour also helps if you have time consuming tasks during initialisation.
I know, it`s a workaround, but my guess, is that it is not possible to check for touches because application will be working on the main thread and the touches also processes on the main thread. This could happen also because there are no ViewControllers or UIWindow initialised and ready to listen to touches.
Hope it helps.
You might try handling the hitTest:withEvent: instead.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
Since according to apple doc "Returns the farthest descendant of the receiver in the view hierarchy (including itself) that contains a specified point."

Macro Recording in iOS

Is it possible to record set of touch events on iPhone and then playback?
I have searched alot but could not find any answer. if its possible, can anyone explain with an example.
I m not looking for testing purpose. Within my application, instead of creating animation, i just want to record set of events and then want to playback to explain the app flow to the users.
Regards.
Recording is pretty simple. Look at the various "Responding to Touch Events" and "Responding to Motion Events" methods on UIResponder. Just create your own UIView subclass (since UIView inherits from UIResponder) and keep a copy of the events passed into the relevant methods.
Playback is a bit more complicated; there's no way to make UITouch or UIEvent objects (so you can't make a fake event and pass it on to -[UIApplication sendEvent:]). But, there's nothing stopping you from manually parsing an array of Event objects and handling it on your own (aside from it being some kind of ugly code).
There's no built-in macro capability, but you could certainly build that ability into your application. You'll need to do more than just play back events, though. Touches aren't normally visible, but if you're trying to explain how to use your app to the user you'll probably want to have some sort of visual representation for the touches that trigger different responses similar to the way the iOS Simulator uses white dots to represent multiple touches when you hold down the option key.
Assuming that you can solve that problem, two strategies for easily recording user actions come to mind:
Use the Undo Manager: NSUndoManager is already set up to "record" undoable events. If you invest some time into making everything in your app undoable, you could (maybe) perform a set of actions, undo them all to move them to the redo stack, and then save the events in the redo stack as your script.
Use Accessibility: The Accessibility framework sends notifications whenever user interface elements are touched. Your app could use those notifications to create a playback script. You'll still need to write the code to play back the events in the script, though.
You could mirror your application with AirServer and use any screen capture software to make the video.

Why are my iPad touch events being delayed (sometimes up to a second)?

I'm working on a game, and I'm using a CAEAGLLayer backed UIView subclass to present the game engine. Touch handling is done using -touchesBegan:withEvent: et. al.
Everything works fine, except that very rarely, if one of the on-screen controls is tapped rapidly, -touchesBegan:withEvent: doesn't get called for somewhere between 0.1 and 1-2 seconds. This happens maybe one in 20 times, and only if you tap the screen rapidly (4-5 times) first. It seems to be more likely to happen if I am also holding down another finger on a different control on the screen.
Thinking that it was something to do with my own code, I subclassed UIApplication so I could add a logging statement to -sendEvent:. When the laggy touch happens, -sendEvent: doesn't get called until some period of time after the touch has started, so it the touch handling code inside my UIView subclass doesn't appear to be at fault.
Does anyone have any idea what's going on here (other than iOS having some obscure bug)? Is there some sort of internal "events queue" that makes event delivery become laggy when it fills up? Has anyone else experienced this?
Touch events are only dispatched in the main UI run loop, and sometimes only when the main run loop goes idle for a bit. So if your app is busy handling several previous touch events in a row without taking a break, the main UI run loop might be saturated, and thus not get any further touch events until done with the current stuff.
Touch events also have time stamps. So you can check if they're coming too fast (faster than your event handlers and resulting UI updates can run), and skip or combine some of the event handlers, as appropriate for your app, if you want the app to stay maximally responsive.

Resources