在iOS上的SpriteKit中,缩放纹理的精灵会产生不正确的帧?

时间:2014-12-30 08:04:40

标签: ios swift sprite-kit scaling

我正在学习SpriteKit游戏开发,以获得它的乐趣。我遇到了一个让我难过的看似简单的问题。

基本上,在我缩放纹理化的SKSpriteNode之后,帧不是我所期望的。我已经找到了一些黑客来强迫它达到我想要的水平,但我正在努力了解发生了什么。任何想法都赞赏!

这是我的代码WITHOUT SCALING:

func addSpaceship()
{
    let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
    spaceship.name = "spaceship"
//  spaceship.setScale(0.50)

    let debugFrame = SKShapeNode.init(rect: spaceship.frame)
    debugFrame.strokeColor = SKColor.greenColor()
    spaceship.addChild(debugFrame)

    spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150)

    self.addChild(spaceship)


}

我的应用看起来像这样: Unscaled ship with green debug frame

现在,如果我在缩放它的代码行中发表评论(spaceship.setScale(0.50)),我会得到这个:

Scaled ship with green debug frame

请注意,太空船在第二张图像中按比例缩小,但帧缩放甚至更小。为什么呢?

如果我在之后将缩放线移动到,我将太空船添加到场景中,它会达到我的预期,但这似乎是错误的:

这是在将太空船添加到场景后调用setScale的代码:

func addSpaceship()
{
    let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
    spaceship.name = "spaceship"

    let debugFrame = SKShapeNode.init(rect: spaceship.frame)
    debugFrame.strokeColor = SKColor.greenColor()
    spaceship.addChild(debugFrame)

    spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150)

    self.addChild(spaceship)
    spaceship.setScale(0.50)


}

以下是运行我的应用程序的原因:

Scaling after adding to the scene

这样有效,但为什么有必要?

以下建议,这是SKShapeNode的错误。但是,用SKLabelNode替换SKShapeNode也存在同样的问题:

func addSpaceship()
{
    let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
    spaceship.name = "spaceship"
    spaceship.setScale(0.50)

    let scoreNode = SKLabelNode(text: "100")
    scoreNode.position = CGPointMake(CGRectGetMidX(spaceship.frame), CGRectGetMaxY(spaceship.frame))

    scoreNode.fontColor = SKColor.redColor()
    scoreNode.fontSize = 15.0
    scoreNode.fontName = "Monaco"
    scoreNode.zPosition = 10.0
    spaceship.addChild(scoreNode)


    spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150)

    self.addChild(spaceship)
}

给了我们:

Same problem with an SKLabelNode

目的是让得分标签(scoreNode)居中高于火箭,但正如您所看到的那样,它位于顶部舷窗顶部。在我打电话给spaceship.setScale之后,宇宙飞船的框架出了问题。

我做了一个额外的发现:在我将太空船添加到场景后,不需要进行setScale调用。它只需要在我将debugFrame / scoreNode添加到太空船之后。如果我在那之后设置了Scale,一切都很好:

func addSpaceship()
{
    let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
    spaceship.name = "spaceship"

    let scoreNode = SKLabelNode(text: "100")
    scoreNode.position = CGPointMake(CGRectGetMidX(spaceship.frame), CGRectGetMaxY(spaceship.frame))

    scoreNode.fontColor = SKColor.redColor()
    scoreNode.fontSize = 15.0
    scoreNode.fontName = "Monaco"
    scoreNode.zPosition = 10.0
    spaceship.addChild(scoreNode)

    spaceship.setScale(0.50)

    spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150)

    self.addChild(spaceship)
}

导致:

This worked

2 个答案:

答案 0 :(得分:5)

您的问题可能是这两行的顺序:

  spaceship.setScale(0.50)
  let debugFrame = SKShapeNode.init(rect: spaceship.frame)

你缩小了宇宙飞船,然后用缩放的太空船计算矩形的大小。然后,当渲染矩形时,缩小到原始太空船大小的四分之一。

如果你换行,它应该按预期工作。

一般情况下,最好在真实大小中进行构图,然后在将其添加到场景之前对其进行缩放。

答案 1 :(得分:1)

首先,让我作为SKShapeNode的前言是一个非常时髦的(也许是错误的类)。至少它是在之前的spritekit迭代中。如果您的目标是为物理目的添加调试矩形。您可以在GameViewController内的SKView类上打开showsPhysics

继承我的实验

    let redbox = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 100, height: 100))
    redbox.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
    redbox.setScale(0.5)

    let debugFrame = SKShapeNode(ellipseOfSize: redbox.size)
    debugFrame.strokeColor = SKColor.greenColor()

    self.addChild(redbox)
    redbox.addChild(debugFrame)

enter image description here

看起来和你的一样。如果我在添加节点后调用setScale,那么我的圆圈会填满我的红色方块。

另外,如果我保持一切相同,但我只是将我的调试帧直接添加到场景中,它将以正确的方式缩放,很奇怪吧?

好的另一个测试。 注意我将绿框设置为红盒大小的50%,以便我们可以看到下方的红框。如果这里发生的错误比绿箱最终填满红盒的25%。

    let redbox = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 100, height: 100))
    redbox.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
    redbox.setScale(0.5)

    let greenbox = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width: 50, height: 50))

    self.addChild(redbox)
    redbox.addChild(greenbox)

enter image description here

好的,所以我使用另一个SKSpriteNode做了同样的事情,它的行为与我们期望的方式相同。因此无论出于何种原因,当您使用SKShapeNode 作为孩子时,会在其上调用两次setScale;除非您在将节点添加到场景后设置比例。但这不会发生在SKSpriteNode上。

答案是......我认为没有一个好的答案。这可能是一个错误。 SKShapeNode有错误的历史。 SpriteKit有一些错误= /如果我错了,有人会纠正我。