【问题标题】:How to simulate Gravity in z-axis in a 2D game with Sprite Kit如何使用 Sprite Kit 在 2D 游戏中模拟 z 轴上的重力
【发布时间】:2014-01-20 07:43:09
【问题描述】:

我正在 iOS 7 上使用 sprite kit 编写一个 2D 球类游戏,目前正在努力进行一个物理模拟。

解释预期的行为:如果一个球掉进茶杯中,它会转圈,失去速度,最后静止在茶杯的中心。

我尝试使用重力来存档,但精灵套件中的重力仅适用于垂直 X 和 Y 轴,而不适用于 Z 轴。我还尝试通过在 beginContact 上根据当前球在茶杯中的位置切换小实体的重力值来使用水平重力。但是有些联系人被丢弃了,结果看起来很现实。

我想我需要在 update: 方法中解决这个问题,但我不知道该走哪条路。 非常欢迎任何建议,我需要提一下,我不是数学专家,请解释你的路径。 :-)

【问题讨论】:

    标签: ios physics sprite-kit


    【解决方案1】:

    由于 SpriteKit 中没有对这种行为的内置支持,与其尝试破解现有函数来获得所需的东西,不如将一些已发布的 2D 物理公式集成到 x,y 2D 世界中.我认为模拟磁或归位行为之类的东西可能适合这个。

    一个简单的例子是这样的(在场景的 -update: 方法中):

     CGFloat strength = 0.5; //(some scaling value)
     CGPoint ballLocation = ball.position;
     CGPoint cupLocation = cup.position;
     [ball.physicsBody applyForce:CGVectorMake((cupLocation.x - ballLocation.x) * strength, 
                                               (cupLocation.y - ballLocation.y) * strength)];
    

    【讨论】:

    • 感谢 Joshd,您的示例完全符合我的要求。我对以下属性进行了一些尝试:您的强度值、质量/密度和线性阻尼以获得完美的结果。
    • 优秀。如果它回答了您的问题,我会喜欢绿色检查!
    • 因为我有多达 8 个球和杯子,所以我添加了一个 NSArray 来保持每个杯子类都引用实际与杯子接触的球类。在 -update 中:我正在向每个球施加力,就像您的示例显示的那样,每 10 毫秒限制一次。这使性能保持良好,甚至所有的球都在他们的杯子里翻滚......
    • 接受方法如下:meta.stackexchange.com/questions/5234/… - 阵列听起来很酷!你应该发布一个屏幕视频;-)
    • 很简单...稍后会添加视频和数组代码。
    【解决方案2】:

    遵循 Joshd 的好主意,我创建了一个 NSArray,就像我在上面的评论中解释的那样。希望这个 sn-ps 确实对其他人有所帮助...

    结果可以在 youtube 上找到:http://youtu.be/Uephg94UH30 抱歉,Airplay 帧速率不佳,它在我的 iPad 上运行非常流畅

    -update: 函数完成工作,但仅在 _meditationIsActive 时触发。当任何球与球洞接触时,此布尔值在 -didBeginContact: 中设置。

       if (_lastCheck > 0.005)
       {
          if (_meditationIsActive)
          {
             CGFloat strength = 0.1; //(some scaling value)
             CGPoint ballLocation;
             CGPoint holeLocation;
    
             for (MeditationHole * holeObj in _meditationHoles)
             {
                if (holeObj.connectedMeditationBall != nil)
                {
                   ballLocation = holeObj.connectedMeditationBall.position;
                   holeLocation = holeObj.position;
                   [holeObj.connectedMeditationBall.physicsBody applyForce:CGVectorMake(
                                                                                        (holeLocation.x - ballLocation.x) * strength, (holeLocation.y - ballLocation.y) * strength)];
                }
             }
             _meditationIsActive = [self doesMeditationApplies];
          }
          _lastCheck = 0;
       }
    

    最后,我正在检查阵列中是否有一个有效的球与孔接触,以避免在每次更新期间进行检查。这是通过以下功能完成的,其中位置检查 +/- 48 检测到靠近洞的球并且 +/-1 球静止

    - (bool)doesMeditationApplies
    {
       bool isInArea = NO;
       int perfectMatchCount = 0;
       for (MeditationHole * holeObj in _meditationHoles)
       {
          if (holeObj)
          {
             if (holeObj.connectedMeditationBall != nil)
             {
                MeditationBall * ballObj = holeObj.connectedMeditationBall;
                if ((ballObj.position.x >= holeObj.position.x - 48) &&
                    (ballObj.position.x <= holeObj.position.x + 48) &&
                    (ballObj.position.y >= holeObj.position.y - 48) &&
                    (ballObj.position.y <= holeObj.position.y + 48))
                {
                   isInArea = YES;
                }
                else
                {
                   holeObj.connectedMeditationBall = nil;
                }
                if ((ballObj.position.x >= holeObj.position.x - 1) &&
                    (ballObj.position.x <= holeObj.position.x + 1) &&
                    (ballObj.position.y >= holeObj.position.y - 1) &&
                    (ballObj.position.y <= holeObj.position.y + 1))
                {
                   perfectMatchCount++;
                   isInArea = YES;
                }
             }
          }
       }
    
       if (perfectMatchCount == _oxydStonesMax)
       {
          if (_sound)
          {
             self.pauseMusicPlaybackBlock(YES);
             NSLog(@"PlaySound Meditation");
             [OxydScene PlaySystemSound:@"Win2"];
          }
    
          isInArea = NO;
    
          [self showPauseScreenWithWin:YES andPauseOnly:NO];
       }
    
       return isInArea;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-14
      • 2015-12-16
      相关资源
      最近更新 更多