SpriteKit物理在不同的屏幕分辨率上不一致

时间:2015-10-04 07:53:56

标签: ios objective-c sprite-kit game-physics screen-resolution

我在使用SpriteKit游戏时遇到了一些问题。我试图做一个平台游戏风格的游戏,玩家在屏幕上点击以使角色跳跃。我实现了这个目标:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    // reset the velocity each jump, so that a constant impulse is always applied
    self.player.physicsBody.velocity = CGVectorMake(0, 0);       

    // jump the player up
    [self.player.physicsBody applyImpulse:CGVectorMake(0, PLAYER_JUMP_HEIGHT)];
}

PLAYER_JUMP_HEIGHT只是一个常数。我还设置了恒定质量的播放器。

这在iPad模拟器上运行得非常好,这是我进行大量初始测试的地方。然而,在调整我的代码以扩展设备分辨率(对于手机等)之后,看来我的物理现在非常关闭,特别是在iPhone 4S模拟器上。同样的冲动现在让玩家跳得很高,而且它们似乎也比较平稳地脱离平台等物体,更像是线性曲线。

我通过首先设置场景的缩放模式来缩放我的场景以容纳多个设备:

scene.scaleMode = SKSceneScaleModeResizeFill;

我还想出了一种方法,通过将当前设备的分辨率与iPad的分辨率进行比较来扩展游戏中的所有其他内容,然后进行划分以获得比例因子以将所有内容相乘。因此,在iPad屏幕宽度为2048的情况下,如果我在iPhone 4S上运行,则比例因子将是960/2048 = 0.46。通过这种方式,我可以使用一组可以在所有设备分辨率上缩放的常量来设计游戏,而不会出现其他缩放模式的裁剪或其他缩放问题。

我对这可能是什么感到非常难过。我尝试将玩家质量和跳跃高度乘以屏幕比例因子,在所有可能的组合中,都无济于事。我也试过搞乱物理世界的引力和速度,这也没有用。如果有人有处理这个问题的经验并且愿意分享,那么任何帮助将不胜感激。谢谢!

1 个答案:

答案 0 :(得分:4)

您的问题需要考虑几个因素,包括不同设备的不同分辨率,重力和动量。为何动力?因为在applyImpulse:(CGVector)impulse中,impulse是一个向量,用于描述添加了多少动量。因此,简单地将PLAYER_JUMP_HEIGHT上的比例因子相乘是没有用的。

感谢this answer,我们可以使用名为“像素到单位”的比率来计算制作脉冲矢量所需的dy

以下是解释如何让玩家跳转到常数PLAYER_JUMP_HEIGHT。您可能希望自己根据不同的分辨率调整它,这次您的比例因子应该有效。

#define kScale ([[UIScreen mainScreen] bounds].size.height) / 1024.0
const CGFloat PLAYER_JUMP_HEIGHT = 200.0;

- (void)didMoveToView:(SKView *)view
{
    self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];

    // Print useful info
    NSLog(@"scale: %.3f", kScale);
    NSLog(@"total height: %.1f", self.frame.size.height);
    NSLog(@"jump height: %.1f%%", kScale * PLAYER_JUMP_HEIGHT / self.frame.size.height * 100);

    // Let player jump over the bar
    SKSpriteNode *bar = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(CGRectGetMaxY(self.frame), 1.0)];
    bar.position = CGPointMake(CGRectGetMidX(self.frame), PLAYER_JUMP_HEIGHT * kScale);
    [self addChild:bar];

    self.player = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(kScale * 50.0, kScale * 50.0)];
    self.player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(kScale * 50.0, kScale * 50.0)];
    self.player.physicsBody.mass = 0.25;
    self.player.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)/5.0);
    [self addChild:self.player];

    // Pixel to unit
    ptu = 1.0 / sqrt([SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(1.0, 1.0)].mass);
}

在上面的代码中,我们首先设置const PLAYER_JUMP_HEIGHT,一个条表示屏幕上有200个点有多高,player和比率ptu

然后计算dy并将其应用于冲动:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // reset the velocity each jump, so that a constant impulse is always applied
    self.player.physicsBody.velocity = CGVectorMake(0, 0);
    self.physicsWorld.gravity = CGVectorMake(0, kScale * (-9.8));

    // jump the player up
    CGFloat dy = self.player.physicsBody.mass * sqrt(2 * (-self.physicsWorld.gravity.dy) * (kScale * PLAYER_JUMP_HEIGHT * ptu));

    [self.player.physicsBody applyImpulse:CGVectorMake(0, dy)];
}

这是演示,运行和播放的sample project过时)。你会发现盒子精灵实际上没有跳过红色条但略低一点。我认为原因在于引力。

在多个地方更新了代码:

  1. 为不同设备定义kScale宏以进行快速测试。仅适用于纵向。

  2. 在需要的地方添加kScale(跳跃高度,玩家大小和重力!)。它现在应该以相同的速度跳跃自适应高度。