Sprite 套件:在匀速运动过程中出现口吃

Posted

技术标签:

【中文标题】Sprite 套件:在匀速运动过程中出现口吃【英文标题】:Sprite kit: Stuttering during movement with constant velocity 【发布时间】:2016-10-02 17:20:50 【问题描述】:

我正在使用 sprite kit 开发一个简单的飞行游戏。一旦宇宙飞船达到最大高度和速度,它就会以恒定速度飞行。我注意到宇宙飞船在不断的飞行过程中随机结结巴巴。我在这里阅读了所有关于这个问题的帖子,但没有什么能真正帮助 100% 解决它。

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

希望有人能帮我解决这个问题。感谢您的任何想法。


Sprite 套件,Objective c,Xcode 8.0,测试设备:iPhone 6 - ios 8.3,iPhone 4s - iOS 9.3.5

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


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


FlightScene.h

#import <SpriteKit/SpriteKit.h>

@interface FlightScene : SKScene <SKPhysicsContactDelegate>

@end

FlightScene.m

#import "FlightScene.h"

#define  HERO_FLIGHT_LOG    1
//#define  HERO_DEBUG_OVERLAY 1

static const CGFloat kMaxHeroVelocityY = 100.0f;
static const CGFloat kMaxHeroVelocityX = 200.0f;

@implementation FlightScene

    SKNode *_world;
    SKSpriteNode *_hero;
    SKSpriteNode *_cloud;

    CGPoint _heroStartPosition;
    CGSize _cloudSize;
    CGFloat _xAdj;

    BOOL _hasBegun;

    // debug
    CGFloat _oldHeroX;
    CGFloat _oldHeroY;
    int _frame;



- (void)didMoveToView:(SKView *)view

    // Setup your scene here

    [super didMoveToView:view];

    _hasBegun = NO;        
    _cloudSize = CGSizeMake(120, 80);
    _xAdj = _cloudSize.width;
    _heroStartPosition = CGPointMake(60, self.size.height/2);

    [self addWorld];
    [self addHero];
    [self addCloud];

    // debug
    _frame = 0;
    _oldHeroX = 0;
    _oldHeroY = 0;


#pragma mark - hero

- (void)addHero

    _hero = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship2"];

    _hero.size = CGSizeMake(80.0f, 70.0f);
    _hero.position = _heroStartPosition;
    _hero.zPosition = 1;

    _hero.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.size.width/2.0f];
    _hero.physicsBody.affectedByGravity = NO;
    _hero.physicsBody.dynamic = YES;
    _hero.physicsBody.allowsRotation = NO;
    _hero.physicsBody.mass = 1.0f;
    _hero.physicsBody.linearDamping = 0.0f;
    _hero.physicsBody.friction = 0.0f;

    [_world addChild:_hero];


- (void)updateFlying

    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;
    if(_hero.position.y > maxHeight)
        _hero.position = CGPointMake(_hero.position.x, maxHeight);


- (void)updateFlight

    // move hero with constant velocity
    [self updateFlying];

    // ensure height doesn't exceed maximum
    [self limitHeight];


#pragma mark - game world

- (void)addWorld

    _world = [SKNode new];
    [self addChild:_world];


- (void)addCloud

    _cloud = [SKSpriteNode spriteNodeWithColor:[SKColor lightGrayColor] size:_cloudSize];

    _cloud.anchorPoint = CGPointMake(0, 1); // top left
    _cloud.position = CGPointMake(self.size.width + _cloudSize.width, self.size.height + _cloudSize.height/2);
    _cloud.zPosition = -1;

    [_world addChild:_cloud];


#pragma mark - update world

- (void)updateCloud

    // reposition the cloud
    if(_world.position.x + _xAdj < -(_cloudSize.width + self.size.width))
    
        _xAdj += _cloudSize.width + self.size.width;

        CGFloat y = arc4random_uniform(_cloudSize.height - 10);
        _cloud.position = CGPointMake(_xAdj + self.size.width, self.size.height + y);
    


- (void)updateWorld

    // move the world
    CGFloat worldX = -(_hero.position.x - _heroStartPosition.x);
    _world.position = CGPointMake(worldX, _world.position.y);

    [self updateCloud];
    [self flightLog];


-(void)update:(CFTimeInterval)currentTime

    // Called before each frame is rendered

    if(!_hasBegun)
        return;

    _frame++;

    // update hero movement
    [self updateFlight];


