iPhoneボールとボウル

ボウルのなかにボールをどんどんいれていくiPhoneアプリのサンプルコードを描いてみます。

import UIKit

import SceneKit

class ViewController: UIViewController {

    weak var scene : SCNScene?

    weak var sceneView : SCNView?

    

    override func viewDidLoad() {

        super.viewDidLoad()

        self.view.backgroundColor = UIColor(hue: 0.75, saturation: 0.3, brightness: 1, alpha: 1)

        

        self.setupScene()

        self.createBowl()

        self.createCamera()

        self.createLight()

        self.createTargetSight()

    }

    

    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.85, saturation: 0.3, brightness: 1, alpha: 1)

        sv.scene = SCNScene()

        self.view.addSubview(sv)

        

        self.scene = sv.scene

        self.sceneView = sv

    }

    

    func createBowl() {

        let bowl = SCNNode()

        bowl.runAction(SCNAction.rotateByAngle(1.6, aroundAxis: SCNVector3(x: 0, y: 1, z: 0), duration: 20.0))

        self.scene?.rootNode.addChildNode(bowl)

        

        let dAngle : Float = Float(M_PI) / 20.0

        for t in 0..<10 {

            for p in 0..<40 {

                let box = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0)

                box.firstMaterial?.diffuse.contents = UIColor(hue: 0.6, saturation: 0.3, brightness: 1, alpha: 1)

                let boxNode = SCNNode(geometry: box)

                boxNode.position = self.sphericalCoordinate(Float(t) * dAngle + Float(M_PI/2.0), phi: Float(p) * dAngle, r: 10)

                bowl.addChildNode(boxNode)

                

                boxNode.physicsBody = SCNPhysicsBody.staticBody()

            }

        }

    }

    

    func createCamera() {

        let camera = SCNNode()

        camera.camera = SCNCamera()

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

        self.scene?.rootNode.addChildNode(camera)

    }

    

    func createLight() {

        let light = SCNLight()

        light.type = SCNLightTypeSpot

        let lightNode = SCNNode()

        lightNode.light = light

        lightNode.position = SCNVector3(x: 0, y: 10, z: 80)

        self.scene?.rootNode.addChildNode(lightNode)

    }

    

    func createTargetSight() {

        let r = CGRectGetMaxX(self.view.bounds) * 0.3

        let path = UIBezierPath()

        for i in 0..<4 {

            let start = CGFloat(i) * CGFloat(M_PI/2.0) CGFloat(M_PI) / 6.0

            let end = start + CGFloat(M_PI/3.0)

            path.appendPath(UIBezierPath(arcCenter: CGPointZero, radius:r, startAngle:start, endAngle:end , clockwise: true))

        }

        let target = CAShapeLayer()

        target.position = CGPoint(x: CGRectGetMidX(self.view.bounds), y: CGRectGetMaxY(self.view.bounds) * 3.0/4.0)

        target.fillColor = UIColor.yellowColor().CGColor

        target.path = path.CGPath

        self.view.layer.addSublayer(target)

    }

    

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

        let p0 = touches.anyObject()!.locationInView(self.view)

        let p = CGPoint(x: p0.x, y: p0.y CGRectGetMidY(self.view.bounds))

        

        let mark = UIView(frame: CGRectMake(0, 0, 6, 6))

        mark.backgroundColor = UIColor.clearColor()

        mark.layer.borderWidth = 2

        mark.layer.borderColor = UIColor.blackColor().CGColor

        mark.center = p0

        self.view.addSubview(mark)

        

        let o = self.sceneView!.projectPoint(SCNVector3Zero)

        let p3 = self.sceneView!.unprojectPoint(SCNVector3(x: Float(p.x), y: Float(p.y), z: o.z))

        let ball = SCNSphere(radius: 3)

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

        ball.firstMaterial?.diffuse.contents = UIColor(hue: hue, saturation: 0.3, brightness: 1, alpha: 1)

        let ballNode = SCNNode(geometry: ball)

        ballNode.position = SCNVector3(x: p3.x, y: 15, z: -p3.y/2.0)

        self.scene?.rootNode.addChildNode(ballNode)

        

        ballNode.physicsBody = SCNPhysicsBody.dynamicBody()

    }

    

    func sphericalCoordinate(theta:Float, phi:Float, r:Float) -> SCNVector3 {

        let x = r * sin(theta) * cos(phi)

        let z = r * sin(theta) * sin(phi)

        let y = r * cos(theta)

        return SCNVector3(x: x, y: y, z: z)

    }

}