3

I have two arcs that form a circle(SKCropNode), each with a different color. I know I can give the whole circle a circleOfRadius, but I was wondering if it was possible to give just one arc a physics body to fit the shape of the arc.

Help much appreciated.

KeepItSimple
  • 133
  • 8

1 Answers1

3

You may want to avoid using an SKCropNode to build your arcs. From Apple's documentation,

Use clipping and effect nodes sparingly. Both are very powerful, but can be expensive, especially when nested together within the node tree.

Alternatively, you can construct an arc-shaped core graphics path and then create a shape node from the path. You can then create a physics body using the CG path.

To build the arc-shaped path,

  1. Add an inner arc from the starting angle to the ending angle
  2. Add a line from the inner arc's ending point to the outer arc's ending point
  3. Add the outer arc from the ending angle to the starting angle
  4. Close the path (which connects the arcs starting points)

Extending CGPath to construct the arc path is not necessary, but often it's more convenient to use. Once extended, the new class method can be called from anywhere in your code. Here's an example:

extension CGPath {
    static func arcWithWidth(arcWidth:CGFloat, start:CGFloat, end:CGFloat, radius:CGFloat, clockwise:Bool) -> CGPath {
        // The radius parameter specifies the middle of the arc; adjust this as needed
        let innerRadius:CGFloat = radius - arcWidth / 2.0
        let outerRadius:CGFloat = radius + arcWidth / 2.0

        // Note the arc is upside down because CGPath uses UIKit coordinates
        let path = UIBezierPath()
        // Add inner ring.
        path.addArcWithCenter(CGPointZero, radius: innerRadius, startAngle: start, endAngle: end, clockwise: clockwise)
        let x = outerRadius * cos(end)
        let y = outerRadius * sin(end)

        // Connect the inner to the outer ring
        path.addLineToPoint(CGPointMake(x, y))

        // Add outer ring
        path.addArcWithCenter(CGPointZero, radius: outerRadius, startAngle: end, endAngle: start, clockwise: !clockwise)

        path.closePath()

        return path.CGPath
    }
}

With the extension, you can create the top and bottom arcs:

    // Top arc
    var path = CGPath.arcWithWidth(20, start:0, end: CGFloat(M_PI), radius: 100, clockwise: true)

    let topArc = SKShapeNode(path: path)
    topArc.position = view.center
    topArc.fillColor = SKColor.redColor()
    topArc.strokeColor = SKColor.clearColor()

    // Add a physics body to the top half
    topArc.physicsBody = SKPhysicsBody(polygonFromPath: path)
    topArc.physicsBody?.affectedByGravity = false

    addChild(topArc)

    // Bottom arc
    path = CGPath.arcWithWidth(20, start:0, end: CGFloat(M_PI), radius: 100, clockwise: false)
    let bottomArc = SKShapeNode(path: path)
    bottomArc.position = view.center
    bottomArc.fillColor = SKColor.blueColor()
    bottomArc.strokeColor = SKColor.clearColor()

    addChild(bottomArc)
0x141E
  • 12,613
  • 2
  • 41
  • 54
  • Apologies for the stupid question, but where do you put the CGPath extension in a SK project so it's working? – Confused Sep 27 '16 at 15:56
  • You can add it to your ViewController (below the import SpriteKit statement) or in a new file called "Extensions.swift". It can't be inside of a class or struct definition. – 0x141E Sep 27 '16 at 18:01
  • Thank you! I've been (very slowly) coming to realise extensions are amazing. – Confused Sep 27 '16 at 18:03
  • @0x141E could you please check out my post, been at it for a while https://stackoverflow.com/questions/44294768/how-to-rotate-sprites-around-a-joint – Containment Jun 05 '17 at 08:47