如何为每个象限创建一个圆形末端的圆

时间:2017-05-19 05:51:01

标签: swift swift3 sprite-kit skshapenode

我创建了一个分为象限的圆圈。我试图让每个象限的末端四舍五入,每个象限之间有一个给定的间隙,但我得到了一些奇怪的行为。我想我错过了一些东西。下面是我得到的图像和相关代码。我希望结果类似于Apple Watch活动响铃。

enter image description here

class GameScene: SKScene {

let radius = CGFloat(100)
var topRightPathNode : SKShapeNode!
var bottomRightPathNode : SKShapeNode!
var bottomLeftPathNode : SKShapeNode!
var topLeftPathNode : SKShapeNode!

override func didMove(to view: SKView) {

}


override init(size: CGSize) {
    super.init(size: size)
    let topRightPath = arcSegment(center: CGPoint.zero, radius: radius, strokeWidth: 18, gapWidth: 6)

    // TOP RIGHT


    topRightPathNode = SKShapeNode(path: topRightPath)
    topRightPathNode.fillColor = SKColor.white
    topRightPathNode.lineWidth = 0
    topRightPathNode.position = CGPoint(x: 320, y: 240)
    addChild(topRightPathNode)


    // BOTTOM RIGHT

    var reflectOnY = CGAffineTransform(scaleX: 1.0, y: -1.0)
    let bottomRightPath = topRightPath.copy(using: &reflectOnY)!
    bottomRightPathNode = SKShapeNode(path: bottomRightPath)
    bottomRightPathNode.fillColor = SKColor.red
    bottomRightPathNode.lineWidth = 0
    bottomRightPathNode.position = CGPoint(x: 320, y: 240)
   addChild(bottomRightPathNode)


    // BOTTOM LEFT


    //var reflectOnX = CGAffineTransform(scaleX: -1.0, y: 1.0)
    //let bottomLeftPath = bottomRightPath.copy(using: &reflectOnX)!
    var reflectOnXAndY = CGAffineTransform(scaleX: -1.0, y: -1.0)
    let bottomLeftPath = topRightPath.copy(using: &reflectOnXAndY)!

    bottomLeftPathNode = SKShapeNode(path: bottomLeftPath)
    bottomLeftPathNode.fillColor = SKColor.purple
    bottomLeftPathNode.lineWidth = 0
    bottomLeftPathNode.position = CGPoint(x: 320, y: 240)
    addChild(bottomLeftPathNode)



    // TOP LEFT
    var reflectOnX = CGAffineTransform(scaleX: -1.0, y: 1.0)
    let topLeftPath = topRightPath.copy(using: &reflectOnX)!
    topLeftPathNode = SKShapeNode(path: topLeftPath)
    topLeftPathNode.fillColor = SKColor.cyan
    topLeftPathNode.lineWidth = 0
    topLeftPathNode.position = CGPoint(x: 320, y:240)
    addChild(topLeftPathNode)

}

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


func arcSegment(center : CGPoint,
                radius: CGFloat,
                strokeWidth: CGFloat,
                gapWidth: CGFloat) -> CGPath
{
    let halfStrokeWidth = strokeWidth / 2.0
    let outerRadius = radius + halfStrokeWidth
    let innerRadius = radius - halfStrokeWidth
    let halfGap = gapWidth / 2.0

    let outerStartAngle = CGFloat(atan2(sqrt(outerRadius * outerRadius - halfGap * halfGap), halfGap))
    let outerEndAngle = CGFloat(atan2(halfGap, sqrt(outerRadius * outerRadius - halfGap * halfGap)))

    let innerStartAngle = CGFloat(atan2(halfGap, sqrt(innerRadius * innerRadius - halfGap * halfGap)))
    let innerEndAngle = CGFloat(atan2(sqrt(innerRadius * innerRadius - halfGap * halfGap), halfGap))

    let path = CGMutablePath()

    path.addArc(center: center, radius: outerRadius, startAngle: outerStartAngle, endAngle: outerEndAngle, clockwise: true)
    // Quartz 2D will assume a "moveTo" here
    path.addArc(center: CGPoint(x: center.x + radius, y: center.y), radius: halfStrokeWidth, startAngle: outerStartAngle, endAngle: outerEndAngle, clockwise: false)

    path.addArc(center: center, radius: innerRadius, startAngle: innerStartAngle, endAngle: innerEndAngle, clockwise: false)

    path.closeSubpath()


    return path
}

2 个答案:

答案 0 :(得分:2)

我在回答你的第一个问题时所用的所有三角函数都是必要的,以便在你想要的曲线上得到平坦的末端,与轴对齐。现在你已经改变了并且想要在圆弧上使用圆形端盖,你可以回到原来的尝试,只需依靠Quartz 2D来使用圆形端盖冲程。代码再简单得多,可以是:

import UIKit
import SpriteKit
import PlaygroundSupport

let radius = CGFloat(100)

let sceneSize = CGSize(width: 640, height: 480)
let sceneView = SKView(frame: CGRect(origin: CGPoint.zero, size: sceneSize))

let scene = SKScene(size: sceneSize)
scene.backgroundColor = UIColor.black

let topRightPath = arcSegment(radius: radius, gapWidth: 25)

let topRightPathNode = SKShapeNode(path: topRightPath)
topRightPathNode.strokeColor = SKColor.white
topRightPathNode.lineWidth = 18
topRightPathNode.lineCap = .round
topRightPathNode.position = CGPoint(x: 320, y: 240)
scene.addChild(topRightPathNode)


var reflectOnY = CGAffineTransform(scaleX: 1.0, y: -1.0)
let bottomRightPath = topRightPath.copy(using: &reflectOnY)!
let bottomRightPathNode = SKShapeNode(path: bottomRightPath)
bottomRightPathNode.strokeColor = SKColor.orange
bottomRightPathNode.lineWidth = 18
bottomRightPathNode.lineCap = .round
bottomRightPathNode.position = CGPoint(x: 320, y: 240)
scene.addChild(bottomRightPathNode)


var reflectOnX = CGAffineTransform(scaleX: -1.0, y: 1.0)
let bottomLeftPath = bottomRightPath.copy(using: &reflectOnX)!
let bottomLeftPathNode = SKShapeNode(path: bottomLeftPath)
bottomLeftPathNode.strokeColor = SKColor.green
bottomLeftPathNode.lineWidth = 18
bottomLeftPathNode.lineCap = .round
bottomLeftPathNode.position = CGPoint(x: 320, y: 240)
scene.addChild(bottomLeftPathNode)


let topLeftPath = bottomLeftPath.copy(using: &reflectOnY)!
let topLeftPathNode = SKShapeNode(path: topLeftPath)
topLeftPathNode.strokeColor = SKColor.blue
topLeftPathNode.lineWidth = 18
topLeftPathNode.lineCap = .round
topLeftPathNode.position = CGPoint(x: 320, y:240)
scene.addChild(topLeftPathNode)

sceneView.presentScene(scene)

PlaygroundPage.current.liveView = sceneView
PlaygroundPage.current.needsIndefiniteExecution = true

func arcSegment( radius: CGFloat,
                 gapWidth: CGFloat) -> CGPath
{
    let halfGap = gapWidth / 2.0
    let path = CGMutablePath()
    let startAngle = CGFloat(atan2(sqrt(radius * radius - halfGap * halfGap), halfGap))
    let endAngle = CGFloat(atan2(halfGap, sqrt(radius * radius - halfGap * halfGap)))

    path.addArc( center: CGPoint.zero,
                radius: radius,
                startAngle: startAngle,
                endAngle: endAngle,
                clockwise: true)

    return path
}

答案 1 :(得分:1)

这是另一组代码,其中生成的路径具有圆形末端,但每个弧段是填充路径而不是单个描边段。这应该允许路径在没有端盖重叠的情况下发生碰撞。

foo/mod.rs