SpriteKit 设备方向改变导致 SKLabelNode 失真 Swift

SpriteKit device orientation change causes SKLabelNode distortion Swift

我正在使用 SpriteKit 为 Swift 中的 iOS 编写游戏。我对 SpriteKit 还是很陌生。

我想支持 iPhone 和 iPad 的两种方向,并发现:

这在模拟器和设备中按预期工作,但是在设备上我注意到一些 SKSpriteNodes 在设备旋转动画之前稍微扭曲到它们的新大小。

这非常明显,尤其是对于 SKLabelNodes,其中文本会根据方向的变化而扭曲或轻微压扁或拉伸。

我知道为什么会发生失真,但确认和修复会很棒。

这发生在使用 link 中描述的代码的设备上,但我已针对 swift 3

进行了更新
class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let scene = GameScene(size:self.view.bounds.size)
        scene.scaleMode = .resizeFill
        (self.view as! SKView).presentScene(scene)
    }

    override var shouldAutorotate: Bool {
        return true
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return .allButUpsideDown
        } else {
            return .all
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
    }

    override var prefersStatusBarHidden: Bool {
        return true
    }
}

class GameScene: SKScene {
    var currentNode: CustomNode!

    override func didMove(to view: SKView) {
        self.backgroundColor = SKColor.white
        transitionToScene(sceneType: .Menu)
    }
    override func didChangeSize(_ oldSize: CGSize) {
        currentNode?.layout()
    }
    func transitionToScene(sceneType: SceneTransition) {
        switch sceneType {
        case .Menu:
            currentNode?.dismissWithAnimation(animation: .Right)
            currentNode = MenuNode(gameScene: self)
            currentNode.presentWithAnimation(animation: .Right)

        case .Scores:
            currentNode?.dismissWithAnimation(animation: .Left)
            currentNode = ScoresNode(gameScene: self)
            currentNode.presentWithAnimation(animation: .Left)

        default: fatalError("Unknown scene transition.")
        }
    }
}

class CustomNode: SKNode {
    weak var gameScene: GameScene!

    init(gameScene: GameScene) {
        self.gameScene = gameScene
        super.init()
    }
    func layout() {}
    func presentWithAnimation(animation:Animation) {
        layout()
        let invert: CGFloat = animation == .Left ? 1 : -1
        self.position = CGPoint(x: invert*gameScene.size.width, y: 0)
        gameScene.addChild(self)
        let action = SKAction.move(to: CGPoint(x: 0, y: 0), duration: 0.3)
        action.timingMode = SKActionTimingMode.easeInEaseOut
        self.run(action)
    }
    func dismissWithAnimation(animation:Animation) {
        let invert: CGFloat = animation == .Left ? 1 : -1
        self.position = CGPoint(x: 0, y: 0)
        let action = SKAction.move(to: CGPoint(x: invert*(-gameScene.size.width), y: 0), duration: 0.3)
        action.timingMode = SKActionTimingMode.easeInEaseOut
        self.run(action, completion: {self.removeFromParent()})
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


class MenuNode: CustomNode {
    var label: SKLabelNode
    var container: SKSpriteNode

    override func layout() {
        container.position = CGPoint(x: gameScene.size.width/2.0, y: gameScene.size.height/2.0)
    }
    override init(gameScene: GameScene) {
        label = SKLabelNode(text: "Menu Scene")
        label.horizontalAlignmentMode = .center
        label.verticalAlignmentMode = .center
        container = SKSpriteNode(color: UIColor.black, size: CGSize(width: 200, height: 200))
        container.addChild(label)
        super.init(gameScene: gameScene)
        self.addChild(container)
        self.isUserInteractionEnabled = true
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.gameScene.transitionToScene(sceneType: .Scores)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class ScoresNode: CustomNode {
    var label: SKLabelNode
    var container: SKSpriteNode

    override func layout() {
        container.position = CGPoint(x: gameScene.size.width/2.0, y: gameScene.size.height/2.0)
    }
    override init(gameScene: GameScene) {
        label = SKLabelNode(text: "Scores Scene")
        label.horizontalAlignmentMode = .center
        label.verticalAlignmentMode = .center
        container = SKSpriteNode(color: UIColor.black, size: CGSize(width: 200, height: 200))
        container.addChild(label)
        super.init(gameScene: gameScene)
        self.addChild(container)
        self.isUserInteractionEnabled = true
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.gameScene.transitionToScene(sceneType: .Menu)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

enum SceneTransition{
    case Menu, Scores
}
enum Animation {
    case Left, Right, None
}

信用:Epic Byte

我也试过使用

viewWillTransitionToSize...

因为它处理设备方向变化,我看到 didChangeSize... 在设备旋转中被多次调用,因此我更喜欢 viewWillTransitionToSize...

提前致谢。

里昂

进入你的 Storyboard 文件,Select 你的 ViewController 视图,然后在右侧栏中查找滑块图像,它应该是从左数第 4 个。这称为属性检查器。将内容模式更改为居中。这会给你黑条,但停止挤压。

这是根据@Knight0fDragon 的建议创建的代码,生成的 SKLabelNode 在使用 scaleMode .resizeFill 旋转时不会挤压或拉伸。请注意,此处视图的大小适用于分辨率为 1024x768 的 iPad,创建大小为 1024x1024 的正方形 skview。当应用程序根据方向加载时,这很容易用最大值(宽度或高度)进行复制。

class GameViewController: UIViewController {

var scene : GameScene!
var newView: SKView!

override func viewDidLoad() {
    super.viewDidLoad()

    self.newView = SKView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 1024, height: 1024)))
    (self.view as? SKView)?.contentMode = .center
    self.newView.contentMode = .center
    self.newView.autoresizesSubviews = false
    self.newView.autoresizingMask = [.flexibleBottomMargin, .flexibleTopMargin, .flexibleLeftMargin, .flexibleRightMargin]
    (self.view as? SKView)?.addSubview(newView)
    self.newView.center = view.center
    self.scene = GameScene(size: CGSize(width: 1024, height: 1024))
    self.scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    self.scene.scaleMode = .resizeFill
    self.newView.presentScene(scene)
}

override var shouldAutorotate: Bool {
    return true
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    if UIDevice.current.userInterfaceIdiom == .phone {
        return .allButUpsideDown
    } else {
        return .all
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Release any cached data, images, etc that aren't in use.
}

override var prefersStatusBarHidden: Bool {
    return true
}
}

class GameScene: SKScene {

var labelNode: SKLabelNode!
var container: SKSpriteNode!

override func didMove(to view: SKView) {
    self.backgroundColor = SKColor.darkGray

    container = SKSpriteNode(color: .black, size: CGSize(width: 300, height: 300))
    self.addChild(container)

    labelNode = SKLabelNode(text: "hello")
    labelNode.fontColor = .white
    container.addChild(labelNode)
}
}