I am trying to make a game movement animation in objective c so that when a button is pressed something will move across the screen while it is pressed. This works fine though the calling of the NSTimer which I am using is irregular and I am getting laggy movements. This is in iOS 6 so I wont use sprite kit as it is not available
Any suggestions on how to make it a regular call or to make it a smooth animation would be much appreciated
Thanks in advance
Here is the code:
-(void) click {
if (!self.animating) {
self.animating = YES;
timer = [NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:#selector(move)
userInfo:nil
repeats:YES];
}
}
- (void) cancelClick {
self.animating = NO;
[timer invalidate];
}
-(void) move {
CGPoint origin = self.target.frame.origin;
if ([self.direction isEqual:#"left"]) {
origin.x -= self.magnitude;
} else if ([self.direction isEqual:#"right"]) {
origin.x += _magnitude;
} else if ([self.direction isEqual:#"up"]) {
origin.y -= _magnitude;
} else {
origin.y += _magnitude;
}
[self.target move:0 toPoint:origin animated:YES delay:0 animationOptions:UIViewAnimationOptionCurveLinear];
}
Related
So, I've been working for hours trying to fix this, and I think It might just be missing something so obvious.
What Im trying to do is have an animation of a line (like a clock second hand) rotating around clockwise, but when the screen is pressed, it stops, but then when pressed again it starts again but the rotation reverses and the line starts rotating anticlockwise...
This is the code I used to rotate the line about a fixed point, and it works:
- (void) spinWithOptions: (UIViewAnimationOptions) options {
[UIView animateWithDuration: 0.0f
delay: 0.0f
options: options
animations: ^{
Hand.layer.anchorPoint = CGPointMake(0.5,1);
Hand.transform = CGAffineTransformRotate(Hand.transform, M_PI / 40);
}
completion: ^(BOOL finished) {
if (finished) {
if (animating) {
// if flag still set, keep spinning with constant speed
[self spinWithOptions: UIViewAnimationOptionCurveLinear];
} else if (options != UIViewAnimationOptionCurveEaseOut) {
// one last spin, with deceleration
//[self spinWithOptions: UIViewAnimationOptionCurveEaseOut];
}
}
}];
}
- (void) startSpin {
if (!animating) {
animating = YES;
[self spinWithOptions: UIViewAnimationOptionCurveEaseIn];
Clockwise = NO;
}
}
- (void) spinWithOptions_Anti: (UIViewAnimationOptions) options {
[UIView animateWithDuration: 0.0f
delay: 0.0f
options: options
animations: ^{
Hand.layer.anchorPoint = CGPointMake(0.5,1);
Hand.transform = CGAffineTransformRotate(Hand.transform, -M_PI / 40);
}
completion: ^(BOOL finished) {
if (finished) {
if (animating) {
// if flag still set, keep spinning with constant speed
[self spinWithOptions: UIViewAnimationOptionCurveLinear];
} else if (options != UIViewAnimationOptionCurveEaseOut) {
// one last spin, with deceleration
//[self spinWithOptions: UIViewAnimationOptionCurveEaseOut];
}
}
}];
}
- (void) startSpin_Anti {
if (!animating) {
animating = YES;
[self spinWithOptions_Anti: UIViewAnimationOptionCurveEaseIn];
Clockwise = YES;
}
}
- (void) stopSpin {
animating = NO;
}
So at the start of the application, the line begins rotating clockwise, when the ViewDidload calls startSpin, which calls spinWithOptions...
Sure enough, if I press the screen, the rotation animation stops, with this...
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event{
NSLog(#"Dircetion: %i", Clockwise);
if(animating){
[self stopSpin];
}
else{
if(Clockwise){
[self startSpin];
NSLog(#"must be clockwise");
}
else{
[self startSpin_Anti];
NSLog(#"anti");
}
}
}
But when pressed again it starts rotating as It should but never changes direction... it only ever rotates clockwise...
I just can't seem to see why it won't change direction... even the NSLogs say the bool of Clockwise is correct...
I have a UIImageView rotating forever on my screen... I use the code below, which I found HERE:
- (void) spinWithOptions: (UIViewAnimationOptions) options {
[UIView animateWithDuration: 0.0f
delay: 0.0f
options: options
animations: ^{
Hand.transform = CGAffineTransformRotate(Hand.transform, M_PI / 30);
}
completion: ^(BOOL finished) {
if (finished) {
if (animating) { //if, keep spinning
[self spinWithOptions: UIViewAnimationOptionCurveLinear];
} else if (options != UIViewAnimationOptionCurveEaseOut) { //final spin
//[self spinWithOptions: UIViewAnimationOptionCurveEaseOut];
}
}
}];
}
- (void) startSpin {
if (!animating) {
animating = YES;
[self spinWithOptions: UIViewAnimationOptionCurveEaseIn];
}
}
- (void) stopSpin {
animating = NO;
}
It worked find and the rotation seems smooth...
I've since added a countdown timer, using the follow:
-(void)timerTick:(NSTimer *)timer{
ticks -= 0.1; //NSLog(#"Total Ticks: %.2f",ticks);
if(ticks < 0.0){ //3 seconds is up
Failed.image = [UIImage imageNamed:#"Failed.png"];
ticks = 0.0;
[self GameOver]; //out of time...
}
else {
FailedBeforeTimer.image = [UIImage imageNamed:#"Failed Before.png"];
}
CountDownTimer.text = [NSString stringWithFormat:#"%.1f",ticks];
}
-(void)startTimer{
ticks = 3.0;
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(timerTick:) userInfo:nil repeats:YES];
}
-(void)stopTimer{
[timer invalidate];
ticks = 0.0;
}
Since adding this timer to my app, the rotation animation is really blocky and no longer a smooth rotation...
Any ideas what I should implement to solve this?
To check, I removed the timer and re-run the application, and sure enough, the animation was smooth again :(
UPDATE:
After some more trial and error, it seems to be this line of code that slows the process down: CountDownTimer.text = [NSString stringWithFormat:#"%.1f",ticks]; ie. When I don't display the countDownTimer text on the screen/update label on screen), the rotation is smooth still...
So confused... What can I do?
Animating with zero-duration animations does not make sense. That's not how UIView animation is supposed to work. My guess is that is the source of your problems. A zero duration animation will be jumpy by definition.
You should be animating your changes over some time-period. (Always use a non-zero duration.)
EDIT:
Note that your timerTick method is horribly inefficient. You load the same image into an image view on every tick. Don't do that. Set it up with the initial image, and then only change the image when your tick count reaches zero.
You should give CADisplayLink a try, it should be suitable for your case. It's easy to use, there are heaps of tutorials out there, just do a search.
I want to get direction of the device motion by using accelerometer. I tried method suggested here as below :-
- (void)accelerometer:(UIAccelerometer *)acel didAccelerate:(UIAcceleration *)aceler {
if (fabsf(aceler.x) > 1.5)
{
shake = YES;
NSTimeInterval myInterval = .75;
[NSTimer scheduledTimerWithTimeInterval:myInterval target:self selector:#selector(endShake) userInfo:nil repeats:NO];
return;
}
if(shake)
{
totalG += aceler.x;
}
}
- (void) endShake {
shake = NO;
int direction;
if (totalG isLessThan 0) direction = 1;
if(totalG isGreaterThan 0) direction = -1;
[self changePageByShake:direction];
totalG = 0;
}
But it's not giving accurate results. Is there any standard way to get the direction of the device ?
Note :- This is different from orientation of the device.
I want to use NSTimer as a Countdown. The counter works fine;-)!
But I I switch to another viewController the timer doesn't runs in "foreground" - so the label isn't updated.... after coming back to this view.
My NSLOG shows that the timer is still runnig, like I want ;-)
So in whicht way I have to work, that my timer update my label?
Here is the code:
- (IBAction)startClock:(id)sender {
globalTimer = 20;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateCircularProgressBar)
userInfo:nil
repeats:YES];
}
- (void)updateCircularProgressBar
{
// Values to be passed on to Circular Progress Bar
if (globalTimer > 0 && globalTimer <= 1200) {
globalTimer--;
minutesLeft = globalTimer / 60;
secondsLeft = globalTimer % 60;
[self drawCircularProgressBarWithMinutesLeft:minutesLeft secondsLeft:secondsLeft];
NSLog(#"Time left: %02d:%02d", minutesLeft, secondsLeft);
}
else {
[self drawCircularProgressBarWithMinutesLeft:0 secondsLeft:0];
[timer invalidate];
}
}
I tested to run the "updateCircularProgressBar" in my viewDidLoad but this shows NO result...
THX for Help
UPDATE more with more Code:
/*-------------------- TIMER --------------------*/
// Draws the progress circles on top of the already painted background
- (void)drawCircularProgressBarWithMinutesLeft:(NSInteger)minutes secondsLeft:(NSInteger)seconds
{
// Removing unused view to prevent them from stacking up
for (id subView in [self.view subviews]) {
if ([subView isKindOfClass:[CircularProgressTimer class]]) {
[subView removeFromSuperview];
}
}
// Init our view and set current circular progress bar value
CGRect progressBarFrame = CGRectMake(0, 0, 180, 180);
progressTimerView = [[CircularProgressTimer alloc] initWithFrame:progressBarFrame];
[progressTimerView setCenter:CGPointMake(160, 210)];
[progressTimerView setPercent:seconds];
if (minutes == 0 && seconds <= 0) {
[progressTimerView setInstanceColor:[UIColor magentaColor]];
}
// Here, setting the minutes left before adding it to the parent view
[progressTimerView setMinutesLeft:minutesLeft];
[progressTimerView setSecondsLeft:secondsLeft];
[self.view addSubview:progressTimerView];
progressTimerView = nil;
}
The label is in another file (CircularProgressTimer) which controls the progessbar...
I have a tall UIImageView scrolling across the screen when a button is pressed. I used a timer to change the y position of the image at a specific speed. The image is 10,000px tall.
Here's my simple code:
-(void) moveImage {
myImage.center = CGPointMake(myImage.center.x, myImage.center.y +6);
}
-(IBAction)StartGame:(id)sender{
moveImageTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(moveImage)userInfo:nil repeats:YES];
[StartGame setHidden:TRUE];
}
Here's what i've tried to stop the timer when the image has scrolled completely through the screen:
-(void) moveImage {
myImage.center = CGPointMake(myImage.center.x, myImage.center.y +6);
if ([myImage == GPointMake(myImage.center.x, myImage.center.y -568) {
[moveImageTimer invalidate];
}
That doesn't work but i thought it would. Can someone tell me why the IF statement doesn't work? Any help is appreciated, thanks
Since you want to stop when the image moves to the bottom corner.
-(void) moveImage {
CGPoint newPoint= CGPointMake(myImage.center.x, myImage.center.y +6);
myImage.center = newPoint;
if ((newPoint.y - (myImage.frame.size.width/2)) >= [UIScreen mainScreen].bounds.size.height)
{
[moveImageTimer invalidate];
}
}
you can check the condition
like if (imageView.center.y > imageView.frame.size.height - self.view.frame.size.height)
here imageView.frame.size.height - self.view.frame.size.height because the image size is twice screen size. You have to set you logic
imageView.center = CGPointMake(imageView.center.x, imageView.center.y + 6);
if (imageView.center.y > imageView.frame.size.height - self.view.frame.size.height)
{
[moveImageTimer invalidate];
}
}