Flipped x-scale breaks collision handling (SpriteKit 7.1)

前端 未结 3 1862
感情败类
感情败类 2020-12-16 03:49

I use SKNode\'s xScale property to flip my sprites horizontally. Now, after updating iOS to version 7.1 horizontal flip causes my objects to sink inside the ground. (See ani

相关标签:
3条回答
  • 2020-12-16 04:35

    I'm convinced this is a bug in SpriteKit.

    Anyway, here is one solution for the problem (Actually, this is more a workaround than a real solution but...): Wrap the sprite in a container node. Also, container node holds the physicsBody while the child node is merely a graphics node. This way you can safely flip the sprite using xScale without affecting the physics of the node.

    // 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;
    }
    
    0 讨论(0)
  • 2020-12-16 04:42

    Alternative Solution

    In my case I generally subclass SKSpriteNode to represent nodes in my scene and then encapsulate their behaviour (animation and movement) in the subclass. The Wrap sprite in container node solution doesn't work in my case as I have actions that animate the sprites texture and also move the sprite in sequence.

    For example:

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

    Workaround

    In my case I solved this by adding these methods to my 'Player' class:

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

    And then override SKScene methods:

    class MyScene: SKScene{
        ...
    
        override func update(currentTime: CFTimeInterval) {
            super.update(currentTime)
            player.willSimulatePhysics()
        }
    
        override func didSimulatePhysics() {
            super.didSimulatePhysics()
            player.didSimulatePhysics()
        }
    }
    

    This works because the node flip is disabled just before physics are simulated for the scene. The node flip is then applied just before the frame is rendered.

    0 讨论(0)
  • 2020-12-16 04:44

    I encountered this problem a couple of days ago. I wanted to invert the sprite based on it's movement (right or left) and found that setting xScale disables any collisions/contacts.

    However, I used this line every time I set the xScale property and everything went back to normal.

    node.xScale = -1.0
    node.physicsBody = node.physicsBody;
    
    0 讨论(0)
提交回复
热议问题