Ios 精灵套件:匀速运动时口吃

Ios 精灵套件:匀速运动时口吃,ios,objective-c,sprite-kit,game-physics,Ios,Objective C,Sprite Kit,Game Physics,我正在用精灵工具包开发一个简单的飞行游戏。一旦太空船达到最大高度和速度,它就会以恒定速度继续飞行。我注意到宇宙飞船在持续的飞行中随机地发出口吃声。我已经在这里阅读了所有关于这个问题的帖子,但是没有任何东西能够100%的解决这个问题 为了测试,我编写了一个非常简单的游戏,其中只包含一艘宇宙飞船和一个简单的云(代码如下)。但即使在这个非常简单的游戏中,太空船仍然会口吃。日志显示,即使飞船以恒定速度飞行,飞船的运动也不是随机恒定的。这就是口吃的原因 希望有人能帮我解决这个问题。谢谢你的建议 Spri

我正在用精灵工具包开发一个简单的飞行游戏。一旦太空船达到最大高度和速度,它就会以恒定速度继续飞行。我注意到宇宙飞船在持续的飞行中随机地发出口吃声。我已经在这里阅读了所有关于这个问题的帖子,但是没有任何东西能够100%的解决这个问题

为了测试,我编写了一个非常简单的游戏,其中只包含一艘宇宙飞船和一个简单的云(代码如下)。但即使在这个非常简单的游戏中,太空船仍然会口吃。日志显示,即使飞船以恒定速度飞行,飞船的运动也不是随机恒定的。这就是口吃的原因

希望有人能帮我解决这个问题。谢谢你的建议


Sprite工具包,Objective c,Xcode 8.0,测试设备:iPhone 6-iOS 8.3,iPhone 4s-iOS 9.3.5

CPU:最大21%,内存:最大8MB,每秒:永久60FPS


这里是我的代码(为了简单起见,我将所有代码放在scene类中)


飞行场景

#import <SpriteKit/SpriteKit.h>

@interface FlightScene : SKScene <SKPhysicsContactDelegate>

@end

编辑:


  • 我将此添加到
    addHero:
    方法中

    _hero.physicsBody.angularDamping = 0.0f;
    
  • 我更改了
    触摸开始:
    ,这样飞船就可以立即以最大速度飞行而不起飞

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        if(_hasBegun)
            return;
    
        _hasBegun = YES;
        _hero.physicsBody.velocity = CGVectorMake(kMaxHeroVelocityX, kMaxHeroVelocityY);
    }
    
    -(void)touchesbeated:(NSSet*)toucheevent:(UIEvent*)event
    {
    如果(_已开始)
    返回;
    _hasbeated=是;
    _hero.physicsBody.velocity=CGVectorMake(kMaxHeroVelocityX,kMaxHeroVelocityY);
    }
    
    • 我运行代码时没有使用
      updatefling:
      方法。宇宙飞船立即以最大速度飞行而不起飞。它以恒定的速度飞行,因此不需要更新速度

    • 我尝试了其他方法,比如将更新放在
      didSimulatePhysics:
      中。。打开飞行模式。。正如他所说的。。但没有什么能解决这个问题。它仍然不是像@crashoveride777所说的那样100%完美


如果还有其他想法,我将不胜感激。

这是因为SpriteKit的默认物理和运动/变换处理未按增量时间进行更正。相反,每当由于系统调用或其他中断而导致帧速率下降时,它就会结巴。这些事情在iOS设备上经常发生。iOS系统不断检查网络,监控各种后台活动的其他状态,并对收到的信息做出响应

