Перевернутая x-scale прерывает обработку столкновений (SpriteKit 7.1)
Я использую свойство SKNode xScale, чтобы перевернуть мои спрайты по горизонтали. Теперь, после обновления iOS до версии 7.1 горизонтальное отражение заставляет мои объекты тонуть в земле. (Смотрите анимацию ниже). Проблема возникает только со свойством xScale. Вертикальные сальто работают нормально.
// Init
{
SKSpriteNode* ground = [SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:CGSizeMake(winSize.width, 150)];
ground.position = CGPointMake(winSize.width/2, ground.size.height/2);
ground.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:ground.size center:CGPointZero];
ground.physicsBody.dynamic = NO;
ground.physicsBody.categoryBitMask = 0x01;
ground.physicsBody.collisionBitMask = 0x02;
ground.physicsBody.contactTestBitMask = 0x02;
[self.world addChild:ground];
SKSpriteNode* turtle = [SKSpriteNode spriteNodeWithImageNamed:@"turtle.png"];
turtle.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:turtle.size.width/2];
turtle.physicsBody.categoryBitMask = 0x02;
turtle.physicsBody.collisionBitMask = 0x01;
turtle.physicsBody.contactTestBitMask = 0x01;
turtle.position = CGPointMake(winSize.width/2, winSize.height/2);
[self.world addChild:turtle];
self.turtle = turtle;
}
// Somewhere else
{
self.turtle.xScale *= -1;
}
3 ответа
Я убежден, что это ошибка в SpriteKit.
В любом случае, вот одно решение проблемы (на самом деле, это скорее обходной путь, чем реальное решение, но...): оберните спрайт в контейнерный узел. Кроме того, контейнерный узел хранит physBody, в то время как дочерний узел является просто графическим узлом. Таким образом, вы можете безопасно переворачивать спрайт с помощью xScale, не влияя на физику узла.
// Init
{
SKSpriteNode* turtleSprite = [SKSpriteNode spriteNodeWithImageNamed:@"turtle.png"];
self.turtleSprite = turtleSprite;
SKNode* turtleWrapper = [SKNode node];
turtleWrapper.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:turtleSprite.size.width/2];
turtleWrapper.physicsBody.categoryBitMask = 2;
turtleWrapper.physicsBody.collisionBitMask = 1;
turtleWrapper.physicsBody.contactTestBitMask = 1;
[turtleWrapper addChild:turtleSprite];
[self.world addChild:turtleWrapper];
}
// Elsewhere
{
self.turtleSprite.xScale *= -1;
}
Я столкнулся с этой проблемой пару дней назад. Я хотел инвертировать спрайт в зависимости от его движения (вправо или влево) и обнаружил, что настройка xScale отключает любые столкновения / контакты.
Однако я использовал эту строку каждый раз, когда устанавливал свойство xScale, и все возвращалось в норму.
node.xScale = -1.0
node.physicsBody = node.physicsBody;
Альтернативное решение
В моем случае я обычно создаю подкласс SKSpriteNode для представления узлов в моей сцене, а затем инкапсулирую их поведение (анимацию и движение) в подклассе. Решение " Обтекание спрайта в контейнерном узле" не работает в моем случае, так как у меня есть действия, которые анимируют текстуру спрайтов, а также перемещают спрайт по очереди.
Например:
class Player: SKSpriteNode{
override init() {
...
super.init(texture: texture, color: nil, size: texture.size())
physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(70,75))
}
func attack(){
let action = SKAction.sequence([
SKAction.moveTo(enemyPosition, duration: 0),
SKAction.animateWithTextures(frames, timePerFrame: 0.5)
])
runAction(action)
}
}
Временное решение
В моем случае я решил эту проблему, добавив эти методы в мой класс Player:
class Player: SKSpriteNode{
private var flipped: Bool
...
func flip(){
flipped = !flipped
position = CGPointMake(-position.x, position.y)
}
//MARK: Workaround for iOS7 -xScale physics bugs
func willSimulatePhysics(){
xScale = 1
}
func didSimulatePhysics(){
xScale = flipped ? -1 : 1
}
}
А затем переопределите методы SKScene:
class MyScene: SKScene{
...
override func update(currentTime: CFTimeInterval) {
super.update(currentTime)
player.willSimulatePhysics()
}
override func didSimulatePhysics() {
super.didSimulatePhysics()
player.didSimulatePhysics()
}
}
Это работает, потому что переворот узла отключен непосредственно перед симуляцией физики для сцены. Отражение узла затем применяется непосредственно перед визуализацией кадра.