Импульс вращения колеса iPhone (фортуны) - PullRequest
4 голосов
/ 16 января 2012

У меня проблемы с добавлением импульса к вращающемуся колесу.
У меня есть это колесо (что-то вроде это ), и я вращаю его вокруг его центра, используя одно касание.
Здесь нет проблем, но когда касание (иначе перетаскивание) заканчивается; Я хочу, чтобы колесо сохраняло свой импульс и облегчало его движение.

Любой, кто может дать мне несколько советов, не обязательно должен быть в объективе-c. AS3, javascript или JAVA также будет достаточно.

* ОБНОВЛЕНИЕ (код для вращения колеса) *

    -(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);
    };

Ответы [ 3 ]

5 голосов
/ 16 января 2012

Вы хотите, чтобы импульс уменьшился из-за трения; трение - это сила, которая является функцией скорости. Технически, у вас есть дифференциальное уравнение. Однако не стоит вкладывать в это слишком много внимания, потому что решение, вероятно, легче найти, просто взмахнув рукой.

Итак: сохранить текущий угол и текущую угловую скорость. n раз в секунду (возможно, через NSTimer или CADisplayLink) прибавьте угловую скорость к углу, затем умножьте угловую скорость на что-то, чтобы сделать ее меньше - например, 0,995. Константы, близкие к 1.0, замедляют процесс; если вы пойдете выше 1,0, он, очевидно, ускорится. По сути, это форма интеграции Эйлера, но, опять же, об этом не стоит беспокоиться.

Возможно, также стоит установить минимальный предел угловой скорости, чтобы, если она упадет ниже, скажем, 0,01 радиана / секунду, вы снизите ее до 0. Это эффективно немного изменит вашу модель трения для перехода от кинетического к статическому трению при подходящий момент и действует как буферная зона точности с плавающей запятой.

Чтобы получить начальную скорость от перетаскивания, вы можете просто обработать вектор от центра колеса до начала перетаскивания, повернуть этот вектор на 90 градусов, сделать с ним точечное произведение, вектор перетаскивания и масштабировать в соответствии с к расстоянию от центра.

1 голос
/ 17 января 2012

Мне удалось получить хорошие результаты.
Как я это сделал, надо подправить еще, но это основы:

    -(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 голос
/ 16 января 2012

Если вы вращаете UIImageView с кодом, подобным:
[UIView beginAnimations:@"rotateImage" context:nil];
[UIView setAnimationDuration:4.0];
wheelImageView.transform = CGAffineTransformMakeRotation(3.14159265*5);
[UIView commitAnimations];

Вы можете использовать [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
Это делает так, чтобы анимация начиналась быстро и постепенно замедлялась.

Нажмите здесь для получения дополнительной информации о UIViewAnimationCurve

...