Search code examples
swiftsprite-kituibezierpath

Amoeba-shaped controls with SpriteKit


I am new to SpriteKit, and I am trying to create a distorted circle that acts like "amoeba". What I am trying to do is to use SKShapeNode initialised with with UIBezierPath created over 8-10 points on a circle with some randomness (something like):

    let theta : Double  =  (Double(i) * Double.pi / 180.0) * (36.0 + Double.random(in: -1...1))
    let radius : CGFloat =  CGFloat(100.0 + Double.random(in: 0...20))
    let a = CGFloat(cos(theta)) * radius
    let b = CGFloat(sin(theta)) * radius

This part works, but then, I am starting to build the path using addCurve() method and the shapes come out really ugly - probably because I don't fully understand how the method works and what should I use for control points.

Appreciate if you have any better ideas or help me with using addCurve() in a better way.


Solution

  • Here is what I've done - posting as it might be useful to someone, parameters could be tweaked to your liking.

        let path = UIBezierPath()
        let numPoints = Int.random(in: 5...25)
        let totalPoints = numPoints * 3
        var pt : [CGPoint] = Array(repeating: CGPoint(), count: totalPoints)
        var coef = 1.0
        for i : Int in 0..<(totalPoints) {
            let theta  =  (Double(i) * Double.pi / 180.0) * (360.0/Double(totalPoints) + Double.random(in: -1.0...1.0))
            
            coef = (i % 3 == 2 ? 1 : 0.25)
            let radius =  CGFloat(100.0 * coef + Double.random(in: 0...20))
            let a = CGFloat(cos(theta)) * radius
            let b = CGFloat(sin(theta)) * radius
            
            pt[i] = CGPoint(x: a, y: b)
            // the code snippet below is to show the curve and critical points
            let point : SKShapeNode = SKShapeNode(circleOfRadius: 5)
            point.fillColor = i % 3 == 0 ? .green : .cyan
            point.position = pt[i]
            point.zPosition = 10
            self.addChild(point)
            // end of code snippet
        }
        path.move(to: CGPoint(x: self.view!.bounds.minX + pt[0].x, y: self.view!.bounds.minY + pt[0].y))
        for i in 1...numPoints{
            path.addCurve(to: pt[(i * 3) % (totalPoints)],
                          controlPoint1: pt[(i * 3 - 1)],
                          controlPoint2: pt[(i * 3 - 2)])
        }
        path.close()
        let amoeba = SKShapeNode(path: path.cgPath)
        amoeba.strokeColor = .orange
        self.addChild(amoeba)