- (void)didFinishUpdate

    if(!_hasBegun)
        return;

    // update world movement
    [self updateWorld];        


#pragma mark - touches

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

    if(_hasBegun)
        return;

    _hasBegun = YES;
    [self updateFlight];



#pragma mark - debug

- (void)flightLog


#ifdef HERO_FLIGHT_LOG

    CGFloat newHeroX = _hero.position.x - _heroStartPosition.x;;
    CGFloat diffX = newHeroX - _oldHeroX;

    CGFloat newHeroY = _hero.position.y;
    CGFloat diffY = newHeroY - _oldHeroY;

    NSLog(@"oldHeroY:%f, newHeroY:%f, diffY:%f", _oldHeroY, newHeroY, diffY);
    NSLog(@"oldHeroX:%f, newHeroX:%f, diffX:%f\n\n", _oldHeroX, newHeroX, diffX);

    if(diffX > 3.5f)
    
        //NSLog(@"\t -> frame:%d fast oldHeroY:%f, newHeroY:%f, diffY:%f", _frame, _oldHeroY, newHeroY, diffY);
        NSLog(@"\t -> frame:%d fast oldHeroX:%f, newHeroX:%f, diffX:%f\n\n", _frame, _oldHeroX, newHeroX, diffX);
    
    else if(diffX < 3.0f)
    
        //NSLog(@"\t -> frame:%d fast oldHeroY:%f, newHeroY:%f, diffY:%f", _frame, _oldHeroY, newHeroY, diffY);
        NSLog(@"\t -> frame:%d slow oldHeroX:%f, newHeroX:%f, diffX:%f\n\n", _frame, _oldHeroX, newHeroX, diffX);
    

    _oldHeroX = newHeroX;
    _oldHeroY = newHeroY;

#endif



@end

日志:


.
.
.
// no stuttering .. FPS: 60

2016-10-02 17:27:19.164 TestFlight[11009:1774440] oldHeroY:301.666534, newHeroY:301.666534, diffY:0.000000
2016-10-02 17:27:19.165 TestFlight[11009:1774440] oldHeroX:263.002899, newHeroX:266.335968, diffX:3.333069

2016-10-02 17:27:19.181 TestFlight[11009:1774440] oldHeroY:301.666534, newHeroY:301.666534, diffY:0.000000
2016-10-02 17:27:19.182 TestFlight[11009:1774440] oldHeroX:266.335968, newHeroX:269.669067, diffX:3.333099

// stuttering .. FPS: 60

2016-10-02 17:27:24.584 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:302.500031, diffY:0.833344
2016-10-02 17:27:24.585 TestFlight[11009:1774440] oldHeroX:1346.335083, newHeroX:1351.335083, diffX:5.000000

2016-10-02 17:27:24.585 TestFlight[11009:1774440]    -> frame:413 fast oldHeroX:1346.335083, newHeroX:1351.335083, diffX:5.000000

2016-10-02 17:27:24.600 TestFlight[11009:1774440] oldHeroY:302.500031, newHeroY:300.833344, diffY:-1.666687
2016-10-02 17:27:24.601 TestFlight[11009:1774440] oldHeroX:1351.335083, newHeroX:1353.001709, diffX:1.666626

2016-10-02 17:27:24.601 TestFlight[11009:1774440]    -> frame:414 slow oldHeroX:1351.335083, newHeroX:1353.001709, diffX:1.666626

2016-10-02 17:27:24.617 TestFlight[11009:1774440] oldHeroY:300.833344, newHeroY:301.666687, diffY:0.833344
2016-10-02 17:27:24.618 TestFlight[11009:1774440] oldHeroX:1353.001709, newHeroX:1356.335083, diffX:3.333374

2016-10-02 17:27:24.634 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:24.634 TestFlight[11009:1774440] oldHeroX:1356.335083, newHeroX:1359.668457, diffX:3.333374

2016-10-02 17:27:24.650 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:24.651 TestFlight[11009:1774440] oldHeroX:1359.668457, newHeroX:1363.001831, diffX:3.333374

2016-10-02 17:27:24.667 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:302.500031, diffY:0.833344
2016-10-02 17:27:24.668 TestFlight[11009:1774440] oldHeroX:1363.001831, newHeroX:1368.001831, diffX:5.000000

2016-10-02 17:27:24.668 TestFlight[11009:1774440]    -> frame:418 fast oldHeroX:1363.001831, newHeroX:1368.001831, diffX:5.000000

