No collision-detection by using SKShapeNode with UIBezierpath - swift

I have the following UIBezierPath which is like a circle, but with a gap in it:
var centerPosition = CGPointMake(self.frame.width/2, self.frame.height/2)
var aPath:UIBezierPath = UIBezierPath(arcCenter: centerPosition, radius: 75, startAngle: 0, endAngle: degreesToRadians(size), clockwise: true)
gapeCircle = SKShapeNode(path: myPath, centered: true)
Now I'd like to use the SKPhysicsBody so that when an object collides with the outline of this object, that there is a notification. But only in that situation. If the object "collides" at the gap-position, there shouldn't be a notification.
But I couldn't find out how to solve that problem. I've already tried multiple different SKPhysicsBody-initializers. The only one that worked was the circleOfRadius but that doesn't work like I want it to work, because I need to check the collision only if an object collides with the "non-gap" part of my circle.

I suspect it's because you're not using a closed UIBezierPath. The following code will create a curve that loops back on itself giving the 'C' a width of just 1 pt
var centerPosition = CGPointMake(self.frame.width/2, self.frame.height/2)
var aPath:UIBezierPath = UIBezierPath(arcCenter: centerPosition, radius: 75, startAngle: 0, endAngle: degreesToRadians(size), clockwise: true)
var aPath:UIBezierPath = UIBezierPath(arcCenter: centerPosition, radius: 74, startAngle: degreesToRadians(size), endAngle: 0, clockwise: false)
gapeCircle = SKShapeNode(path: myPath, centered: true)

Related

Inner shadow for partial arc with Swift

I want to create an inner shadow for an arc but I get half of a circle instead of the shadow (see image below).
My code is:
let rect = self.bounds
let segmentArcPath = UIBezierPath()
segmentArcPath.addArc(withCenter: rect.center,
radius: (rect.height - insetShadow) / 2,
startAngle: -.pi/2,
endAngle: value * 2 * .pi - .pi/2,
clockwise: true)
shadowPath = segmentArcPath.cgPath
I have tried to add two paths (to not close the shadow), but without success:
let rect = self.bounds
let segmentArcPath = UIBezierPath()
segmentArcPath.addArc(withCenter: rect.center,
radius: (rect.height - insetShadow) / 2,
startAngle: internalStrokeStart,
endAngle: internalStrokeEnd,
clockwise: true)
let segmentArcPath2 = UIBezierPath()
segmentArcPath2.addArc(withCenter: rect.center,
radius: (rect.height - insetShadow) / 2 - 5,
startAngle: internalStrokeStart,
endAngle: internalStrokeEnd,
clockwise: false)
segmentArcPath.append(segmentArcPath2)
shadowPath = segmentArcPath.cgPath
How can I create a shadow as shown in the image above? Do you have any hints?
As recommended by #vacawama:
Only create one UIBezierPath. After drawng the outer arc, draw a 5
unit line towards the center of the arc, then call addArc to add the
inner arc to the same path
let rect = self.bounds
let outerRadius = (rect.height - insetShadow) / 2
let segmentArcPath = UIBezierPath()
segmentArcPath.addArc(withCenter: rect.center,
radius: outerRadius,
startAngle: internalStrokeStart,
endAngle: internalStrokeEnd,
clockwise: true)
let innerCircleRadius = outerRadius - 2
let startPointXInnerCircle = cos(internalStrokeEnd) * innerCircleRadius + rect.center.x
let startPointYInnerCircle = sin(internalStrokeEnd) * innerCircleRadius + rect.center.y
segmentArcPath.addLine(to: CGPoint(x: startPointXInnerCircle, y: startPointYInnerCircle))
segmentArcPath.addArc(withCenter: rect.center,
radius: innerCircleRadius,
startAngle: internalStrokeEnd,
endAngle: internalStrokeStart,
clockwise: false)
shadowPath = segmentArcPath.cgPath

Circular crown with UIBezierPath

