I have some sprites falling from the point A to B with ease. The code:
id move = [CCMoveTo actionWithDuration:time position:new_position];
id move_ease_in = [CCEaseIn actionWithAction:[[move copy] autorelease] rate:ratio];
[sprite runAction:move_ease_in];
When someone taps on the screen, the sprite has to keep falling to the point C, that is below B. The sprites have to keep falling without stopping and falling again. How can I do that? Thanks.
Try CCMoveBy, and add the amount of want them to move each time.
(Note that depending on the version of cocos2d that you're using, you may encounter a jerky behavior. If that is the case, check the cocos2d method definition for the move methods and comment out the flag there that has a comment "bug fix" preceding it. )
Related
I've come across a problem to which the simplest solution would be to extend the length of a UIGestureRecognizer. What I mean is that I need the iOS device to still believe the user has their finger on the screen for about 0.1 seconds after they release it. I need the device to think that the finger is in the exact same position for the 0.1 seconds as it was when the user released this.
Any help as to weather this is possible would be greatly appreciated!
Thank you!!!
EDIT:
Sorry for the late reply, I've been really busy with work.
To elaborate, I'm using a set of classes made by Alan Quartermain called AQGridView. It's a class that strongly resembles UITableView; however, it displays data in a grid instead of a list. There appears to be a bug where (if I understand correctly, and I may very well not) the data of the grid is reloaded before the delegate method, that is called when a user ends a UIGestureRecognizer, finishes if the user releases their finger while dragging a cell (from one grid index to another) very quickly. This causes a graphical glitch (which can be recreated in the springboard example that comes with the class set) where the dragging cell appears to settle one cell before or after it's appropriate location, and then quickly jumps to it's proper location. I believe this is because there is a brief period, when the user releases their finger, where the grids count is -1 of what it is when the cell settles.
This is a poor explanation of the problem, but the best I could come up with. As well, I'm a relatively new developer and could be way off on the cause of the problem. That is why I believe the most appropriate fix would be to extend the gesture length by a very small amount. If anyone wants to take a look at the AQGridView classes (https://github.com/AlanQuatermain/AQGridView/) I would really appreciate it! But if possible a simpler fix would just be to simulate the touch that the user inputed right before they released their finger so that the desired animation occurs.
Inside touchesEnded delegate method, start timer for 0.1 second and perform your selector.
You can even, subclass UIGestureRecogniser and implement your own gestures, Check the first answer of this question.
See : custom iOS gesture
The question is simple but extremely complicated: in UIResponder there are 4 methods for handling touches.
- touchesEnded:withEvent:event
– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesCancelled:withEvent:
How do I detect if a touch stopped on the screen?
The problem is that I have to detect if something moved under a stationary touch (not cancelled or ended. It just doesn't move) And because it doesn't move, none of these methods gets called.
My idea was this:
I could add the touches to a NSMutableArray but then I'd have to update it for any touch move (and that's a lot). Also this creates more problems, I need to detect which of the touches stopped and if any ended. And because I get an NSSet from UIResponder, I don't have an organized array so... all kinds of problems.
I'm waiting for ideas.
i fixed it..and also found out something really cool about UITouch
what i did: in
– touchesBegan:withEvent:
for(UITouch*touch in touches){
[touchesSet addObject:touch]; } //touchesSet is a set that i store all the touches on the screen
in
- touchesEnded:withEvent:
for(UITouch*touch in touches){
[touchesSet removeObject:touch]; }
in
– touchesCancelled:withEvent:
[touchesSet removeAllObjects];
doing this i have a NSSet of all the touches on the screen at any given time, with position and UITouchPhase
The solution depends a little upon what you're trying to do (and you don't really describe what business problem or user experience you're going for). But assuming you're just trying to detect when a continuous gesture paused but hadn't been completed:
You could have touchesMoved keep track of where and when it was last invoked. E.g. if you have a subclassed gesture recognizer, give it a property of CGPoint lastLocation or something like that which you could inquire upon.
You could then setup a NSTimer that would be triggered a certain amount of time later, which would test for your "stopped" condition. E.g. if your NSTimer is called every 0.1 seconds and you're waiting for no change in location for, say 1 second, then that would qualify as a stopped condition.
And if you're looking to see if "something moved under a stationary touch", you could add this to your NSTimer routine.
im trying to make my sprite blink, but it just disappears, i have searched google, but i cant find a solution, heres what im doing:
CCBlink * blinker = [CCBlink actionWithDuration: 0.5 blinks: 1];
[player runAction: blinker];
this method is called when two of my sprites collide, when the collision takes place, i want the 'player' sprite to blink for a few seconds. at the moment, when the sprites collide, the 'player' sprite becomes invisible....thanks
CCBlink seems to work by toggling the visibility of your sprite on and off a given number of times within the stated duration you gave it. Depending on the duration you set, you might sometimes end up with an "off" visibility state at the end of the action (very buggy yeah, I had that too before), which isn't quite desired.
Two suggestions:
(1) Play around with the number of blinks.
(2) Always force the sprite to be visible at the end of the blink:
Add: [CCShow action] to the end of your blink action. You can string both actions into a CCSequence.
Verify that when (and where) you process 'onCollision' types of events you do not remove the sprite from its parent.
Blink action is buggy. I always use the following to guarantee that the object remains visible at the end of the animation:
Sequence* action = Sequence::create(Blink::create(BLINK_DURATION, BLINK_TIMES), Show::create(), NULL);
Greetings! I'm attempting to use MKMapView without any Apple code samples, though there are a few others out there of varying clarity. (I know, "Read the friendly manual." I've done that but it's not 100% clear, so please bear with me on this one.)
Here's the situation. I have a MKMapView object, wherein I have added a set of about ten MKPinAnnotation objects. So far, so good. Everything is alloced/released sanely and there doesn't appear to be any complaints from Instruments.
Upon initial display, I set up a MKCoordinateRegion object with the centerpoint at our first pin location, and a (arbitrary) span of 0.2 x 0.2. I then call:
[mapView setRegion:region animated:YES];
[mapView regionThatFits:region];
Wow! That worked well.
Meanwhile ... I also have a segmented control to allow for movement to each pin location. So as I tap through the list, the map animates to each new pin location with a new pair of calls to setRegion:animated: and regionThatFits: ... or at least that's the idea.
While the map does "travel" to the new pin location, the map itself doesn't update underneath. Instead, I see my pin on a gray/blank-map background ... until I nudge the map in any direction, however slightly. Then the map shows through! (If I'm only moving within a short distance of the previous pin location, I'll usually see whatever part of the map was already loaded.)
I suspect I'm doing something dumb here, but I haven't been able to figure out what, at least not from the MapKit docs. Perhaps I'm using the wrong calls? (Well, I do need to set the region at least once, yes? Moving that around doesn't seem to help though.) I have also tried using setCenterCoordinate:animated: - same problem.
I'm assuming nothing at this point (no pun intended). Just trying to find my way.
Clues welcome/appreciated!
UPDATE: Calling setRegion:animated: and regionThatFits: the first time, followed by setCenterCoordinate:animated: while traversing the list, has no effect. Interesting finding though: If I change animated to NO in both cases, the map updates!!! Only when it's set to YES. (Wha happen?! Is animated: broken? That can't be ... ???)
It turns out that the map update doesn't work when using the SIMULATOR. When I try setCenterCoordinate:animated: on the device, I do get the map update underneath.
Bottom line: I was trusting the simulator to match the device in terms of map updating behavior. Alas, I was mistaken! Lesson learned. "Don't let this happen to you." :)
You need to invoke the setRegion:animated: call in the Main thread context.
Just do something like:
....
[self performSelectorOnMainThread:#selector(updateMyMap) withObject:nil waitUntilDone:NO];
}
-(void) updateMyMap {
[myMap setRegion:myRegion animated:YES];
}
and it should work in any case (animated or not), with the map updated underneath.
Hum strange. The map updates on my Mac even in the simulator. Maybe a network setting (proxy or whatever) that would prevent the map widget to download the tiles on the simulator ?
Even though this is an old topic I thought I'd ring in with my experience. It seems the map animation only fails on devices running iOS 3.1.x and the simulator running 3.1.x. My dev iPod touch with 3.1.3 fails to zoom if animation is on.
I have a NSArray of UIImageViews that I want to loop over and quickly swap out an "on" and "off" state. I wrote the code to do so in a for loop instead a method that was called when the user tapped a UIButton ( the button's action ).
Here's that loop:
for(int i = 0; i < [Images count]; i++) {
if( i > 0 ){
[self toggleImageViewOff:[Images objectAtIndex:i - 1]];
}
[self toggleImageViewOn:[Images objectAtIndex:i]];
[NSThread sleepForTimeInterval:0.5f];
}
The UI did not update as I expected as I only ever saw the last UIImageView in the "on" state. I figured that the drawing update of the views must occur in the main thread this code was also executing in. So I learned about performSelectorInBackground:withObject: . Performing the toggleImageViewOn/Off methods using this made the loop work. The problem is if I make the sleep interval too short I can have an "on" update after an "off" with Threads operating out of order.
So I had the bright idea of moving the whole loop with the sleep into its own method and calling that from the action method using performSelectorInBackground:withObject: . I tried that and I'm back to not getting an updated view until the loop is over.
That's a long winded way to get to my question:
What's the best way to animate this to guarantee the on/off code fires in the right order and still get view updates, even at high speeds? ( i.e. looping very quickly )
I tried to think about how I'd do it with CoreAnimation, but I can't seem to get my head around how to do it there.
For bonus, here are the toggle methods:
- (void)toggleImageViewOn:(UIImageView *)theImageView {
[theImageView setImage:[UIImage imageNamed:#"on.png"]];
}
- (void)toggleImageViewOff:(UIImageView *)theImageView {
[theImageView setImage:[UIImage imageNamed:#"off.png"]];
}
Did you set up an animation context (UIView class method does that) around this for loop? Without it changes are immediate instead of animated.
The problem is that you are not giving any of the UIImages time to draw. The drawing code is optimised to only draw what's needed - rendering all those intermediate stages is optimised out.
Sleeping the main thread doesn't actually give it chance to run.
Bill is right in that you need to set up an animation context around your loop. This will capture all of the UIView changes you make and then play them out. The easiest way to do this is using Core Animation. Core animation 'records' changes in UIElemenets and plays them back. Your code (without the sleep) will work just fine in a Core Animation block.
Apple have a reasonable cookbook for Core Animation on their site
You're on the right track with moving the loop to a background thread, but you also need to make sure that you give the main run loop a chance to update the UI. You should be able to replace the direct calls to toggleImageViewOn: and toggleImageViewOff: with something like
[self performSelectorOnMainThread:#selector(toggleImageViewOn:) withObject:[Images objectAtIndex:i] waitUntilDone:NO];
This will do the UI update on the main thread, and by not waiting until the update is done you give the main run loop a chance to reach its end. You run into the same issue with things like progress bars, where they won't change until the loop ends unless you do your updates from a background thread with a UI update call like the one above.
Hey Patrick. Have a look at UIImageView's animationImages property, as well as the animationRepeatCount and animationDuration properties. If you put your on/off images into an array and assign that as the animationImages property, you should be able to control the repeat and duration to get the desired effect.
Hope that helps!
Thanks for that. I've already looked into UIIMageView's animationImages property. That's not exactly what I'm attempting to do. I'm cycling between several UIImageView's that are placed near each other to give the impression that a light is moving between them and cycling over them. So an individual UIImageView's animation is separate from each other as I need to swap the image as necessary in code.
Calling peformSelectorOnMainThread:withObject:waitUntilDone: from the loop on the background thread does indeed update the view as quickly as I can think I will ever need. I'm curious why I need to do the UIImageView swap on the Main thread? Why wouldn't changing it on the background thread and then using NSThread's sleepForTimeInterval allow the main thread to update the drawing anyway?
I guess I need to go read up on the run loop and where drawing updates occur.
Thanks so much for the help. ( I'm also going to try some additional suggestions from Bill Dudney, that I think will work based on CoreAnimation )