Unexpected physicsBody in SpriteKit scene - ios

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:
In XCode 8, create a brand new project with the "Game" template.
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:
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.

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.

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

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

Related

Is there a simple way to temporarily disable the physics bodies for a sprite in Swift? (SpriteKit)

I'm making a maze app, that generates a new maze after one is completed. Obviously, I can turn the walls (each having their own physics and sprite stored in their spot on an array) invisible by doing what I did in my code wall[location].isHidden = true ,but I couldn't find a way to do the same with the physics body bound to the wall, creating an invisible wall. Is there a simple way to do that without setting it to nil?
Just to clarify, it's not that I don't want it to be dynamic, I just want the entire thing to not exist while that maze is being solved.
Also the only reason I wouldn't want to set it to nil is because I don't know how to restore its old physics body in an easy way.
The preferred way would be to physically remove your wall from your node tree. This will increase performance since the system does not have to check unnecessary nodes.
Just make sure that your wall is being retained when you remove it so that you can readd it when needed.
wall[location].removeFromParent()
...
scene.addChild(wall[location])
Sure
just set
isDynamic = false
wall.physicsBody?.collisionBitMask = 0
wall.physicsBody?.contactTestBitMask = 0
This pretty much isolates the SKPhysicsBody from the rest of the system. Do you have any SKJoints connected to your nodes with the bodies ? This can be awkward if you do.
or you can set it to nil
wall.physicsBody? = nil
then just make a method to set it again when your ready
func addPhysics() {
wall.physicsBody = SKPhysicsBody(circleOfRadius: 5)
wall.isDynamic = true
wall.physicsBody?.collisionBitMask = whatever
wall.physicsBody?.collisionBitMask = whatever
wall.physicsBody?.contactTestBitMask = whatever
}
If you do set to nil and then restore it make sure you do this at either the start or the end of the gameLoop.
In either of these override methods in the gameScene
override func update(_ currentTime: TimeInterval) {
}
override func didFinishUpdate() {
}
Hope this helps
You already have an answer, but another approach might be to subclass SKSpriteNode with one extra property called inactivePhysicsBody (or similar) which is an 'SKPhysicsBody'.
When you want to 'turn off' the physics for that node, set the inactivePhysicsBody property to physicsBody and then set physicsBody to nil. You can then easily restore the physics body when necessary.
Or you could add methods to the new class to do the same:
wall.activatePhysicsBody()
wall.inactPhysicsBody()
Give the object that owns the sprite an 'extra' reference to the sprite's physics body, e.g.:
init(sprite: SKSpriteNode) {
self.sprite = sprite
self.physicsBody = sprite.physicsBody
super.init()
}
Then you can set self.sprite.physicsBody to either self.physicsBody or nil to turn the object's physics on / off. Personally I'd avoid subclassing here but YMMV.

Designing complex objects with SpriteKit Scene Editor

Near as I can tell, there isn’t a way to add physics joints in the scene editor. Is that right?
Consider a simple person object with a body, child legs and arms w/ pin joints. If I want to design this person in the scene editor and then programmatically add him to a scene, I’m not getting very far. I’m able to find the nodes in the scene, remove them from their parent and add them as a child at a new position in my scene, but I still have to specify all their joints manually.
Thoughts?
Here is my solution. I'm still hoping there is a way to create physics joints with the scene editor but I haven't found it so...
Step 1) Add all the child nodes to the scene, ensuring that objects are grouped by parent.
Step 2) Define a swift class for your complex node.
class MyNode : SKSpriteNode {
func spawn(parentNode: SKNode, position: CGPoint) {
parentNode.addChild(self) // before physics joints
let arm = self.childNode(withName:"arm")
// note if you didn't add physics bodies in scene file
// do that first
let shoulders = SKPhysicsJointPin.joint(withBodyA:self.physicsBody!, bodyB: arm.physicsBody!, anchor: CGPoint(x:position.x,y:position.y-1))
scene!.physicsWorld.add(shoulders)
// feature of pulling a child from a scene, it's always paused by default.
self.isPaused = false
}
}
Set the class for your body node in your scene.
Step 3) Transfer your node to your game scene at init time.
let tmpScene = SKScene.init(fileNamed: "MyNode.sks")
var myNode = tmpScene.childNamed(withName:"myNode") as! MyNode
myNode.removeFromParent()
myNode.spawn(world, position) // or your own parent and position as needed for your scene

