【问题标题】:SpriteKit, sprite moves very fast when coming back to foreground using accelerometerSpriteKit,当使用加速度计回到前台时,精灵移动得非常快
【发布时间】:2014-07-10 22:51:39
【问题描述】:

在我的 sprite kit 游戏中,角色通过倾斜 iPhone 移动。我已经使用 CMMotionManager 完成了这项工作。它就像一个魅力。

- (void)processUserMotionForUpdate:(NSTimeInterval)currentTime
{
    CMAccelerometerData *data = self.motionManager.accelerometerData;

    //NSLog(@"data is %2@", data);

    if (fabs(data.acceleration.x) > 0.2)
        {
            [self.player.physicsBody applyForce:CGVectorMake(40 * data.acceleration.x, 0)];
        }
}

感谢雷·温德利希!

我使用以下代码启动和停止加速度计。

[self.motionManager startAccelerometerUpdates];
[self.motionManager stopAccelerometerUpdates];

这也很好用。

我遇到的问题是应用程序在后台运行,然后又回到前台。我让加速度计在进入后台时停止,并在进入前台时重新启动。但是,如果我在应用程序处于后台时倾斜 iPhone,然后返回应用程序,我的精灵就会到处乱拍。这几乎就像加速度计在后台将数据保存在缓存中并立即将其全部取出!

为了解决这个问题,我尝试使用 accelerometerUpdateInterval。我 NSLogged 的​​值是 0.010000。因此,当应用程序进入后台时,我将其设置为非常高的数字,希望加速度计能够记录更多数据。

self.motionManager.accelerometerUpdateInterval = 11111;

但它没有工作。如果我倾斜手机,当我回到应用程序时,角色仍然会四处射击。如果我保持非常稳定,就不会发生这种情况。当应用程序进入前台时,我什至将角色的速度设置为零,但这也不起作用。有谁知道如何处理这个问题?提前致谢!!

编辑#1

这就是我的更新方法的样子。

-(void)update:(CFTimeInterval)currentTime
{
    // Called before each frame is rendered
    NSTimeInterval delta = currentTime - self.previousUpdateTime;

    if (delta > 0.02)
    {
        delta = 0.02;
    }

    self.previousUpdateTime = currentTime;
    [self.player update:delta];
}

previousUpdateTime 是一个 NSTimeInterval。

编辑#2

使用 Theis 的建议,我记录了一个从 0 开始并在每次调用该方法时递增的数字,然后我还记录了调用该方法的时间,并在后台应用程序然后将其引入时得到以下结果到前台。

2014-07-12 10:42:34.838 ChargedUp[439:60b] number is 245.000000 at , 33078.175972
2014-07-12 10:42:34.855 ChargedUp[439:60b] number is 246.000000 at , 33078.192806
2014-07-12 10:42:34.871 ChargedUp[439:60b] number is 247.000000 at , 33078.209226

去后台,回来,我得到

2014-07-12 10:42:42.762 ChargedUp[439:60b] number is 248.000000 at , 33086.082453
2014-07-12 10:42:42.798 ChargedUp[439:60b] number is 249.000000 at , 33086.125970
2014-07-12 10:42:42.803 ChargedUp[439:60b] number is 250.000000 at , 33086.142641
2014-07-12 10:42:42.822 ChargedUp[439:60b] number is 251.000000 at , 33086.159510
2014-07-12 10:42:42.837 ChargedUp[439:60b] number is 252.000000 at , 33086.176046

所以似乎该方法被定期调用。我还记录了当前时间的加速度计的值并得到了。

2014-07-12 10:50:30.367 ChargedUp[452:60b] data is x 0.288071 y -0.562469 z -0.778046 @ 33553.664755 at , 33553.704597
2014-07-12 10:50:30.382 ChargedUp[452:60b] data is x 0.286469 y -0.550476 z -0.794571 @ 33553.684229 at , 33553.721224
2014-07-12 10:50:30.399 ChargedUp[452:60b] data is x 0.292175 y -0.541321 z -0.808090 @ 33553.703698 at , 33553.737901

进入后台,然后返回。

2014-07-12 10:50:41.716 ChargedUp[452:60b] data is x -0.241135 y -0.416245 z -0.877899 @ 33565.009330 at , 33565.036282
2014-07-12 10:50:41.756 ChargedUp[452:60b] data is x -0.253601 y -0.390457 z -0.879852 @ 33565.067755 at , 33565.087821
2014-07-12 10:50:41.765 ChargedUp[452:60b] data is x -0.253601 y -0.390457 z -0.879852 @ 33565.067755 at , 33565.104657
2014-07-12 10:50:41.783 ChargedUp[452:60b] data is x -0.246246 y -0.403030 z -0.869965 @ 33565.087311 at , 33565.121255
2014-07-12 10:50:41.799 ChargedUp[452:60b] data is x -0.250214 y -0.405685 z -0.860123 @ 33565.106754 at , 33565.137892

