SpriteKit物理引擎在不同屏幕分辨率下表现不一致

3

我正在制作一个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。这样,我可以使用一组常量设计游戏,在所有设备分辨率上都能够缩放,而不会出现剪裁或其他缩放问题。
我对这可能是什么感到相当困惑。我尝试将玩家质量和跳跃高度与屏幕缩放因子相乘,以所有可能的组合方式,但没有结果。我还试图调整物理世界的重力和速度,也没有起作用。如果有经验处理这方面问题并愿意分享的人,请帮忙一下,非常感谢!

你是否根据比例因子调整了 applyImpulseCGVector - WangYudong
@WangYudong 感谢您的快速评论!我已经尝试将PLAYER_JUMP_HEIGHT乘以屏幕比例因子了。 - kingsapo
1个回答

5
在你的问题中需要考虑几个因素,包括不同设备的不同分辨率、重力和动量。为什么要考虑动量?因为在applyImpulse:(CGVector)impulse中,impulse是一个向量,描述了添加多少动量。因此,仅仅在PLAYER_JUMP_HEIGHT上乘以一个比例因子是没有用的。
感谢这个答案,我们可以使用一个名为“像素到单位”的比率来计算需要多少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);
}

在上面的代码中,我们首先设置了常量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)];
}

这是一个关于IT技术的翻译内容。以下是需要翻译的内容:

这里有一个示例项目(已过时)sample project,您可以运行并玩它。您会发现盒子精灵实际上没有跳过红色条,而是低了一点。我认为原因是重力。

代码在几个地方进行了更新:

  1. 定义kScale宏以适应不同设备的快速测试。仅在纵向方向上起作用。

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


非常感谢您提供如此详细的答案!不幸的是,它仍然无法解决我的问题。在低分辨率的iPhone 4S上,玩家仍然会跳得很高,在iPad上则可以正常跳跃。我尝试将比例因子应用于“ptu”和“dy”,但没有帮助。重力在这个解决方案中仍然是一个问题,因为玩家在低分辨率设备上下落得更快,在iPad上则下落得更慢(以及以适当的速度)。 - kingsapo
@kingsapo 我的提示是:你只需要将比例因子应用到 PLAYER_JUMP_HEIGHT 上。 - WangYudong
1
好的,我进行了更多的测试。我成功地通过缩放因子将PLAYER_JUMP_HEIGHT乘以来使其工作。但是,我仍然在不同屏幕尺寸上存在重力不同的问题。例如,在iPhone 4S上,从屏幕轻触到着陆的整个跳跃大约需要0.6秒,而在iPad Air 2上,相同的跳跃需要大约0.9秒。我在应用了与我的项目相同的缩放技术后,在您的示例项目中复制了这个问题,这只涉及将barself.player的大小和位置乘以缩放因子。 - kingsapo
1
你具体想要什么?是在同一时间内跳不同的高度(例如,在 iPad 上跳 200 点,而在 iPhone 4s 上跳 200*0.46 点)吗? - WangYudong
1
是的,那听起来正是我想要的。 - kingsapo
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接