iPhone回るスタンプ

棒をくるくる回しておいて、タップしたらそこにスタンプなiPhoneアプリのサンプルコードを描いてみます。(結構な頻度で exec bad access…)

import UIKit

import SceneKit

class ViewController: UIViewController, SCNSceneRendererDelegate {

    weak var sceneView : SCNView?

    var push : Bool = false

    

    override func viewDidLoad() {

        super.viewDidLoad()

        self.setupScene()

        self.createStampBoard()

        self.createStampHand()

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

        sv.scene = SCNScene()

        sv.scene?.physicsWorld.gravity = SCNVector3Zero

        sv.delegate = self

        self.view.addSubview(sv)

        

        self.sceneView = sv

    }

    func createStampBoard()

    {

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

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

        let boardNode = SCNNode(geometry: board)

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

    }

    

    func createStampHand() {

        let hand = SCNCylinder(radius: 0.5, height: 20)

        hand.firstMaterial?.diffuse.contents = UIColor(hue: 0.4, saturation: 0.9, brightness: 0.6, alpha: 1)

        let handNode = SCNNode(geometry: hand)

        handNode.name = “hand”

        handNode.position = SCNVector3(x: 0, y: 10, z: 4.0)

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

        self.addBodyToHand()

        

        let stamp = SCNCylinder(radius: 2, height: 3)

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

        let stampNode = SCNNode(geometry: stamp)

        stampNode.name = “stamp”

        stampNode.rotation = SCNVector4(x: 1, y: 0, z: 0, w: Float(M_PI/2.0))

        stampNode.position = SCNVector3(x:0, y:7, z:0)

        handNode.addChildNode(stampNode)

    }

    

    func createCamera() {

        let camera = SCNNode()

        camera.camera = SCNCamera()

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

        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: –20, z: 50)

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

    }

    

    func renderer(aRenderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) {

        

        // some time bad access …

        

        if (push) {

            return

        }

        

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

            

            let v = SCNVector3(x: hand.presentationNode().position.y/3.0, y: -hand.presentationNode().position.x/3.0, z: 0)

            if let body = hand.physicsBody {

                body.applyForce(v, impulse: false)

            }

        }

    }

    

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

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

            

            if let body = hand.physicsBody?{

                

                self.push = true

                body.velocity = SCNVector3Zero

                body.angularVelocity = SCNVector4Zero

                self.sceneView?.scene?.physicsWorld.removeAllBehaviors()

                let joint = SCNPhysicsHingeJoint(body: hand.physicsBody!, axis:SCNVector3(x: 1, y: 0, z: 0) , anchor: SCNVector3(x: 0, y: –9, z: 0))

                self.sceneView?.scene?.physicsWorld.addBehavior(joint)

                let op = hand.presentationNode().position

                let ow = hand.presentationNode().rotation

                body.applyForce(SCNVector3(x: 0, y: 0, z: –10), impulse:true);

                

                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(Double(NSEC_PER_SEC) * 0.2)), dispatch_get_main_queue(), {

                    

                    self.stamp()

                    

                    hand.physicsBody = nil

                    SCNTransaction.begin()

                    SCNTransaction.setAnimationDuration(0.1)

                    hand.presentationNode().position = op

                    hand.presentationNode().rotation = ow

                    

                    SCNTransaction.setCompletionBlock({ () -> Void in

                        self.addBodyToHand()

                        self.push = false

                    })

                    

                    SCNTransaction.commit()

                })

            }

            

        }

    }

    

    func stamp () {

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

            let s = SCNBox(width: 3, height: 3, length: 0.1, chamferRadius: 0)

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

            let sNode = SCNNode(geometry: s)

            var stampPosition = hand.presentationNode().position

            sNode.position = SCNVector3(x: 1.8 * stampPosition.x, y: 1.8 * stampPosition.y, z: 1)

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

        }

    }

    

    func addBodyToHand () {

        

        self.sceneView?.scene?.physicsWorld.removeAllBehaviors()

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

            handNode.physicsBody = SCNPhysicsBody.dynamicBody()

            handNode.physicsBody?.allowsResting = false

            let joint = SCNPhysicsHingeJoint(body: handNode.physicsBody!, axis:SCNVector3(x: 0, y: 0, z: 1) , anchor: SCNVector3(x: 0, y: –9, z: 0))

            self.sceneView?.scene?.physicsWorld.addBehavior(joint)

        }

    }

}