Search code examples
iosswiftsprite-kitskshapenode

How to draw a face to SKShapeNode


I'm fairly new to Swift and I'm coding for my kids. I'm using sprite-kit to create a simple game for them. At the moment I'm struggling with how to draw a face to an arbitrary skshapenode? I know that there is no holes within the shape but other than that it can be of any shape. Dispite what shape it is, I would like to draw eyes and mouth to it programmatically. The shapes can came in many sizes.

Any suggestions how to approach this?


Solution

  • Here's an example of how to draw a smiley face with an SKShapeNode. It provides a framework that you can expand upon to draw more complex faces.

    We start by extending the UIBezierPath class to add instance methods that are useful for drawing faces. The first method adds a circle to a path at a given location and with a specified radius. The moveToPoint statement moves the current point of a path to a new location. This is the equivalent of picking up a "pen" and moving it to a new location to draw a different, non-connected object. The second method draws a half circle with the open side facing up. This can be used to draw a smile. Note that extensions cannot be defined within a class. You can place it above your GameScene definition.

    extension UIBezierPath {
        func addCircle(center:CGPoint, radius:CGFloat) {
            self.moveToPoint(CGPointMake(center.x+radius, center.y))
            self.addArcWithCenter(center, radius: radius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)
        }
        func addHalfCircle(center:CGPoint, radius:CGFloat) {
            self.moveToPoint(CGPointMake(center.x+radius, center.y))
            self.addArcWithCenter(center, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI), clockwise: false)
        }
    }
    

    We can now use the extended UIBezierPath class to draw a face consisting of a face outline (a large circle), eyes (two small circles), and a mouth (a half circle). The face is constructed by adding components of the face to a path and then attaching the path to an SKShapeNode.

    class GameScene: SKScene {
    
        override func didMoveToView(view: SKView) {
            scaleMode = .ResizeFill
            let face = SKShapeNode()
            // The argument determines the size of the face
            face.path = drawFace(50)
            face.lineWidth = 2
            // Place the face in the center of the scene
            face.position = CGPointMake (CGRectGetMidX(view.frame),CGRectGetMidY(view.frame))
            addChild(face)
        }
    
        func drawFace(radius:CGFloat) -> CGPathRef {
    
            var path = UIBezierPath()
    
            // Add the outline of the face
            let center = CGPointZero
            path.addCircle(center, radius: radius)
    
            // Add the eyes
            let eyeOffset = radius * 0.35
            let eyeRadius = radius * 0.125
    
            let left = CGPointMake(-eyeOffset, eyeOffset)
            path.addCircle(left, radius: eyeRadius)
    
            let right = CGPointMake(eyeOffset, eyeOffset)
            path.addCircle(right, radius: eyeRadius)
    
            // Add the mouth
            let smileRadius = radius*0.65
            path.addHalfCircle(center, radius: smileRadius)
    
            return path.CGPath
        }        
    }