scribu
scribu

Reputation: 3078

Unexpected physicsBody in SpriteKit scene

I'm implementing a mass-spring system (many small physics bodies joined together with SKPhysicsJointSpring instances) with SpriteKit. Some of the particles would get snagged while traversing the center of the scene.

There seems to be a small, static body in the middle of the scene and I don't know why it's there.

Here's an easy way to see what I'm talking about:

  1. In XCode 8, create a brand new project with the "Game" template.
  2. In GameViewController.viewDidLoad(), add view.showsPhysics = true

If you run the project, you should see a little dot in the middle, which is the errant body:

enter image description here

Anyone know how to get rid of it?

Edit: I tried to manually create the scene object:

In GameViewController.viewDidLoad(), I replaced this:

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

with this:

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

but that didn't fix it.

Upvotes: 8

Views: 681

Answers (3)

BillMHourly
BillMHourly

Reputation: 31

I had a similar problem. I have a game with two sprite nodes joined together (SKPhysicsJointFixed.joint) moving around an SKEditor created scene. As per my design, this node-pair would impact a third sprite node and be propelled smoothly away from the third sprite node, EXCEPT when the impact was in the center of the scene. For the center of the scene impact, the node-pair would compress together while be propelled away from the third sprite node, presenting a poor graphical image.

After significant time debugging my code, I found this post. Kudos for the explanations and code. I can’t answer the “why” question but for the “particles would get snagged while traversing the center of the scene” question my suggested solution is to clear the collisionBitMask instead of moving the body.

BTW categoryBitMask is 0 when loaded.

        //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

Upvotes: 3

Whirlwind
Whirlwind

Reputation: 13675

Anyways, I decided to make an answer because comments are not suitable due to lot of info I want to share. Also my answer, sadly, doesn't answer the question but it gives some useful info about this unidentified, obviously capable of flying (physics body) object :)

So this is the code how to grab it (and modify it???):

 //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)")
}

So if you put a break point inside of that else statement, you can scan this physics body completely and get all the info about it, like that its node property is set to nil or that its isDynamic property is set to false. But you can change that, and like in my code, set for example isDynamics to true. This makes it moveable. So if you apply some forces to it, it will move.

Still, like I said in comments, I don't have an idea why it is there and what it represents or what is its purpose.

Also, for those who are wondering how it is possible that one physics body doesn't have a node associated with it ( body.node equals nil) but is still visible on screen when showsPhysics is set to true, there is a reasonable explanation. Physics world is separated from the node tree. So we can remove a sprite from a node tree, but that doesn't mean that its physics body will be removed instantly. It may happen that physics engine haven't finished simulation... So you probably wonder, how this might happen?

Let say you have three SKSpriteNode objects intersecting at the same time (say A contacts B and A contacts C at the same time). SpriteKit can process only one contact at time. And say that you are removing A from a parent when it is contacting with B. Then, there is a contact between A and C also, so didBegin:(_ contact) will be called twice. And if you remove A from its parent in first didBegin(_ contact) call, in the next didBegin(_ contact) call, bodyA.node will be nil (bodyA is a physics body of sprite A), but its physics body will remain visible until engine finishes what needed. This is because node tree and a physics world are separated.

Upvotes: 4

Alessandro Ornano
Alessandro Ornano

Reputation: 35402

About the "hello world" xCode game template , it seems a little physicsBody associated to the GameScene node. With some code I've found this:

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

With a breakpoint to the last brace, you can see two bodies (maybe an array of bodies), one of them is the physicsBody to the left debugArea (array with index 1) with the same hex address as my body b in my code : 0x79794f90, a little rectangle body with area 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

Upvotes: 3

Related Questions