Search code examples
iosswiftsprite-kituibezierpathskspritenode

How to calculate the "center" point of a curved SKSpriteNode?


I'm initializing and displaying an SKSpriteNode via the texture of an SKShapeNode with a certain path that represents a portion of a circle. Below is an example of a shape I'm generating using a playground:

import SpriteKit
import PlaygroundSupport

let view = SKView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
let scene = SKScene(size: view.frame.size)
view.presentScene(scene)

let radius: CGFloat = view.frame.width * 0.40

var length: CGFloat = (.pi * 2.0) / 8.0
var width: CGFloat  = radius / 5.0

var path: CGPath {

    let path = UIBezierPath(arcCenter: view.center, radius: radius, startAngle: 0.0, endAngle: length, clockwise: true)
    path.addArc(withCenter: view.center, radius: radius - width, startAngle: length, endAngle: 0.0, clockwise: false)

    path.close()

    return path.cgPath
}

let shapeNode = SKShapeNode(path: path)
shapeNode.fillColor = .white
let texture = view.texture(from: shapeNode)!

let spriteNode = SKSpriteNode(texture: texture, color: .white, size: texture.size())
spriteNode.position = CGPoint(x: shapeNode.frame.midX, y: shapeNode.frame.midY)

scene.addChild(spriteNode)

PlaygroundPage.current.liveView = view

This generates this shape:

shape

I'd like to add a small child SKSpriteNode that is centered within the width of the curved node and at the middle arc point like so:

proper shape

The closest I could come is using the spriteNode's position:

let childNode = SKSpriteNode(color: .red, size: CGSize(width: 5, height: 5))
childNode.position = spriteNode.position
scene.addChild(childNode)

This produces something close, but it's using the frame, which is entirely wrong:

improper shape

I'm assuming I need to do something with the path of the arc but I'm unsure how. Could someone point me in the right direction?


Solution

  • Thanks to the comments I avoided using the path and refreshed on some basic trig to solve:

    let x = (radius - width/2) * cos(length/2) + view.center.x
    let y = (radius - width/2) * sin(length/2) + view.center.y
    childNode.position = CGPoint(x: x, y: y)