SKSpriteNode frame way off

2020-04-22 02:13发布

问题:

I am trying to create an open circle from a UIBezierPath and turn that into an SKShapeNode which will later be turned into a SKSpriteNode.

I had an problem where I could not figure out how to shrink a Sprite while its line width did not scale down. You can see the solution here: Resize sprite without shrinking contents

I ended up fixing some things and creating a new class to implement a custom SKShapeNode with this functionality:

class ShrinkableShape: SKShapeNode {

let level: Int
let bezierPath: UIBezierPath
let scale: CGFloat
let finalLineWidth: CGFloat
let from: SKSpriteNode

let initialLineWidth = CGFloat(20)
let duration = 0.3

// level would be from 1 to 5 (it is in a for loop)
init(level: Int, from: SKSpriteNode) {
    self.level = level
    self.from = from

    // create the open circle  which is (43 * level) + 140
    bezierPath = UIBezierPath(arcCenter: CGPoint(x: 0, y: 0), radius: CGFloat(((43 * level) + 140)), startAngle: CGFloat(GLKMathDegreesToRadians(-50)), endAngle: CGFloat(M_PI * 2), clockwise: false)

    // calls static function in this class so it is more readable 
    scale = ShrinkableShape.scaleFrom(level: level) / ShrinkableShape.scaleFrom(level: level + 1)
    finalLineWidth = (initialLineWidth / scale)

    // inits shape and then sets it up to specific values
    super.init()
    setup()
}

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

func setup() {
    // set sprite to path, set color, set line width and rotate it 
    self.path = bezierPath.cgPath
    self.strokeColor = UIColor(red:0.98, green:0.99, blue:0.99, alpha:1.00)
    self.lineWidth = 20
    self.position = from.position

    // FOR DEBUG: you will see what this makes in the screenshot
    let color = SKShapeNode(rect: self.frame)
    color.fillColor = UIColor.red
    color.alpha = 0.2
    color.position = self.position
    self.addChild(color)
}

// Makes the radius from the value given (only 1...5) 183, 226, 269, etc
static func scaleFrom(level: Int) -> CGFloat {
    return (CGFloat((level * 43) + 140) * 2.0)
}

}

If you look at the screenshot you can notice the white circle is a little off compared to where it should be aligned (the gray bar and white circle path should be on each other). This only happens when I call the scale function shown in the solution (linked above).

I think it is because of the frame being all messed up. If you see, the frame is very off (and that same issue was the reason for past issues when converting to a texture because the frame was not exact as it should be)

Why does this happen? How do I fix it? Is there a way for me to manually set the correct frame for the SKShapeNode? Any other ideas on how I can do this?

--Edit-- I forgot to mention. The red part in the picture is a debug to see the frame of the SKShapeNode. You can see how it is created in the setup() func. But I included that to show how far off the frame was.

回答1:

I think part of your problem is the difference between where you have your lines versus where the bitmap edges are as a result of the stroke/outline width you have 'around' those lines.

Perhaps best described visually, whereby Red is what the system sees as the sprite size, whilst yellow is perhaps what you're thinking about. I've greatly exaggerated the line width to show the effect/problem I'm thinking about.