iOS 利用CoreMotion 实现小球随重力和设备方向滚动

需求:

kids 在答题的时候手拿设备根据倾斜度将小球滚动对应的hole中代表选中答案。

现实:

基本思路:
    利用CoreMotion中提供的陀螺仪和加速计来检测当前设备的倾斜度和当前在xy坐标方向小球的速度来实现小球的移动

1.控制小球的移动方向:
  通过 CMMotionManager 来实时获取设备当前的状态,然后更新小球的移动方向。
2.  控制小球的速度,实现小球根据设备的倾斜度以不同的速度移动
    2.1根据小球当前在xy坐标方向上的速度来计算小球当前的加速度,在计算单位时间内小球移动的距离,并更新小球的位置.
    2.2利用 UIDynamicAnimator 来实现。

具体实现:

CMMotionManager的使用很简单,可以看这篇文章 [https://www.jianshu.com/p/c4fff00b50ff](https://www.jianshu.com/p/c4fff00b50ff)

这里主要说下第二个问题和其他一些坑:

控制小球速度2.1 实现代码:

- (void)updateLocation {
  static NSDate *lastUpdateTime = nil;
  if (lastUpdateTime) {
      //计算两次更新之间有多长时间
      NSTimeInterval updatePeriod = [[NSDate date] timeIntervalSinceDate:lastUpdateTime];
      
      //计算球现在的速度。速度= 速度 + 加速度*时间
  
      self.ballXVelocity = self.ballXVelocity + (self.accelleration.x * updatePeriod);
      self.ballYVelocity = self.ballYVelocity + (self.accelleration.y * updatePeriod);
              
      //设置当前的imageView的中心点。后面乘以5000,是为了让小球位移的快一些,很明显能够看到效果。
      
      //横屏
      CGPoint point = CGPointMake(self.currentPoint.x + self.ballXVelocity * updatePeriod * KSpeedVelocity, self.currentPoint.y - self.ballYVelocity * updatePeriod * KSpeedVelocity);
  [self updateCurrentPoint:point];
  }
//更新时间
  lastUpdateTime = [NSDate date];
}

2.2利用 UIDynamicAnimator 来实现。首先大家可以先看下这篇文章https://www.jianshu.com/p/e34dfae218f3 熟悉下UIDynamicAnimator的使用。

看具体实现:

   //开启小球的游戏
- (void)playBall{
    
    if ([self.manager isDeviceMotionAvailable]) {
        self.manager.deviceMotionUpdateInterval = 1 /60;
        __weak __typeof(&*self) weakSelf = self;
        
        [self.manager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
            double gravityX = motion.gravity.x;
            double gravityY = motion.gravity.y;
            
            NSString *velocityX = [NSString stringWithFormat:@"%0.2f",fabs(gravityX)] ;
            NSString *velocityY = [NSString stringWithFormat:@"%0.2f",fabs(gravityY)];
            
            if ([velocityX floatValue] > 0 && [velocityY floatValue] > 0) {
                //  self.gyroscopeBallView.accelleration = motion.gravity;
                //    开启主队列异步线程,更新球的位置。
                dispatch_async(dispatch_get_main_queue(), ^{
                    
                    double xy = 0.0;
                    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
                    if (orientation == UIInterfaceOrientationPortrait) {
                        xy = atan2(gravityX, gravityY);
                        [weakSelf.pushBehvior1 setPushDirection:CGVectorMake(gravityX, gravityY)];
                    }else if (orientation == UIInterfaceOrientationLandscapeLeft) {
                        xy = atan2(gravityY, -gravityX);
                        [weakSelf.pushBehvior1 setPushDirection:CGVectorMake(gravityY, -gravityX)];
                    }else if (orientation == UIInterfaceOrientationLandscapeRight) {
                        xy = atan2(-gravityY, gravityX);
                        [weakSelf.pushBehvior1 setPushDirection:CGVectorMake(-gravityY, gravityX)];
                    }else {

                    }
                    // 计算相对于y轴的重力方向
                    weakSelf.gravityBehavior.angle = xy-M_PI_2;
                    [self.ball updateBallCenter];
                    self.resultLable.text = [self getCorrectAnswer];
                });
            }

看完代码是不是觉得很简单,现在说下需要注意的地方:

  1. 计算小球速度的方法2.1和2.2 对比,亲测方法2.2 比较好,因为2.1会出现卡顿的情况而且小球的回弹效果2.2的实现方式也比较好。
  2. 要注意一点在设备横竖屏下重力在xy坐标上的大小和设备屏幕坐标系直接是存在一定的差异性的,自己手绘了一张图大家可以参考下:


    image.png

总结:

大家可以自己动手实践下,这里主要给出一些自己的心得体会和一些需要注意的地方

最后给大家推荐个不错的公众号 "说神码",或者大家可以扫描下面的二维码关注


iOS 利用CoreMotion 实现小球随重力和设备方向滚动_第1张图片
qrcode_for_gh_3b0177133bdb_258.jpg

你可能感兴趣的:(iOS 利用CoreMotion 实现小球随重力和设备方向滚动)