# Draw Line With Rounder Corners – WWDC20 Scholarship

Having a basic working engine of the game, I had an idea to make a smooth animation selecting winning fields. The idea sounds easy, a line from one place to another. What can be difficult in drawing a simple line?

It’s very simple to draw a tiny line, it looks good but I need a thick line and there is one small challenge. The line always is a rectangle, like this:

It doesn’t look nice so I started to look for any solution to draw the line with rounded corners. Unfortunately, I didn’t find anything, nobody even asked such questions on StackOverflow. I decided to find a solution on my own. And, I have one.

The final result looks like this:

The solution is very simple, draw a circle at the starting point, draw another circle in the starting point and move it to finish point, during moving the second circle start drawing a line from the first circle to the second. Beneath it looks like:

Combined together:

#### Let’s code it.

Firstly, you need a starting circle.

let startPointPath = UIBezierPath(arcCenter: startPoint, radius: finishLineWidth, startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true)

let startPointShapeLayer = CAShapeLayer()
startPointShapeLayer.
fillColor = finishLineColor
startPointShapeLayer.
strokeColor = finishLineColor
startPointShapeLayer.
path = startPointPath.cgPath

There are few constant, you can change them in your project based on your needs. Below are mine:

let finishLineColor = #colorLiteral(red: 0.9529411793, green: 0.6862745285, blue: 0.1333333403, alpha: 1).cgColor
let finishLineWidth: CGFloat = 12
let finishLineAnimationDuration: CFTimeInterval = 2

var finishLineView: UIView = {
let view = UIView()
view.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.30)
view.frame = frameOfMainView
view.isUserInteractionEnabled = true
return view
}()

frameOfMainView is the whole screen.
startPoint and endPoint are based on winning fields, there are instances of CGPoint.

Next, you need to draw a circle that will be moved.

let linePath = UIBezierPath(arcCenter: startPoint, radius: finishLineWidth, startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true)

let lineShapeLayer = CAShapeLayer()
lineShapeLayer.
fillColor = finishLineColor
lineShapeLayer.
strokeColor = finishLineColor
lineShapeLayer.
path = linePath.cgPath

let lineAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.position))
lineAnimation.
fromValue =  CGPoint(x: 0, y: 0)
lineAnimation.
toValue = CGPoint(x: endPoint.xstartPoint.x, y: endPoint.y startPoint.y)
lineAnimation.
isRemovedOnCompletion = false
lineAnimation.
duration = finishLineAnimationDuration
lineAnimation.
fillMode = .forwards

lineShapeLayer.

Note that toValue doesn’t point to endPint, it needs relative coordinates.

lineAnimation.isRemovedOnCompletion = false
lineAnimation.fillMode = .forwards

Prevent from looping animation and after animation circle will stay in the same place.

Another step is to draw a line.

let finishPointPath = UIBezierPath()
finishPointPath.
move(to: startPoint)
finishPointPath.

let finishPointShapeLayer = CAShapeLayer()
finishPointShapeLayer.
strokeColor = finishLineColor
finishPointShapeLayer.
lineWidth = finishLineWidth * 2 + 1
finishPointShapeLayer.
path = finishPointPath.cgPath

let finishPointAnimation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.strokeEnd))
finishPointAnimation.
fromValue = 0
finishPointAnimation.
duration = finishLineAnimationDuration

finishPointShapeLayer.