有两种方法可以解决这个问题

  • 打开飞行模式,关闭所有后台更新应用程序,严格限制几乎所有应用程序在其设置中进行后台处理;这减少了操作系统噪音和开销

  • 使用delta time滚动您自己的调整和补偿机制,这样即使跳过一两帧,事情也会以正确的速率继续移动到预期的目的地


  • 如果你不局限于SpriteKit,或者不需要它的物理,你可以包括另一个物理引擎并使用它。这最终意味着您可以使用SceneKit、核心动画甚至金属来进行渲染。。。。还是斯皮特基特

    最明智的两个选择是Box2D和Chipmunk2D

    以下是有关将Box2D添加到iOS的教程:


    这是花栗鼠2D的快速包装:

    我的游戏也遇到了同样的问题。似乎它并不特别喜欢持续的运动

    你可以尝试的第一件事就是使用

    applyForce
    
    而不是直接操纵玩家的速度属性

    当我在常规赛中移动球员时,我似乎得到了最好的结果

    override func update(_ currentTime: TimeInterval) { ... }
    
    方法

    我更新了相机

    override func didFinishUpdate() { ... }
    
    在苹果示例游戏Demobot中,他们对相机使用约束。在DidSimulatePhysics之后,约束将得到更新,因此当您手动执行时,didFinishUpdate似乎是最佳位置

    还请记住,通过执行以下操作,您将获得一些性能

    1)测试时断开手机与mac的连接。只需在插入时通过xCode运行手机就会降低性能

    2)测试应用程序时,它处于调试模式,而不是发布模式,这将降低性能

    若要在测试时手动更改此设置,请转到您的方案(按以运行应用程序的按钮旁边的按钮)。单击“编辑方案”并在“更改生成配置以发布信息”中单击

    请记住,当您完成特定测试时,应该将其更改回。您希望在测试应用程序时运行调试工具

    3)确保您的抽签要求非常低。通过确保

    ignoresSiblingOrder 
    
    在GameViewController中设置为true,默认情况下应为true

    而不是根据你的精灵所在的图层给他们不同的位置

    e、 g

    4)尽可能多地制作物理体,因为它们使用最少的性能

    5)更新方法中的代码尽可能少

    6)缓存纹理,尤其是在使用纹理动画时


    7)如果要大量实例化某些节点,请将它们集合起来。

    我将回答自己的问题

    飞行阶段:

    • 起飞
    • 一旦太空船达到最高高度和速度,它就会继续飞行 匀速
    问题:

    • 宇宙飞船在持续飞行中随机地发出口吃声
    这种情况下的解决方案:

    • 由于口吃发生在持续飞行期间,请定义一个变量(
      \u maxreach
      )来控制起飞阶段的结束

    • 一旦太空船达到最大高度和速度,设置
      \u maxreach=YES

    • 通过更新x位置(
      updatePosition
      )更新恒定飞行

    更新
    override func didFinishUpdate() { ... }
    
    ignoresSiblingOrder 
    
    background = 1
    sun = 2
    clouds = 3
    traps, obstacles, objects = 4
    player = 5
    
    .
    .
    // new:
    static const CGFloat kMaxSpeed = 5.0f;
    
    @implementation FlightScene
    {
    .
    .
    .
        // new:
        BOOL _maxReached;
    }
    
    // new: rename
    //- (void)updateFlying
    - (void)takeOff
    {
        if(!_hasBegun)
            return;
    
        CGVector oldVel = _hero.physicsBody.velocity;
        CGVector newVel = oldVel;
    
        // increase the velocity
        newVel.dx += (kMaxHeroVelocityX - newVel.dx) / 10.0f;
        newVel.dy += (kMaxHeroVelocityY - newVel.dy) / 10.0f;
    
        // ensure velocity doesn't exceed maximum
        newVel.dx = newVel.dx > kMaxHeroVelocityX ? kMaxHeroVelocityX : newVel.dx;
        newVel.dy = newVel.dy > kMaxHeroVelocityY ? kMaxHeroVelocityY : newVel.dy;
    
        _hero.physicsBody.velocity = newVel;    
    }
    
    - (void)limitHeight
    {
        const CGFloat maxHeight = self.size.height * 0.8f;
    
        // new 
        if(_hero.position.y >= maxHeight)
        {
        if(_hero.physicsBody.velocity.dy == kMaxHeroVelocityY)
            _maxReached = YES;
    
            if(_hero.position.y > maxHeight)
                _hero.position = CGPointMake(_hero.position.x, maxHeight);
        }
    }
    
    // new: move the hero with constant velocity 
    - (void)updatePosition
    {
        CGFloat newX = _hero.position.x + kMaxSpeed;
        _hero.position = CGPointMake(newX, _hero.position.y);
    }
    
    - (void)updateFlight
    {    
        if(_maxReached) // new
        {
            [self updatePosition]; // move the hero with constant velocity
        }
        else
        {
            [self takeOff];
    
            // ensure height doesn't exceed maximum
            [self limitHeight];
        }
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        if(_hasBegun)
            return;
    
        _hasBegun = YES;
        _maxReached = NO; // new
        [self updateFlight];
    }