IPhone Ferris Wheel (Fortune)

I'm having difficulty adding dynamics to a spinning wheel.
I have this wheel (something like this ) and I rotate it around the center with a one-touch event.
There is no problem, but when the touch (aka pull) ends; I want the wheel to keep him moving and make his movement easier.

Anyone who can give me some pointers doesn't have to be in objective-c. AS3, javascript or JAVA will also suffice.

* UPDATE (code for wheel rotation) *

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { rotation = _startAngle = atan2(384 - touchPoint.y, 512 - touchPoint.x); }; -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { CGPoint touchPoint = [[touches anyObject] locationInView:self.view]; rotation = atan2(384 - touchPoint.y, 512 - touchPoint.x); rotation = fmod(rotation - _startAngle, M_PI * 2.0f); [wheel setTransform:CGAffineTransformMakeRotation(_circleRotationOffset + rotation)]; }; -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { _circleRotationOffset = fmod(_circleRotationOffset + rotation, M_PI * 2); }; 
+4
source share
3 answers

You want the momentum to decrease due to friction; friction is a force that depends on speed. So technically you have a differential equation. It is not worth investing too much thought, although a solution is probably more easily achieved by hand-waving.

So: save the current angle and current angular speed. n times per second (possibly through NSTimer or CADisplayLink ) add the angular speed to the corner, then multiply the angular speed by something to reduce it - for example, 0.995. Constants close to 1.0 will slow down for longer; if you go above 1.0 it will obviously speed up. This is actually a form of Euler integration, but again, this is not worth the worry.

It might also be worth setting the minimum maximum angular speed, so if it drops below, say, 0.01 radian / second, then you reset it to 0. This effectively slightly changes your friction model to go from kinetic to static friction to suitable moment and acts as a floating point precision buffer zone.

To get the initial speed from dragging and dropping, you can simply generate a vector from the center of the wheel to start dragging, rotate this vector 90 degrees, make a point product with this and drag and drop vector and scale according to the distance from the center.

+5
source

If you rotate a UIImageView with code like:
[UIView beginAnimations:@"rotateImage" context:nil];
[UIView setAnimationDuration:4.0];
wheelImageView.transform = CGAffineTransformMakeRotation(3.14159265*5);
[UIView commitAnimations];

You can use [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
This makes the animation start fast and slow down over time.

Click here for more information on UIViewAnimationCurve

+1
source

I managed to get good results.
How I did it, I need to adjust more, but these are the basics:

  -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { CGPoint touchPoint = [[touches anyObject] locationInView:self.view]; rotation = _startAngle = atan2(384 - touchPoint.y, 512 - touchPoint.x); [_history removeAllObjects]; }; -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { CGPoint touchPoint = [[touches anyObject] locationInView:self.view]; [_history insertObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithDouble:CFAbsoluteTimeGetCurrent()], @"time", [NSValue valueWithCGPoint:touchPoint], @"point", [NSNumber numberWithFloat: _circleRotationOffset + rotation], @"rotation", nil] atIndex:0]; if ([_history count] == 3) { [_history removeLastObject]; } rotation = atan2(384 - touchPoint.y, 512 - touchPoint.x) - _startAngle; [circleImage setTransform:CGAffineTransformMakeRotation(_circleRotationOffset + rotation)]; }; -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { CGPoint tp = [[touches anyObject] locationInView:self.view]; _circleRotationOffset += rotation; NSDictionary *lo = [_history lastObject]; CGPoint pp = [[lo objectForKey:@"point"] CGPointValue]; double timeDif = CFAbsoluteTimeGetCurrent() - [[lo objectForKey:@"time"] doubleValue]; float lastRotation = [[lo objectForKey:@"rotation"] floatValue]; // Calculate strength float dist = sqrtf(((pp.x - tp.x) * (pp.x - tp.x)) + ((pp.y - tp.y) * (pp.y - tp.y))); float strength = MIN(1.0f, dist / 80.0f) * (timeDif / .025) * M_PI; float p = _circleRotationOffset; float dif = _circleRotationOffset - lastRotation; BOOL inc = dif > 0; if (dif > 3 || dif < -3) { // Some correction inc = !inc; } if (inc) { _circleRotationOffset += strength; } else { _circleRotationOffset -= strength; } [circleImage.layer removeAllAnimations]; CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"]; animation.duration = MAX(strength / 2.5, 1.0f); animation.cumulative = YES; animation.repeatCount = 1; animation.values = [NSArray arrayWithObjects: [NSNumber numberWithFloat:p], [NSNumber numberWithFloat: _circleRotationOffset], nil]; animation.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:0], [NSNumber numberWithFloat:1.0], nil]; animation.timingFunctions = [NSArray arrayWithObjects: [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], nil]; animation.removedOnCompletion = YES; animation.delegate = self; animation.fillMode = kCAFillModeForwards; [circleImage.layer addAnimation:animation forKey:@"rotate"]; }; 
+1
source

Source: https://habr.com/ru/post/1391290/


All Articles