iPhoneボールパッチワーク

円形のプレートでパッチワークなボールを表示するiPhoneアプリのサンプルコードを描いてみます。

import UIKit

import SceneKit

class ViewController: UIViewController {

    weak var sceneView : SCNView?

    

    override func viewDidLoad() {

        super.viewDidLoad()

        self.view.backgroundColor = UIColor(hue: 0, saturation: 0.4, brightness: 1, alpha: 1)

        self.setupScene()

        self.createPatchBall()

        self.createCamera()

        self.createLight()

    }

    func setupScene() {

        let w = CGRectGetMaxX(self.view.bounds)

        let sv = SCNView(frame: CGRect(x: 0, y: 0, width: w, height: w))

        sv.backgroundColor = UIColor(hue: 0, saturation: 0.3, brightness: 1, alpha: 1);

        sv.scene = SCNScene()

        self.view.addSubview(sv);

        

        self.sceneView = sv;

    }

    

    func createPatchBall() {

        let ball = SCNNode()

        ball.name = “ball”

        self.sceneView?.scene?.rootNode.addChildNode(ball)

        

        let dAngle = 2.0 * Double(M_PI) / 10.0

        let radius = 20.0

        let baseLength = 2.0 * Double(M_PI) * radius / 10.0

        

        for phi in 0..<5 {

            

            let p = dAngle * Double(phi)

            let cnt = 2.0 * Double(M_PI) * radius * sin(p) / baseLength

            let adjLength = 2.0 * Double(M_PI) * radius * sin(p) / floor(cnt)

            

            for theta in 0..<Int(cnt) {

                let t = (2.0 * Double(M_PI) / floor(cnt)) * Double(theta)

                let x = radius * cos(t)

                let z = radius * sin(t)

                let axis = SCNVector3(x: Float(x), y: 0, z: Float(z))

                let panel = SCNCylinder(radius: CGFloat(adjLength)/2.0, height: 1)

                panel.firstMaterial?.diffuse.contents = UIColor.whiteColor()

                let panelNode = SCNNode(geometry: panel)

                panelNode.name = “panel”

                panelNode.transform = SCNMatrix4Translate(panelNode.transform, 0, Float(radius), 0)

                panelNode.transform = SCNMatrix4Rotate(panelNode.transform, Float(p), axis.x, axis.y, axis.z)

                

                ball.addChildNode(panelNode)

            }

        }

    }

    

    func createCamera() {

        let camera = SCNNode()

        camera.camera = SCNCamera()

        camera.camera?.zFar = 2000

        camera.position = SCNVector3(x: 0, y: 0, z: 60)

        self.sceneView?.scene?.rootNode.addChildNode(camera)

    }

    

    func createLight() {

        let light = SCNLight()

        light.type = SCNLightTypeOmni

        let lightNode = SCNNode()

        lightNode.light = light

        lightNode.position = SCNVector3(x: 0, y: 5, z: 50)

        self.sceneView?.scene?.rootNode.addChildNode(lightNode)

    }

    

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {

        let p = touches.anyObject()!.locationInView(self.sceneView)

        if let hit = self.sceneView?.hitTest(p, options: [SCNHitTestSortResultsKey : true])?.first as? SCNHitTestResult {

            if hit.node.name == “panel” {

                hit.node.runAction(SCNAction.rotateByAngle(CGFloat(M_PI), aroundAxis: SCNVector3(x: 1, y: 0, z: 0), duration: 0.5))

                let hue = CGFloat(arc4random() % 10) * 0.1

                hit.node.geometry?.firstMaterial?.diffuse.contents = UIColor(hue: hue, saturation: 0.4, brightness: 1, alpha: 1)

            }

        }

    }

    

    override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {

        if let ball = self.sceneView?.scene?.rootNode.childNodeWithName(“ball”, recursively: false) {

            ball.transform = SCNMatrix4Rotate(ball.transform, 0.1, 0, 1, 0)

        }

    }

}