iPhoneコップにボール

コップにボールを入れるiPhoneアプリのサンプルコードを描いてみます。

import UIKit

import SceneKit

class ViewController: UIViewController {

    weak var sceneView : SCNView?

    

    override func viewDidLoad() {

        super.viewDidLoad()

        setupScene()

        createGround()

        createCup()

        createBall()

        createCamera()

    }

    func setupScene() {

        let sv = SCNView(frame: view.bounds)

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

        sv.scene = SCNScene()

        sv.autoenablesDefaultLighting = true

        view.addSubview(sv)

        sceneView = sv

    }

    func createGround() {

        let box = SCNCylinder(radius: 10, height: 1)

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

        let boxNode = SCNNode(geometry: box)

        boxNode.physicsBody = SCNPhysicsBody.staticBody()

        sceneView?.scene?.rootNode.addChildNode(boxNode)

    }

    func createCup() {

        let cup = SCNTube(innerRadius: 1.6, outerRadius: 1.8, height: 2.5)

        cup.firstMaterial?.diffuse.contents = UIColor(hue: 0.2, saturation: 0.6, brightness: 0.9, alpha: 1).colorWithAlphaComponent(0.8)

        let cupNode = SCNNode(geometry: cup)

        cupNode.position = SCNVector3(x: 0, y: 1.7, z: –8)

        cupNode.physicsBody = SCNPhysicsBody.staticBody()

        cupNode.physicsBody?.physicsShape = SCNPhysicsShape(geometry: cup, options: [SCNPhysicsShapeTypeKey : SCNPhysicsShapeTypeConcavePolyhedron])

        sceneView?.scene?.rootNode.addChildNode(cupNode)

    }

    

    func createBall (){

        let ball = SCNSphere(radius: 0.8)

        ball.firstMaterial?.diffuse.contents = UIColor.greenColor()

        let ballNode = SCNNode(geometry: ball)

        ballNode.name = “ball”

        ballNode.position = SCNVector3(x: 0, y: 1.2, z: 8)

        sceneView?.scene?.rootNode.addChildNode(ballNode)

    }

    

    func createCamera() {

        let camera = SCNNode()

        camera.camera = SCNCamera()

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

        camera.rotation = SCNVector4(x: 1, y: 0, z: 0, w: –0.6)

        camera.transform = SCNMatrix4Rotate(camera.transform, 0.5, 0, 1, 0)

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

    }

    

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

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

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

        

        sceneView?.scene?.rootNode.childNodes

            .filter {($0 as SCNNode).name == “marker”}

            .each {i in i.removeFromParentNode(); }

        let mid = CGRectGetMidY(self.sceneView!.frame)

        for (var i=0; i < Int(p.y mid); i+=10) {

            let marker = SCNBox(width: 0.2, height: 0.2, length: 0.2, chamferRadius: 0)

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

            let markerNode = SCNNode(geometry: marker)

            markerNode.name = “marker”

            markerNode.position = SCNVector3(x: Float(ball!.position.x), y: Float(ball!.position.y) + Float(i)/20.0, z: ball!.position.zFloat(i)/20.0)

            sceneView?.scene?.rootNode.addChildNode(markerNode)

        }

    }

    

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

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

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

        sceneView?.scene?.rootNode.childNodes

            .filter {($0 as SCNNode).name == “marker”}

            .each {i in i.removeFromParentNode(); }

        let dl = Float(p.y CGRectGetMidY(self.sceneView!.bounds))

        ball?.physicsBody = SCNPhysicsBody.dynamicBody()

        ball?.physicsBody?.applyForce(SCNVector3(x: 0, y: dl/10.0, z: -dl/10.0), impulse: true)

        

        ball?.name = “”

        

        func delay(delay:Double, doit:() -> Void) {

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), doit)

        }

        

        delay(1.0) {

            self.createBall()

        }

        

        delay(10.0) {

            ball!.removeFromParentNode()

        }

    }

}

extension Array {

    func each(doit:T->Void) { for i in self {doit(i);}}

}