Sprite Kit - Creating node from didBeginContact()

I am using a custom brick class:
import SpriteKit
class Brick: SKSpriteNode {
enum type { case Normal }
convenience init (type: Brick.type) {
self.init(color: .greenColor(), size: CGSizeMake(75, 25))
physicsBody.SKPhysicsBody(rectangleOfSize: size)
physicsBody!.mass = 9999
physicsBody!.affectedByGravity = false
position = CGPointMake(100, 50)
// Category and collision bitmasks ...
// Action to move the brick upwards ...
}
// Stuff
}
In my scene, I'm creating one initial brick, and everything works just fine. However, when I try to add a brick in the didBeginContact() function, I get unexpected results.
I have a SKNode at 1/5 height of the screen. So everytime a brick reaches that height, it will make contact with this invisible node and create a new brick:
// Inside SKScene
func didBeginContact(contact: SKPhysicsContact) {
// I set physics body A and B ...
if a.categoryBitMask == Category.brick && b.categoryBitMask == Category.brickSpawner {
addChild(Brick(type: .Normal))
}
}
So the problem is: when I create a new brick inside this function, the position is set to (0, 0) instead of (100, 50) as defined in the Brick class. Actually, if I go ahead and use println(brick.position) I get (100, 50), but in the screen it looks positioned at (0, 0).
If I create a brick anywhere else in the code, for example in the touchesBegan() or update() functions, the position is set correctly. This problem only happens when creating the node from didBeginContact().
This should help, it explains the steps in a single frame.
https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Introduction/Introduction.html
You are creating it at the wrong time, so one of the steps behind the scenes is resetting it due to a few steps being missing. Queue that process up for the didFinishUpdate command. ( I would just create the object in the did contact, then throw it into an array, then on didFinishUpdate, go through the array and add them to the scene, and clear the array)

Affecting a Child From Another Scene Using Sprite Kit and Swift

I'm trying to teach myself Sprite Kit and Swift. What I'm trying to do is access a child node from an ArcheryScene.sks file and affect that child from the ArcheryScene.swift file. For Example: In my ArcheryScene.swift file I have added this line of code: let scene = SKScene(fileNamed: "ArcheryScene").
This compiles fine and when I say println(scene), it correctly prints the scene I want it to print, this is how I know that ArcheryScene.sks is truly in my scene variable. After this, I access a child from that scene by adding this line of code: let ballChild = scene.childNodeWithName("Ball"). When I use println(ballChild), it prints the correct child, letting me know that the variable truly contains Ball child that is in ArcheryScene.sks. And now to my problem...
Why can't I say things in my ArcheryScene.swift file like:
ballChild?.physicsBody?.affectedByGravity = false
or
ballChild?.position.x = self.frame.size.width / 2
or
let move = SKAction.moveByX(40, y: 0, duration: 5.0)
ballChild?.runAction(move)
All of this code will compile without errors but when I run the game, the Ball is not affected at all. Also, if I run ballChild?.position.x = self.frame.size.width / 2 and then print the ballChild position, it will show up as x: 512, which is what it should be, but still when I run the game, the Ball is not affected. This is really confusing to me and I'd just like to figure out what is going on. Any suggestions would be appreciated, thank you.
If you look at the definition of Class ArcheryScene you will see it is a subclass of SKScene - so the class you are coding in is already your scene. The UIViewController subclass in your project has loaded ArcheryScene.sks and associated it with an instance of ArcheryScene.
When you subsequently say let scene=SKScene(fileName:"ArcheryScene.sks") you are actually creating a new instance of the scene that isn't presented into your SKView. You then modify the ball in that scene, but nothing happens as this is not the ball that is visible.
Instead you should say
let ballChild=self.childNodeWithName("Ball")
if (ballChild? != nil) {
let move=SKAction.moveByX(50 y:10 duration:10.0)
ballChild!.runAction(move)
}
When you write your following line :
let scene = SKScene(fileNamed: "ArcherySceneSKS")
You are creating a new scene. So the ballChild you are accessing is another one (not the one inside your self (ArcheryScene class)).
If you ArcheryScene class is properly instantiated, can't you access the ball by doing like so ?
let ballChild = self.childNodeWithName("Ball")
Let me know if it helped.

