多层中的 SpriteKit 物理实体碰撞

Posted

技术标签:

【中文标题】多层中的 SpriteKit 物理实体碰撞【英文标题】:SpriteKit Physics Bodies Collisions in Multiple Layers 【发布时间】:2014-12-16 02:36:13 【问题描述】:

好的,所以我正在为太空爆破游戏编写代码,而且除了这些关键问题之外,一切似乎都很顺利。

首先,我添加了一艘宇宙飞船(带有 PhysicsBody)作为 self 的子节点(GameScene)。

然后我添加了一个背景层作为节点,也作为 self 的子节点,在飞船后面,并通过操纵杆控制在飞船后面移动背景来模拟运动。

我添加了一个带有边界物理 Edge Loop 主体的节点,这样背景就不会超出船,并将该节点添加为 bgLayer 的子节点。

我有宇宙飞船要射击的物体,但我希望它们像背景一样移动,所以我将它们添加为 bgLayer 的子对象。

当然,飞船开火时我需要激光,所以我添加了这个以及 bgLayer 的一个子节点。


_spaceship.physicsBody = (custom physicsBody code);
[self addChild:_spaceship];

_bgLayer = [SKNode node];
[self addChild:_bgLayer];

_bounds = [SKNode node]; 
_bounds.physicsBody = (physicsBody edgeLoop code);
[_bgLayer addChild:_bounds];

_otherObjects.physicsBody = (custom physicsBody code);
[_bgLayer addChild:_otherObjects];

_laser.physicsBody = (custom physicsBody code);
[_bgLayer addChild:_laser];

一切都很好,背景没有移动到飞船之外,其他物体随着背景的移动而移动,并且激光在被召唤时会发射。

我的第一个大难题是当我的激光发射时,它不会随着背景的移动而移动,而是背景在它后面移动。我可能会凑合,但如果激光总是与船平行移动,那看起来很有趣。这对我来说似乎很奇怪,因为我将激光添加为 _bgLayer 的子项。

其次,我的激光器的physicsBody 似乎无法识别EdgeLoop 体,而是直接穿过它。此外,我的宇宙飞船的physicsBody 似乎可以识别EdgeLoop 主体,但它不能识别其他属于_bgLayer 子对象的对象。

不是同一层子级的物理实体是否可以相互识别? 为什么我的激光与同一层的其他子激光的行为不同?

【问题讨论】:

物理引擎中没有层。每个场景有一个物理世界。您只需要设置碰撞类别之类的东西,并确保设置所有定义对象是否以及如何参与物理的东西。 我很抱歉没有在我的编码示例中添加这个,但我确实为它们设置了类别和碰撞位掩码,但激光似乎忽略了这些设置。 【参考方案1】:

通过改变位置来移动世界会影响

    拥有物理身体的孩子 没有物理身体的孩子

通过施加力/脉冲或通过设置其速度来移动世界

    没有物理身体的孩子

除了通过设置速度来移动世界,您可以向世界添加一个相机(带有物理体的SKNode),通过设置速度来移动相机,然后将世界的位置更新为中心相机。您可以在didFinishUpdate 方法中将相机居中。

【讨论】:

我很抱歉没有在我的编码示例中添加这个,但我确实使用 setVelocity 方法设置了激光。我的激光确实与我提到的其他物体相互作用,但与 edgeLoop 没有相互作用。你最后的评论让我很感兴趣。我可以简单地从激光矢量的 dx 和 dy 中减去背景矢量的 dx 和 dy 吗? 实际上,如果将激光添加到世界节点,它应该可以适当移动而无需任何调整。 我也是这么想的。但是,它仍然相对于场景而不是 _bgLayer 节点移动。 激光是子弹还是光流(即线)?我已经用子弹实现了滚动背景,当我滚动背景图像时,子弹会正确移动。例如,如果我向背景图像中的目标射击,无论我滚动多少背景,子弹都会朝着该目标移动。 它更像是一颗子弹。给我一分钟,我会发布我的激光代码。【参考方案2】:
-(void)fireLaser

    _laser = [SKSpriteNode spriteNodeWithImageNamed: [NSString stringWithFormat:@"blueLaser"]];;
    _laser.zRotation = _spaceShip.zRotation;
    CGVector rotationVector = RadiansToVector(_spaceShip.zRotation);
    _laser.position = (Custom code for positioning the laser just in front of the spaceship);

    _laser.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_laser.size];
    [_bgLayer addChild:_laser];

    _laser.physicsBody.velocity = CGVectorMake(rotationVector.dx * LASER_SPEED, rotationVector.dy * LASER_SPEED);  

[self fireLaser] 在触摸特定 SpriteNode 时在 touchesBegan 中调用。 激光发射得很漂亮,但不会随着背景滚动,而是相对于宇宙飞船移动。使用 PhysicsBody 滚动背景,当操纵杆移动时调用 setVelocity 方法,从而模拟宇宙飞船的运动,而实际上宇宙飞船永远不会离开屏幕的中心。物理类别可防止背景物理主体与任何物体发生碰撞。 LASER_SPEED 只是一个静态常量浮点数。

【讨论】:

以上是关于多层中的 SpriteKit 物理实体碰撞的主要内容,如果未能解决你的问题,请参考以下文章

SpriteKit物理引擎碰撞中5个重要信息

SPRITEKIT游戏框架之关于PHYSICS物理引擎属性

Swift SpriteKit 基本接触/碰撞

低 SpriteKit FPS 会导致碰撞丢失?

Sprite Kit 碰撞检测和物理

Swift SpriteKit 从图像的纹理中制作物理体会大大降低我的应用程序的速度