2016-10-02 17:27:24.684 TestFlight[11009:1774440] oldHeroY:302.500031, newHeroY:300.833344, diffY:-1.666687
2016-10-02 17:27:24.684 TestFlight[11009:1774440] oldHeroX:1368.001831, newHeroX:1369.668457, diffX:1.666626

2016-10-02 17:27:24.685 TestFlight[11009:1774440]    -> frame:419 slow oldHeroX:1368.001831, newHeroX:1369.668457, diffX:1.666626

2016-10-02 17:27:24.700 TestFlight[11009:1774440] oldHeroY:300.833344, newHeroY:301.666687, diffY:0.833344
2016-10-02 17:27:24.701 TestFlight[11009:1774440] oldHeroX:1369.668457, newHeroX:1373.001831, diffX:3.333374

2016-10-02 17:27:24.717 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:302.500031, diffY:0.833344
2016-10-02 17:27:24.718 TestFlight[11009:1774440] oldHeroX:1373.001831, newHeroX:1378.001831, diffX:5.000000

2016-10-02 17:27:24.718 TestFlight[11009:1774440]    -> frame:421 fast oldHeroX:1373.001831, newHeroX:1378.001831, diffX:5.000000

2016-10-02 17:27:24.734 TestFlight[11009:1774440] oldHeroY:302.500031, newHeroY:301.666687, diffY:-0.833344
2016-10-02 17:27:24.734 TestFlight[11009:1774440] oldHeroX:1378.001831, newHeroX:1381.335205, diffX:3.333374

// no stuttering  .. FPS: 60

2016-10-02 17:27:24.750 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:24.751 TestFlight[11009:1774440] oldHeroX:1381.335205, newHeroX:1384.668579, diffX:3.333374

2016-10-02 17:27:24.767 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:24.768 TestFlight[11009:1774440] oldHeroX:1384.668579, newHeroX:1388.001953, diffX:3.333374

2016-10-02 17:27:24.784 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:24.784 TestFlight[11009:1774440] oldHeroX:1388.001953, newHeroX:1391.335327, diffX:3.333374

2016-10-02 17:27:24.801 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:24.801 TestFlight[11009:1774440] oldHeroX:1391.335327, newHeroX:1394.668701, diffX:3.333374

2016-10-02 17:27:24.817 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:24.818 TestFlight[11009:1774440] oldHeroX:1394.668701, newHeroX:1398.002075, diffX:3.333374

2016-10-02 17:27:24.834 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:24.834 TestFlight[11009:1774440] oldHeroX:1398.002075, newHeroX:1401.335449, diffX:3.333374

2016-10-02 17:27:24.850 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:24.851 TestFlight[11009:1774440] oldHeroX:1401.335449, newHeroX:1404.668823, diffX:3.333374

2016-10-02 17:27:24.867 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:24.868 TestFlight[11009:1774440] oldHeroX:1404.668823, newHeroX:1408.002197, diffX:3.333374

// stuttering  .. FPS: 60

2016-10-02 17:27:24.883 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:300.833344, diffY:-0.833344
2016-10-02 17:27:24.884 TestFlight[11009:1774440] oldHeroX:1408.002197, newHeroX:1409.668823, diffX:1.666626

2016-10-02 17:27:24.885 TestFlight[11009:1774440]    -> frame:431 slow oldHeroX:1408.002197, newHeroX:1409.668823, diffX:1.666626

2016-10-02 17:27:24.901 TestFlight[11009:1774440] oldHeroY:300.833344, newHeroY:302.500031, diffY:1.666687
2016-10-02 17:27:24.902 TestFlight[11009:1774440] oldHeroX:1409.668823, newHeroX:1414.668823, diffX:5.000000

2016-10-02 17:27:24.902 TestFlight[11009:1774440]    -> frame:432 fast oldHeroX:1409.668823, newHeroX:1414.668823, diffX:5.000000

2016-10-02 17:27:24.917 TestFlight[11009:1774440] oldHeroY:302.500031, newHeroY:300.833344, diffY:-1.666687
2016-10-02 17:27:24.918 TestFlight[11009:1774440] oldHeroX:1414.668823, newHeroX:1416.335449, diffX:1.666626

2016-10-02 17:27:24.918 TestFlight[11009:1774440]    -> frame:433 slow oldHeroX:1414.668823, newHeroX:1416.335449, diffX:1.666626

