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

self.finishLineView.layer.addSublayer(startPointShapeLayer)

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.x – startPoint.x, y: endPoint.y – startPoint.y)

lineAnimation.isRemovedOnCompletion = false

lineAnimation.duration = finishLineAnimationDuration

lineAnimation.fillMode = .forwards

lineShapeLayer.add(lineAnimation, forKey: “animation”)

self.finishLineView.layer.addSublayer(lineShapeLayer)

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

**lineAnimation.isRemovedOnCompletion = falselineAnimation.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.addLine(to: endPoint)

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.add(finishPointAnimation, forKey: “animation”)

self.finishLineView.layer.addSublayer(finishPointShapeLayer)

Note **finishPointShapeLayer.lineWidth finishLineWidth * 2 + 1**. It has a multiplication of 2 because previously it was used as a radius. Adding 1 makes that line looks better.

The last step is to add finishLineView to view.

view.addSubview(finishLineView)

Change width and color based on your needs.

This post is another step in my learning journey of learning Playground preparing for WWDC Scholarship this year, more information.