Reputation: 63
I am trying to create a CGPath with the shape of an eight or infinity sign. I do think the path creation should return the desired result but I will still post it here:
let path = CGMutablePath()
path.addEllipse(in: CGRect(x: -height/4, y: -height/2, width: height/2, height: height/2))
path.addEllipse(in: CGRect(x: -height/4, y: 0.0, width: height/2, height: height/2))
path.closeSubpath()
return path
Now I have another Node that should follow this path, which I thought would just work by using the SKAction like so:
highlighter.run(SKAction.repeatForever(SKAction.follow(shape.path!, asOffset: false, orientToPath: true, duration: 5.0)))
highlighter being the name of my node, shape being the name of the SKShapeNode I have assigned my path to. However the node only draws one of the circles and not the desired shape. I have been googling the issue but could not find any similar cases and have now been sitting on this for over a day so I might not see something obvious. Any insight would be much appreciated!
Upvotes: 1
Views: 165
Reputation: 8134
If you draw the figure 8 you have generated, you'll see that your sprite is only following the bottom circle, as this is the way you have drawn the path.
You need to draw half of either the top or the bottom circle, from top/bottom to the middle, then add the complete other circle starting and ending at the middle, and finally another half circle back to where you started.
Here is an example, which also draws the bounding rectangle and the figure-8 path to follow:
class GameScene: SKScene {
// var sprite = SKSpriteNode()
var figureEightPath = CGMutablePath()
override func didMove(to view: SKView) {
let boundingRect = CGRect(x: -200, y: -400, width: 400, height: 800)
addChild(drawSKShapeNode(fromRect: rect, withWidth: 2, inColour: SKColor.green, called: "rect"))
figureEightPath = drawFigureEight(in: boundingRect)
addChild(drawSKShapeNode(fromPath: figureEightPath, withWidth: 2, inColour: SKColor.red, called: "path"))
let sprite = SKSpriteNode(color: SKColor.yellow, size: CGSize(width: 50, height: 50))
addChild(sprite)
let moveAction = SKAction.follow(figureEightPath, asOffset: false, orientToPath: true, speed: 200)
sprite.run(SKAction.repeatForever(moveAction))
}
func drawSKShapeNode(fromPath path: CGMutablePath,
withWidth width: CGFloat,
inColour colour: SKColor,
called name: String) -> SKShapeNode {
let shape = SKShapeNode(path: path, centered: true)
shape.lineWidth = width
shape.strokeColor = colour
shape.name = name
return shape
}
func drawSKShapeNode(fromRect rect: CGRect,
withWidth width: CGFloat,
inColour colour: SKColor,
called name: String) -> SKShapeNode {
let shape = SKShapeNode(rect: rect)
shape.lineWidth = width
shape.strokeColor = colour
shape.name = name
return shape
}
func drawFigureEight(in rect: CGRect) -> CGMutablePath {
let bottomCentre = CGPoint(x: rect.midX, y: rect.height/4+rect.minY)
let topCentre = CGPoint(x: rect.midX, y:(rect.height/4)*3+rect.minY)
let radius = rect.height/4
let bottom = CGPoint(x: rect.midX, y: rect.minY)
let path = CGMutablePath()
path.move(to: bottom)
//Draw a semi-circle from the bottom counter-clockwise to the middle
path.addArc(center: bottomCentre, radius: radius, startAngle: CGFloat(Double.pi*1.5), endAngle: CGFloat(Double.pi/2), clockwise: false)
//Draw to top circle in a clockwise direction
path.addArc(center: topCentre, radius: radius, startAngle: CGFloat(Double.pi*1.5), endAngle: CGFloat(-Double.pi/2), clockwise: true)
//Draw the rest of the bottom circle by drawing a semi-circle from the middle to the bottom counter-clockwise.
path.addArc(center: bottomCentre, radius: radius, startAngle: CGFloat(Double.pi/2), endAngle: CGFloat(-Double.pi/2), clockwise: false)
return path
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
There's a couple of helper function - drawSKShapeNode - which you won't need but are useful for debugging as they 'draw' a CGPath or CGRect by creating an SKShapeNode from what they are given.
Upvotes: 1