I'am trying draw a circular crown with UIBezierPath. I can draw two circle with two diferent radius:
let bezierCrown = UIBezierPath()
bezierCrown.addArc(withCenter: center,
radius: raidus1,
startAngle: 0,
endAngle: CGFloat.pi*2,
clockwise: true)
bezierCrown.move(to: CGPoint(x: center.x+distancia2, y: center.y))
bezierCrown.addArc(withCenter: center,
radius: raidus2,
startAngle: 0,
endAngle: CGFloat.pi*2,
clockwise: true)
But when I fill:
UIColor.green.setFill()
bezierCrown.fill()
Everything is filled: image.
I want only the crown to be filled.
You need to set the fillRule to evenOdd
let center = CGPoint(x: 200, y: 400)
let raidus1:CGFloat = 100
let raidus2:CGFloat = 80
let bezierCrown = UIBezierPath()
bezierCrown.addArc(withCenter: center,
radius: raidus1,
startAngle: 0,
endAngle: CGFloat.pi*2,
clockwise: true)
bezierCrown.move(to: CGPoint(x: center.x+raidus2, y: center.y))
bezierCrown.addArc(withCenter: center,
radius: raidus2,
startAngle: 0,
endAngle: CGFloat.pi*2,
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = bezierCrown.cgPath
shapeLayer.fillColor = UIColor.blue.cgColor
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.fillRule = .evenOdd
view.layer.addSublayer(shapeLayer)

Set position of outerBelowCircle CAShapeLayer in the center of View

I make a circle by using CAShapeLayer, and I want to set the center of it, in the center of the view. But the circle will be created exactly below the center line (see the screenshot), could anyone help me on this?
let circle = CAShapeLayer()
view.layer.addSublayer(circle)
circle.position = view.center
let circularPath = UIBezierPath(arcCenter: .zero, radius: 100, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
circle.path = circularPath.cgPath
I also change the way that for setting it in the center, but It doesn't work
circle.position = CGPoint(x: view.layer.bounds.midX, y: view.layer.bounds.midY)
Consider the following method according to your screenshot this method will resolve your issue.
func showCircle() {
let view = UIView()
let circle = CAShapeLayer()
view.layer.addSublayer(circle)
let positionX = view.center.x
let positionY = view.center.y - 100 // your circle radius
circle.position = CGPoint(x: positionX, y: positionY)
let circularPath = UIBezierPath(arcCenter: .zero, radius: 100, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
circle.path = circularPath.cgPath
}
I haven't tested the code. Please verify it by yourself.

Swift draw and RESIZE circle with CAShapeLayer() and UIBezierPath

I want to draw a circle with animation, where the animation starts from 12 o'clock, and goes 360 degrees. Everything works fine, but I can not resize the circle.
If I use UIBezierPath - I can define the starting point ("startAngle: -CGFloat.pi / 2").
let shapeLayer = CAShapeLayer()
let center = progressView.center
let circularPath = UIBezierPath(arcCenter: center, radius: 100, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)
shapeLayer.path = circularPath.cgPath
If I use UIBezierPath(ovalIn:...) I can resize.. But I want to use both, or how can I keep the start angle, and the size too?
shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: 8, y: 78, width: 70, height: 70)).cgPath
For the first version of your path code, the radius parameter determines the size of the circle.
In the second version, it draws an oval (which may or may not be a circle) into a rectangular box.
Both let you control the size, just with different parameters.
If you want to vary the size of the arc drawn with init(arcCenter:radius:startAngle:endAngle:clockwise:) then vary the radius parameter.
A circle drawn with
let circularPath = UIBezierPath(arcCenter: center,
radius: 100,
startAngle: -CGFloat.pi / 2,
endAngle: 2 * CGFloat.pi,
clockwise: true)
Will be twice as big as a circle drawn with
let circularPath = UIBezierPath(arcCenter: center,
radius: 50,
startAngle: -CGFloat.pi / 2,
endAngle: 2 * CGFloat.pi,
clockwise: true)
(And btw, if the start angle is -π/2, shouldn't the end angle be 3π/2, so the arc is 360° (or 2π) rather than 450°?)

How to change the endAngle programmatically

I would like to create an arc with Swift and SpriteKit by doing something like this:
func createArc(endAngle: CGFloat) -> SKShapeNode {
let bezierPath = UIBezierPath(arcCenter: CGPointMake(0, 0), radius: 300, startAngle: CGFloat(M_PI_2), endAngle: endAngle, clockwise: false)
let pathNode = SKShapeNode(path: bezierPath.CGPath)
pathNode.strokeColor = SKColor.blackColor()
pathNode.lineWidth = 50
pathNode.position = CGPoint(x: size.width/2, y: size.height/2)
pathNode.antialiased = true
return pathNode
}
But how should I change the endAngle value of the UIBezierPath programmatically say in the update() function?