8

我使用 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;
}

x-scale 翻转问题

4

3 回答 3

12

我确信这是 SpriteKit 中的一个错误。

无论如何,这是解决问题的一种方法(实际上,这更像是一种解决方法,而不是真正的解决方案,但是......):将精灵包装在容器节点中。此外,容器节点包含物理体,而子节点只是一个图形节点。这样,您可以使用 xScale 安全地翻转 sprite,而不会影响节点的物理特性。

// 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;
}
于 2014-03-17T14:13:10.303 回答
6

几天前我遇到了这个问题。我想根据精灵的运动(向右或向左)反转精灵,并发现设置 xScale 会禁用任何碰撞/接触。

但是,我每次设置 xScale 属性时都使用这条线,一切都恢复正常。

node.xScale = -1.0
node.physicsBody = node.physicsBody;
于 2014-03-28T06:52:33.567 回答
0

替代解决方案

在我的情况下,我通常将 SKSpriteNode 子类化以表示场景中的节点,然后将它们的行为(动画和运动)封装在子类中。容器节点中的Wrap sprite解决方案在我的情况下不起作用,因为我有一些动作可以为 sprite 纹理设置动画并按顺序移动 sprite。

例如:

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

解决方法

在我的情况下,我通过将这些方法添加到我的“播放器”类来解决这个问题:

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

这是因为在为场景模拟物理之前禁用了节点翻转。然后在渲染帧之前应用节点翻转。

于 2015-03-17T11:53:10.363 回答