2016-10-02 17:27:24.934 TestFlight[11009:1774440] oldHeroY:300.833344, newHeroY:302.500031, diffY:1.666687
2016-10-02 17:27:24.935 TestFlight[11009:1774440] oldHeroX:1416.335449, newHeroX:1421.335449, diffX:5.000000

2016-10-02 17:27:24.935 TestFlight[11009:1774440]    -> frame:434 fast oldHeroX:1416.335449, newHeroX:1421.335449, diffX:5.000000

2016-10-02 17:27:24.950 TestFlight[11009:1774440] oldHeroY:302.500031, newHeroY:301.666687, diffY:-0.833344
2016-10-02 17:27:24.951 TestFlight[11009:1774440] oldHeroX:1421.335449, newHeroX:1424.668823, diffX:3.333374

// no stuttering for a while (17 seconds .. long time) .. FPS: 60

2016-10-02 17:27:24.967 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:24.968 TestFlight[11009:1774440] oldHeroX:1424.668823, newHeroX:1428.002197, diffX:3.333374
.
.
.

2016-10-02 17:27:41.559 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:41.559 TestFlight[11009:1774440] oldHeroX:4742.992188, newHeroX:4746.325684, diffX:3.333496

// stuttering .. FPS: 60 

2016-10-02 17:27:41.575 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:300.833344, diffY:-0.833344
2016-10-02 17:27:41.576 TestFlight[11009:1774440] oldHeroX:4746.325684, newHeroX:4747.992188, diffX:1.666504

2016-10-02 17:27:41.576 TestFlight[11009:1774440]    -> frame:1432 slow oldHeroX:4746.325684, newHeroX:4747.992188, diffX:1.666504

2016-10-02 17:27:41.592 TestFlight[11009:1774440] oldHeroY:300.833344, newHeroY:302.500031, diffY:1.666687
2016-10-02 17:27:41.593 TestFlight[11009:1774440] oldHeroX:4747.992188, newHeroX:4752.992188, diffX:5.000000

2016-10-02 17:27:41.593 TestFlight[11009:1774440]    -> frame:1433 fast oldHeroX:4747.992188, newHeroX:4752.992188, diffX:5.000000

2016-10-02 17:27:41.609 TestFlight[11009:1774440] oldHeroY:302.500031, newHeroY:301.666687, diffY:-0.833344
2016-10-02 17:27:41.609 TestFlight[11009:1774440] oldHeroX:4752.992188, newHeroX:4756.325684, diffX:3.333496

2016-10-02 17:27:41.625 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:41.626 TestFlight[11009:1774440] oldHeroX:4756.325684, newHeroX:4759.659180, diffX:3.333496

2016-10-02 17:27:41.642 TestFlight[11009:1774440] oldHeroY:301.666687, newHeroY:301.666687, diffY:0.000000
2016-10-02 17:27:41.643 TestFlight[11009:1774440] oldHeroX:4759.659180, newHeroX:4762.992676, diffX:3.333496
.
.
.
// and so on ..

编辑:


我将此添加到 addHero: 方法中

_hero.physicsBody.angularDamping = 0.0f;

我更改了touchesBegan:,以便太空船立即以最大速度飞行而无需起飞。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

    if(_hasBegun)
        return;

    _hasBegun = YES;
    _hero.physicsBody.velocity = CGVectorMake(kMaxHeroVelocityX, kMaxHeroVelocityY);

我在没有updateFlying: 方法的情况下运行代码。宇宙飞船在没有起飞的情况下立即以最大速度飞行。它以恒定速度飞行,因此不需要更新速度。

我尝试了其他方法,例如将更新放入 didSimulatePhysics: .. 开启飞行模式 .. 正如 @Confused 建议的那样.. 但没有任何帮助解决这个问题。正如@crashoverride777 所说,它仍然不是 100% 完美。

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

【问题讨论】:

尝试在您的游戏中添加SKScenes didSimulatePhysics 函数并在那里添加您的limitHeight 函数,但不确定它是否会起作用。 我做到了。请参阅我的编辑。不幸的是,问题仍然存在。谢谢。 我仍在努力解决这个问题。 Apple 刚刚回复了我的错误报告,所以我将我的整个项目发送给他们。当他们再次回复我时,我会及时通知你。 【参考方案1】:

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

有两种处理方式。

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

    使用增量时间滚动您自己的调整和补偿机制,这样即使跳过一两帧,事情似乎也会继续以正确的速度移动到预期的目的地。