201

哎呀,我想我不需要额外的 currentTime 阅读!感谢您的所有帮助。

编辑#3 [解决方案]

感谢 Theis 的帮助,我终于弄明白了。我最终记录了加速度计的所有数据,发现当它立即进入后台时它并没有停止。我正在使用通知暂停我的游戏。

[[NSNotificationCenter defaultCenter] addObserver:self 选择器:@selector(willResignActive) name:UIApplicationWillResignActiveNotification object:nil];

在 willResignActive 方法中暂停我的游戏。但是,我将这些通知放置在包含我的 Sprite Kit 场景的视图控制器中。因此,当应用程序实际执行 Resign Active 时,加速度计需要一些时间才能真正停止。事实上,直到我触摸了多任务视图中的另一个窗口。所有这些数据都由加速度计保存,然后在返回时使用。所以我只需要将通知放在场景本身中,现在一切正常。感谢大家的洞察力。

【问题讨论】:

  • 可能只是忽略应用从后台返回后获得的第一个值,或者将获得的第一个值作为偏移量或类似的东西?
  • 您是否偶然检查过 delta 是否为负数?
  • @TheisEgeberg,刚刚记录下来。它开始时非常高,例如 567,然后下降到 1.5,然后下降到 0.003 左右作为其余时间的平均值,但这就是为什么我放入 if 语句希望处理它,但没有负值。
  • 加速度计是否会存储值,然后在您重新打开它时触发?我知道其他一些苹果框架可以做到这一点。所以它保存了很多缓冲值,当你的应用程序恢复正常时你会得到这些值。尝试注销 processMotionForUpdate 运行的简单计数。
  • @TheisEgeberg,感谢您的帮助,我在帖子中添加了另一个编辑。我在想也许保存最后的加速度计数据,然后把它放回去?但我认为数据是只读的。

标签: ios iphone objective-c sprite-kit


【解决方案1】:

我认为让它进入后台,恢复然后回到游戏而不在最后一次阅读和你回来后得到的第一个阅读之间进行插值是没有多大意义的。在游戏术语中,它基本上意味着用户可以无限快地“移动”设备。也就是说用户可以将设备向左倾斜,然后将其置于后台。在后台将其向右倾斜并再次打开。加速度计数据现在有一个巨大的跳跃,这意味着一个巨大的跳跃。解决它的一种方法是让加速度计不设置移动物理对象的速度,但有一个中间变量会随着时间的推移影响速度。

【讨论】:

  • 我明白你在说什么,不管我做什么,它仍然会因为差异而跳跃。但是,如果我使用加速度计移动角色,而您的建议是不让加速度计设置速度,我将如何倾斜手机并获得动作?我将如何使用这个中间变量?再次感谢您的帮助。
  • 您有设置作用力的变量。开始时将其设置为零。如果设备倾斜,您可以像这样更改施加的力:appliedForce += deviceTilt*0.5(可选阻尼系数)。然后你限制施加的力:appliedForce =(appliedForce>5?5:appliedForce);应用力=(应用力
  • Theis,非常感谢您的帮助。我对解决方案进行了另一次编辑。但如果不是你,我永远也找不到它。非常感谢您的时间和努力!
【解决方案2】:

感谢 Theis 的帮助,我终于弄明白了。我最终记录了加速度计的所有数据,发现当它立即进入后台时它并没有停止。我正在使用通知暂停我的游戏。

[[NSNotificationCenter defaultCenter] addObserver:self 选择器:@selector(willResignActive) name:UIApplicationWillResignActiveNotification object:nil];

在 willResignActive 方法中暂停我的游戏。但是,我将这些通知放置在包含我的 Sprite Kit 场景的视图控制器中。因此,当应用程序实际执行 Resign Active 时,加速度计需要一些时间才能真正停止。事实上,直到我触摸了多任务视图中的另一个窗口。所有这些数据都由加速度计保存,然后在返回时使用。所以我只需要将通知放在场景本身中,现在一切正常。感谢大家的洞察力。

【讨论】:

  • 给你@rickster。感谢您的建议。
猜你喜欢
  • 2019-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多