SpriteKit场景中出现了意外的physicsBody。

7
我正在使用SpriteKit实现一个质点弹簧系统(许多小的物理体通过SKPhysicsJointSpring相连)。在穿越场景中心时,一些粒子会被卡住。
场景中心似乎有一个小的静态物体,我不知道它为什么存在。
以下是一个简单的方法来查看我所说的问题:
1.在XCode 8中,使用“Game”模板创建一个全新的项目。 2.在GameViewController.viewDidLoad()中,添加view.showsPhysics = true 如果运行该项目,则应该在中央看到一个小点,这就是错误的物体。

enter image description here

有人知道如何消除它吗?

编辑:我尝试手动创建场景对象:

GameViewController.viewDidLoad()中,我替换了这个:

// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
    view.presentScene(scene)
}

用这个:
let scene = GameScene(size: view.frame.size)
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
view.presentScene(scene)

但那并没有解决它。
3个回答

3

无论如何,我决定写一个答案,因为评论不太适合分享我想要分享的大量信息。很遗憾,我的答案并没有回答这个问题,但它提供了一些关于这个未经确认、显然有能力飞行(物理实体)的对象的有用信息 :)

以下是代码如何抓取它(以及修改它?):

 //you can use self.frame here...I just copied Alessandro's code
 self.physicsWorld.enumerateBodies(in:(label?.frame)!) { body, stop in

    if let node = body.node {

        print("Type of this node: \(type(of:node))")    
        print("Frame of this node: \(node.frame))")

    }else{

       print("This body's node property is nil")

        body.affectedByGravity = true
        body.isDynamic = true

        body.applyImpulse(CGVector(dx: 0.003, dy: 0.0003))

    }
     print("Area covered by this node physicsBody: \(body.area)")
}

如果您在else语句中设置断点,就可以完全扫描这个物理体并获取所有关于它的信息,例如其节点属性设置为nil或者其isDynamic属性设置为false。但是您可以更改它,就像在我的代码中一样,例如将isDynamics设置为true。这使它可移动。因此,如果您对它施加一些力,它就会移动。

尽管如我在评论中所说,我不知道它为什么存在,代表什么或者其目的是什么。

此外,对于那些想知道为什么一个物理体没有与之相关联的节点(body.node等于nil),但在showsPhysics被设置为true时仍然可见的人,有一个合理的解释。物理世界与节点树是分开的。因此,我们可以从节点树中删除精灵,但这并不意味着其物理体会立即被删除。可能发生的情况是,物理引擎还没有完成模拟...这可能让你想知道,这是怎么发生的?

假设您有三个SKSpriteNode对象同时相交(比如A与B以及A与C同时接触)。SpriteKit一次只能处理一个接触。假设您在A与B接触时将A从其父节点中删除。然后,A和C之间也有接触,因此didBegin:(_ contact)将被调用两次。如果在第一个didBegin(_ contact)调用中将A从其父级中删除,在下一个didBegin(_ contact)调用中,bodyA.node将为nil(bodyA是精灵A的物理体),但其物理体仍然会保持可见状态,直到引擎完成所需操作。这是因为节点树和物理世界是分开的。


另外,作为一些额外的信息,我想补充一下,这是一个圆形的物体(显然非常小,面积等于0.000139626354211941),它在两种情况下都存在,就像OP所说的-当你从.sks文件创建一个场景时,或者使用其他SKScene初始化器创建它时。唯一的区别在于它的最终位置取决于场景的锚点,默认情况下锚点是0.0, 0.0(左下角)或0.5, 0.5(屏幕中间),这是从.sks文件加载的场景的默认anchorPoint - Whirlwind
好的,我已经解决了这个问题,但是我找不到一种方法来完全删除那个physicsBody。是的,我可以让它移动,但是改变它的categoryBitMask似乎没有任何效果,更别说让它对我添加的其他物体“不可见”了。 - PKCLsoft
所以,仅设置categoryBitMask是不够的。我还需要更改collisionBitMask。这样做相当糟糕。我会提交一个radar。 - PKCLsoft
1
我已经提交了一个雷达,并在Github上上传了一个演示项目,链接为:https://github.com/pkclsoft/TestMysteryPhysicsBody。 - PKCLsoft

2
我有一个类似的问题。我有一个由两个精灵节点(SKPhysicsJointFixed.joint)组成的游戏,它们在SKEditor创建的场景中移动。根据我的设计,这对节点将影响第三个精灵节点,并顺利地从第三个精灵节点中弹出,但当碰撞发生在场景中心时,节点对将压缩在一起,同时从第三个精灵节点中弹出,呈现出较差的图形效果。
经过长时间调试代码,我找到了这篇文章。赞扬对解释和代码的贡献。我无法回答“为什么”问题,但对于“粒子在穿越场景中心时被卡住”的问题,我的建议是清除collisionBitMask而不是移动body。
顺便说一下,当加载时categoryBitMask为0。
        //moves the problem offscreen unless it hits another node
                    //body.affectedByGravity = true
                    //body.isDynamic = true
                    //body.applyImpulse(CGVector(dx: 0.003, dy: 0.0003))
        //
        // collisionBitMask loads with 4294967295 = default value to collide with all categories
        //
                    body.collisionBitMask = 0

2

关于“hello world”xCode游戏模板,它似乎与GameScene节点相关联了一些physicsBody。通过一些代码我找到了这个:

class GameScene: SKScene {

    private var label : SKLabelNode?
    private var spinnyNode : SKShapeNode?

    override func didMove(to view: SKView) {
        ... 
        // End part of this function:
        if let b = physicsWorld.body(in: (label?.frame)!) {
            if let node = b.node {
                print("Type of this node: \(type(of:node))")
                print("Frame of this node: \(node.frame))")
            }
            print("Area covered by this node physicsBody: \(b.area)")
        }
    }
}

enter image description here

通过在最后一个大括号处设置断点,您可以看到两个主体(可能是一个主体数组),其中一个是位于左侧调试区域(具有索引1)中的physicsBody,其十六进制地址与我的代码中的b相同:0x79794f90,一个面积为4.444的小矩形主体。

Printing description of ((PKPhysicsBody *)0x79794f90):
<SKPhysicsBody> type:<Rectangle> representedObject:[<SKScene> name:'(null)' frame:{{-375, -667}, {750, 1334}} anchor:{0.5, 0.5}]
(lldb) 

enter image description here


我也怀疑GameScene.sks,但没有结果。(请参见更新的问题) - scribu
我认为这些物体可能是未来“hello world”模板中展示物理的实现方式,但我不确定。正如你所看到的,有两个物体。 - Alessandro Ornano
感谢您帮助诊断,但这并没有真正回答为什么会有这些物体或如何移除它们的问题。这似乎是SpriteKit本身的问题,而不是XCode模板的问题。 - scribu
不客气,无论如何似乎你无法将它们删除。我同意你的看法。 - Alessandro Ornano
@scribu 你可以“删除”它,但问题是为什么它在那里,它的目的是什么。经过 Alessandro 和我的一些测试,发现这个 body 默认情况下其 isDynamic 属性设置为 false。但你可以抓住它并改变它 :) 你还可以对它施加一个冲量,看看它如何飞出屏幕 lol :) 我可以给你发布这样做的代码。 - Whirlwind
3
我猜测这个小物体是用来保持物理系统处于“唤醒”状态的。在SpriteKit中管理音频/声音和AVFoundation中的语音合成需要使用这些技巧来保持它们处于唤醒状态并且存在于内存中。可能是因为苹果在iOS上采用了激进的内存和/或资源管理策略。 - Confused

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