如果您不限于 SpriteKit,或者不需要它的物理,您可以包含另一个物理引擎并使用它。这最终意味着您可以使用 SceneKit、Core Animation 甚至 Metal 来进行渲染......或 SpriteKit

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

这里有一个将 Box2D 添加到 iOS 的教程:https://www.raywenderlich.com/2061-liquidfun-tutorial-with-metal-and-swift-part-1

这是 Chipmunk2D 的 Swift 包装器:https://github.com/jakubknejzlik/ChipmunkSwiftWrapper

【讨论】:

我试过了。即使在飞行模式下仍然存在问题。请参阅我的编辑。这似乎是精灵套件中的一个严重问题。当一个物体以恒定速度飞行时,没有线性和角度倾倒..没有重力..没有摩擦..我希望物体在飞行过程中不会结结巴巴。我在考虑你的第二点。谢谢。 SpriteKit 的物理引擎不根据增量时间校正运动的事实真的很糟糕。它似乎与帧率有关,并且每个最小的 fps 下降都可以真正看到,尤其是在匀速运动中。根据我的经验,即使游戏以 60fps 轻松运行,这种情况也会时有发生。完美解决这个问题的唯一真正解决方案似乎是根本不使用 SpriteKit 的物理引擎并自己执行所有计算或选择其他一些开源物理引擎。 是的。很遗憾。是的。好消息是……因为 SpriteKit 在 Xcode 中,等等……你可以加入 Box2D 的完整 C++ 实现,并使用你自己的访问器来访问你需要的任何东西。您也将获得性能提升。似乎 SpriteKit 的物理速度有点慢,而且集成和设置也很差。我 110% 同意。令人愤怒的是,Apple 没有做到这一点,而且 SpriteKit 是一个被忽视的、可悲的游戏套件。 @LeszekSzary 我已经转移到其他引擎,只是为了更好地访问物理。那是另一件事......暴露的物理引擎还不够多。使用 SpriteKit 做任何事情所需的所有样板都是......浪费时间。 @LeszekSzary 添加了几个在 SpriteKit 中使用其他物理引擎的选项作为答案。祝你好运!!!【参考方案2】:

我会回答我自己的问题。

飞行阶段:

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

问题:

宇宙飞船在不断的飞行过程中随机结结巴巴

这种情况下的解决方案:

由于在持续飞行过程中会出现卡顿,因此定义一个变量 (_maxReached) 来控制起飞阶段的结束。

一旦太空船达到最大高度和速度,设置_maxReached = YES

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

更新代码:

.
.
// 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];

【讨论】:

【参考方案3】:

我的游戏也遇到了同样的问题。看起来 SpriteKit 不是特别喜欢持续移动。

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

applyForce

而不是直接操纵播放器的速度属性。

当我在常规中移动播放器时,我似乎得到了最好的结果

override func update(_ currentTime: TimeInterval)  ... 

方法。

我在更新相机

override func didFinishUpdate()  ... 

在 Apple 示例游戏 DemoBots 中,他们使用相机的约束条件。约束在 DidSimulatePhysics 之后得到更新,因此 didFinishUpdate 似乎是您手动执行的最佳位置。

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

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

2)当您测试您的应用时,它处于调试模式而不是发布模式,这会降低性能。

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

请记住,您应该在完成特定测试后将其改回。您希望在测试应用时运行调试内容。

3) 确保您的绘图调用非常低。你通过确保

ignoresSiblingOrder 

在您的 GameViewController 中设置为 true,这是默认设置。

比根据它们所在的层为所有精灵提供不同的 zPosition。

例如

background = 1
sun = 2
clouds = 3
traps, obstacles, objects = 4
player = 5

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

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

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

7) 如果您要大量实例化某些节点,则将它们池化。

【讨论】:

我尝试了更多。看我的编辑。但不幸的是,没有任何帮助。正如你所说,它仍然不是 100% 完美的。我还在为这个问题而战。如果我找到解决方案,我会在这里发布。谢谢。 是的,如果您找到解决方案,请发布解决方案,我也会。

以上是关于Sprite 套件:在匀速运动过程中出现口吃的主要内容,如果未能解决你的问题,请参考以下文章

如何显示抛物线运动以及如何在 Cocos2D 中找到 Sprite 的最终位置 [关闭]

Swift Sprite Kit 相机运动

对角线运动

Sprite Kit runAction 延迟,奇怪的错误?

moveclips中如何添加sprite

雪碧套件节点在接触时结结巴巴