【问题标题】:How best to give falling ball real world gravity如何最好地给予落球真实世界的重力
【发布时间】:2014-03-27 20:39:33
【问题描述】:

我是一个相当新的应用程序开发人员,对 Sprite Kit 非常陌生。我正在创建一个游戏,我希望球总是像重力一样向下落。这只是一个 2d 应用程序,所以我想要的只是当球落下时,当您将手机向左倾斜时,球在屏幕上向下和向左移动,如果您将手机向右倾斜,球在屏幕上向下和向右移动.为了更好地了解我想要的内容,我在 Photoshop 中制作了一个快速图表:

我想就哪种方法最简单和最好的方法提出一些意见。我的第一个想法是记录偏航并用它来指示球向左或向右行进多远。这需要一些计算才能让球以 90 度完美落下,虽然这对我来说听起来可能,但我不确定它是否真的可能。

有人认为这是这样做的方法还是有更好的方法?

我在尝试第一个想法时遇到的一个问题是,当我倾斜手机时,球会左右移动(没有任何适当的计算,因此完全不准确),我会将手机向左倾斜(对于示例)并且我将其倾斜得越远,它变得越不敏感,因此球向左移动的距离就越少。这会阻止我的想法发挥作用,我不确定是否有解决办法。

我遇到的一个更大的问题是当我在座位上旋转时,偏航也会改变!我认为这与指南针有关,因为我这样做时滚动或俯仰都没有改变。我确信可以采取一些措施来纠正这个问题,因为我在玩使用陀螺仪的游戏时从来没有遇到过这个问题。如果有人能指出我正确的方向,我将不胜感激,或者我可能只是在一个单独的新问题中问它。下面是我在 Photoshop 中快速绘制的另一个图表,以帮助解释问题。图 1 是我希望能够倾斜手机的方式,但是当你转身时(图 2),球会向左或向右移动,这取决于你转了多远。 (是的,这意味着是图 2 中拿着手机的人)

我们将不胜感激!

【问题讨论】:

    标签: ios objective-c sprite-kit game-physics core-motion


    【解决方案1】:

    这是我从不久前构建的一个演示项目中提取的一些代码。它是通过将一堆视图与 UIKit 动态连接起来创建的一根绳子。根据您的描述,我认为该行为与您要查找的行为相同。

    需要注意的是,此代码遵循真实的重力方向,因此,如果您将手机平放,在平行于屏幕的平面上,重力将为 0 或接近 0,因为它的全部大小将沿着z 轴。您可能希望对其进行归一化,以便方向发生变化,但幅度保持不变。

    在此示例中,self.gravityUIGravityBehavior,但您可以使用相同的代码来提供您想要的任何类型的重力模拟。只需注销运动管理器处理程序中的值,即可查看您可能获得的值类型。

    self.motionManager = [[CMMotionManager alloc] init];
    [self.motionManager startDeviceMotionUpdatesToQueue:self.motionQueue withHandler:^(CMDeviceMotion *motion, NSError *error) {
        CMAcceleration gravity = motion.gravity;
        dispatch_async(dispatch_get_main_queue(), ^{
            self.gravity.gravityDirection = CGVectorMake(gravity.x, -gravity.y);
        });
    }];
    

    我希望这会有所帮助!

    【讨论】:

    • 非常感谢您的帮助。我的项目中有你的代码,但我不确定如何让它移动球,因为我不能将屏幕宽度乘以 x 值,那么你有什么建议?我敢肯定它比我想象的要简单,但我想不出办法。我知道您从一个听起来非常不同的项目中提取了代码,但是比我更有经验的人可能能够比我做得更好!谢谢!
    • 也许下落物体的位置公式会有所帮助?位移 = 1/2 g t^2,其中 g 是您刚刚找到的重力矢量,t 是经过的时间。更多here.
    • 哦,我忘了你在使用 SpriteKit。我对 API 不熟悉,但是否有可以插入该向量的重力行为?
    • 很抱歉回复晚了。很忙!非常感谢你的帮助。我保证我会将您的答案标记为“已回答”。无论如何,关于你提到的重力行为,你知道我在哪里可以找到更多关于它的信息吗?谷歌搜索没有显示任何我认为有帮助的结果。如果您可以提供尽可能多的帮助,请不要担心,因为我意识到您不熟悉 SpriteKit。我相信我最终会弄清楚的,或者我会放弃并找到一个更简单的想法......(最后的手段)
    • 啊,好的。这足以让我弄清楚其余的。感谢你的帮助!祝你有美好的一天。
    【解决方案2】:

    这是一个使用 SpriteKit 的解决方案:

    1.新建一个SpriteKit项目

    2.添加CoreMotion框架

    3.在“MyScene”类中导入新框架:

    #import <CoreMotion/CoreMotion.h>
    

    4.Example 针对这个方向进行了优化:

    5.将此代码添加到“MyScene”类的“touchesBegan”方法中

        sprite.size = CGSizeMake(20, 20);
        sprite.physicsBody= [SKPhysicsBody bodyWithCircleOfRadius:sprite.size.width/2];
    

    6.将此代码添加到“MyScene”类的“update”方法中

    CMMotionManager *_motionManager;
    -(void)update:(CFTimeInterval)currentTime {
        /* Called before each frame is rendered */
        if (_motionManager== nil) {
            _motionManager=[[CMMotionManager alloc]init];
            _motionManager.deviceMotionUpdateInterval=0.025;
            [_motionManager startDeviceMotionUpdates];
        }
    
        CMAcceleration gravity=  _motionManager.deviceMotion.gravity;
        self.physicsWorld.gravity = CGVectorMake(gravity.y*4, -gravity.x/4);
    
    }
    

    您必须四处寻找重力的最佳因素。

    希望有用

    【讨论】:

    • 感谢 Stefan 的意见。看到不同的解决方案很有帮助。我已经意识到,虽然使用重力影响球的侧向运动是不现实的,因为当你转动设备时会有延迟,然后是加速度。这不是现实世界的物理学,我目前正在研究如何在不使用重力的情况下控制侧向运动。
    • 嗨,大卫。如果您找到解决方案,如果您可以在这里分享,那就太好了。我想很多人(包括我)都尝试过。
    【解决方案3】:

    Swift 代码:

     if motion.isDeviceMotionAvailable {
                self.motion.deviceMotionUpdateInterval = 1.0 / 60.0
                self.motion.showsDeviceMovementDisplay = true
                self.motion.startDeviceMotionUpdates(using: .xMagneticNorthZVertical)
                // Configure a timer to fetch the motion data.
                self.timer = Timer(fire: Date(), interval: (1.0/60.0), repeats: true,
                                   block: { (timer) in
                                    if let data = self.motion.deviceMotion {
                                      let gravityData = data.gravity
                                      scene.physicsWorld.gravity = CGVector(dx: 9.8 * (gravityData.x), dy: 9.8 * (gravityData.y))
                                    }
                })
                // Add the timer to the current run loop.
                RunLoop.current.add(self.timer, forMode: .defaultRunLoopMode)
              }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-19
      • 2017-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-16
      • 2010-12-07
      • 1970-01-01
      相关资源
      最近更新 更多