问题
I have a node with a dynamic physics body. And I would like to make it static and change its position when it comes in contact with another body.
I managed to make the body static with the solution provided in this question: Sprite Kit failing assertion: (typeA == b2_dynamicBody || typeB == b2_dynamicBody)
However if I change the position
property of the node in one of the contact callback methods (e.g didBeginContact
) the new position is not taken into account.
How could I achieve that?
回答1:
I believe this is a bug in SpriteKit. (I was able to reproduce this problem with SpriteKit 7.1).
Here is a quick workaround:
- (void) didBeginContact:(SKPhysicsContact *)contact
{
contact.bodyB.node.position = CGPointMake(newX, newY);
contact.bodyB.node.physicsBody = contact.bodyB.node.physicsBody; // <-- Add this line
}
回答2:
JKallio's solution did not work for me (Xcode 7.2.1 on OS X 10.10.5, targeting iOS 8.1). I figured out that I was able to change the position in update:
method, so I got around the bug by setting a flag in didBeginContact
and changing the position in update:
.
@implementation GameScene {
SKNode *_victim;
CGPoint _target;
}
- (void)didMoveToView:(SKView *)view {
_victim = nil;
}
- (void)didBeginContact:(SKPhysicsContact *)contact {
_victim = contact.bodyB.node;
_target = CGPointMake(newX, newY);
}
- (void)update:(CFTimeInterval)currentTime {
if (_victim != nil) {
_victim.position = _target;
_victim = nil;
}
}
@end
Note that _victim
serves as both the node and the flag.
My solution is more complicated that JKallio's; try that one before coming for this.
回答3:
As another option for a workaround, I instead call a method in a SKSpriteNode
subclass for the object I want to move, passing in that body. The position gets set correctly.
/* In GameScene.swift */
func didBegin(_ contact: SKPhysicsContact) {
let dotBody: SKPhysicsBody
if contact.bodyA.categoryBitMask == 0b1 {
dotBody = contact.bodyB
} else {
dotBody = contact.bodyA
}
if let dot = dotBody.node as? Dot {
dot.move()
}
}
Here is the Dot class:
import SpriteKit
class Dot : SKSpriteNode {
let dotTex = SKTexture(imageNamed: "dot")
init() {
super.init(texture: dotTex, color: .clear, size: dotTex.size())
self.physicsBody = SKPhysicsBody(circleOfRadius: size.width / 2)
self.physicsBody?.categoryBitMask = 0b1 << 1
self.physicsBody?.contactTestBitMask = 0b1
}
func move() {
let reset = SKAction.run {
self.position.x = 10000
}
self.run(reset)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
来源:https://stackoverflow.com/questions/22810237/spritekit-cannot-change-node-position-in-contact-callback