SpriteKit: detect complete node overlap

I have two SKShapeNodes – one with an edge-based SKPhysicsBody, one volume-based – and I want to detect their intersection without collision. I've got this working fine, with the SKPhysicsContactDelegate contact methods getting called as one passes over another, but my issue is that didEndContact gets called when the edges no longer intersect, even when one body is completely contained within the other. What's the best way to determine true contact or overlap, not just edge intersection? I've tried usesPreciseCollisionDetection, to no avail.
CGPoint locObj1 = [sprite1 locationInNode:self];
CGPoint locObj2 = [sprite2 locationInNode:self];
if([sprite1 containsPoint: locObj2]) return;
if([sprite2 containsPoint: locObj1]) return;
Add this to the beginning of didBeginContact and didEndContact. This checks to see if one of the nodes contains the other node. If it does, it does nothing which will alleviate your issue of didBeginContact and didEndContact being unessesarily called. I am not on my mac so you may need to play with the syntax a bit. Hope this sends you in the right direction.
As meisenman suggested, it looks like the best way to do this is using the containsPoint method to determine true node overlap. The docs state that this "returns a Boolean value that indicates whether a point lies inside the node's bounding box", but in my experimentation it looks like this works for concave edge-based shapes as well.
So if I want to detect when two objects no longer overlap, it makes sense to do a containsPoint check within didEndContact – but it turns out didEndContact gets called when each edge is no longer intersected, even if another edge of the same shape still intersects the same object. For example, a ball exiting a rectangle through its corner will yield two didEndContact events. Therefore, it's necessary to keep an absolute count of contact events (the difference between begin and end), and only test for containment when this count is zero.
My solution, in Swift:
var _contactCount = 0
func didBeginContact(contact: SKPhysicsContact!) {
if ((contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask) == (CATEGORY_ONE | CATEGORY_TWO)) {
if (_contactCount == 0) {
// Contact is actually beginning
}
_contactCount += 1
}
}
func didEndContact(contact: SKPhysicsContact!) {
if ((contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask) == (CATEGORY_ONE | CATEGORY_TWO)) {
_contactCount -= 1
let overlap = contact.bodyA.node.containsPoint(contact.bodyB.node.position) || contact.bodyB.node.containsPoint(contact.bodyA.node.position)
if (!overlap && _contactCount == 0) {
// Contact is actually ending
}
}
}
These are my thoughts on #meisenman example for swift 3. Instead of collision detection through masks, let's say we wanted to to know if an node is inside a node. With #meisenman, the location of the node is being used for each.
This following image is what we actually what I want done.
The code #meisenman uses does not require SKPhysics. Here is the code in Swift 3.0
let Object_1: CGPoint! = Sprite_Object_1.position
//this obtains the location of the sprite node, through CGPoint.
if Object_Sprite_2.contains(Object_1){
print("Then it is true, object 2 is within the location of object 1")
}
The only limitations that I have found are that if the center of these nodes are not within the body of the desired node, then this if statement will not be true. This has not been tested by setting the node's body defination (mask).
What I like, is having the ability to use this if statement throughout different functions or overide fuctions, this is not limited to only 'did begin' or 'touches moved.'

Resources