4

好的,所以我正在尝试在 iOS 中使用轮子形状制作“幸运之轮”类型的效果,我可以在其中抓住并旋转轮子。我目前可以随心所欲地拖动和旋转轮子,但是松开手指后,它就停止了。我需要对其施加一些动量或惯性,以模拟车轮自然旋转。

我已经进行了速度计算,所以当我抬起手指时,我NSLog会得出一个速度(在最小 1 到最大 100 之间),范围在 1 到 1800 之间(在我最难的轻弹中!) ,现在我只是想确定如何将该速度转换为实际旋转以应用于对象,以及如何随着时间的推移减慢速度。

我最初的想法是这样的:开始以与给定速度相同的速度在一个循环上旋转一整圈,然后在随后的每次旋转中,将速度降低一小部分。这应该会产生一种效果,即较硬的旋转速度更快,并且需要更长的时间才能减速。

我不是数学家,所以我的方法可能是错误的,但如果有人对我如何让它工作有任何提示,至少在基本状态下,我将非常感激。这里有一个非常有用的答案:iPhone添加惯性/动量物理来动画“命运之轮”,如旋转控制,但它更具理论性,缺乏关于如何将计算出的速度准确应用于对象等的实用信息。我是我想我在这里也需要一些动画帮助。

编辑:我还需要弄清楚他们是顺时针还是逆时针拖动轮子。

非常感谢!

4

2 回答 2

1

我为我的程序 Bit 写了一些类似的东西,但我认为我的情况有点复杂,因为我在 3D 中旋转:https ://itunes.apple.com/ua/app/bit/id366236469?mt=8

基本上我所做的是设置一个定期调用某些方法的 NSTimer。我只是用方向和速度来创建一个旋转矩阵(正如我所说,3D 有点糟糕:P),然后我将速度乘以小于 1 的数字,所以它会下降。乘法而不是减法的原因是,如果用户的旋转速度是原来的两倍,那么您不希望对象旋转两倍的时间,因为等待我发现这很烦人。

至于确定车轮旋转的方向,只需将其存储在您拥有所有信息的 touchesEnded:withEvent: 方法中。既然您说只要用户手指向下,您就已经可以进行跟踪,这应该是显而易见的。

我在 3D 中的内容类似于:

// MyView.h
@interface MyView : UIView {
    NSTimer *animationTimer;
}
- (void) startAnimation;
@end


// MyAppDelegate.h
@implementation MyAppDelegate

- (void) applicationDidFinishLaunching:(UIApplication *)application {
    [myView startAnimation];
}

@end

// MyView.m
GLfloat rotationMomentum = 0;
GLfloat rotationDeltaX  = 0.0f;
GLfloat rotationDeltaY  = 0.0f;

@implementation MyView
- (void)startAnimation {
    animationTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)((1.0 / 60.0) * animationFrameInterval) target:self selector:@selector(drawView:) userInfo:nil repeats:TRUE];
}

- (void) drawView:(id)sender {
    addRotationByDegree(rotationMomentum);
    rotationMomentum /= 1.05;
    if (rotationMomentum < 0.1)
        rotationMomentum = 0.1; // never stop rotating completely
    [renderer render];
}

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
}

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
    UITouch *aTouch = [touches anyObject];
    CGPoint loc = [aTouch locationInView:self];
    CGPoint prevloc = [aTouch previousLocationInView:self];

    rotationDeltaX = loc.x - prevloc.x;
    rotationDeltaY = loc.y - prevloc.y;

    GLfloat distance = sqrt(rotationDeltaX*rotationDeltaX+rotationDeltaY*rotationDeltaY)/4;
    rotationMomentum = distance;
    addRotationByDegree(distance);

    self->moved = TRUE;
}

- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
}

- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event
{
}

我省略了 addRotationByDegree 函数,但它的作用是使用全局变量 rotationDeltaX 和 rotationDeltaY 并将旋转矩阵应用于已存储的矩阵,然后保存结果。在您的示例中,您可能想要一些更简单的东西,例如(我现在假设只有 X 方向的运动才能旋转轮子):

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
    UITouch *aTouch = [touches anyObject];
    CGPoint loc = [aTouch locationInView:self];
    CGPoint prevloc = [aTouch previousLocationInView:self];

    GLfloat distance = loc.x - prevloc.x;
    rotationMomentum = distance;
    addRotationByDegree(distance);

    self->moved = TRUE;
}

void addRotationByDegree(distance) {
    angleOfWheel += distance; // probably need to divide the number with something reasonable here to have the spin be nicer
}
于 2013-02-15T16:28:52.137 回答
1

这将是一个粗略的答案,因为我手头没有任何详细的例子。

如果您在抬起手指时已经有了速度,那么它应该不难。你拥有的速度是每秒像素或类似的东西。首先,您需要将该线速度转换为角速度。这可以通过知道圆的周长来完成2*PI*radius,然后2*PI/perimeter*velocity得到以弧度每秒为单位的角速度。

如果您的车轮在其轴上没有任何摩擦,它将永远以该速度运行。好吧,你可以为这个摩擦力仲裁一个值,这是一个加速度,可以用每秒平方的像素数或角加速度的每秒弧度平方来表示。然后只需将角速度除以该角加速度,就可以得到直到它停止的时间。

通过动画时间,您可以使用等式finalAngle = initialAngle + angularSpeed*animationTime - angularAcceleration/2*animationTime*animationTime来获得您的轮子将在动画结束时的最终角度。然后在变换上做一个动画,并在你得到的时间内旋转那个角度,然后说你的动画应该缓和下来。

这看起来应该足够现实。如果不是,您需要根据上面等式中的一些样本为您的轮子的旋转属性提供动画路径。

于 2013-02-21T18:20:05.850 回答