iPhone影から階段

影から階段がニョキニョキ出てくるiPhoneアプリのサンプルコードを描いてみます。

import UIKit

import SceneKit

class ViewController: UIViewController, SCNPhysicsContactDelegate {

    weak var sceneView : SCNView?

    var start = false

    var count = 2

    

    override func viewDidLoad() {

        super.viewDidLoad()

        setupScene()

        create1F()

        createWall()

        createSteps()

        createJumper()

    }

    func setupScene() {

        let sv = SCNView(frame: view.bounds)

        sv.backgroundColor = UIColor.darkGrayColor()

        sv.scene = SCNScene()

        sv.scene?.physicsWorld.contactDelegate = self

        sv.allowsCameraControl = true

        sv.autoenablesDefaultLighting = true

        view.addSubview(sv)

        

        sceneView = sv

    }

    

    func createWall() {

        let wall = SCNBox(width: 10, height: 10, length: 0.1, chamferRadius: 0)

        wall.firstMaterial?.diffuse.contents = UIColor.darkGrayColor()

        let wallNode = SCNNode(geometry: wall)

        wallNode.position = SCNVector3(x: 0, y: 5, z: –0.5)

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

    }

    

    func create1F() {

        let f = SCNBox(width: 10, height: 0.2, length: 2, chamferRadius: 0)

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

        let fNode = SCNNode(geometry: f)

        fNode.physicsBody = SCNPhysicsBody.staticBody()

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

    }

    

    func createSteps() {

        for i in 0..<25 {

            let x = ((i / 5) % 2) == 0 ? Float(i % 5) – 1 : 2Float(i % 5)

            let y = Float(i / 5) * 2 + Float(i % 5) * 0.4

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

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

            let stepNode = SCNNode(geometry: step)

            stepNode.name = “step \(i)”

            stepNode.position = SCNVector3(x: Float(x), y: Float(y), z: 0)

            stepNode.physicsBody = SCNPhysicsBody.staticBody()

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

        }

    }

    

    func createJumper() {

        let jumper = SCNBox(width: 0.4, height: 0.4, length: 0.4, chamferRadius: 0.05)

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

        let jumperNode = SCNNode(geometry: jumper)

        jumperNode.name = “jumper”

        jumperNode.position = SCNVector3(x: –1, y: 1, z: 0)

        jumperNode.physicsBody = SCNPhysicsBody.dynamicBody()

        jumperNode.physicsBody?.friction = 0.9

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

    }

    

    func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact) {

        let step = [contact.nodeA, contact.nodeB]

            .filter {

                ($0 as SCNNode).name == “step \(self.count1)”

            }

        if step.count > 0 {

            if let nextStep = sceneView?.scene?.rootNode.childNodeWithName(“step \(self.count)”, recursively: false) {

                nextStep.runAction(SCNAction.sequence([SCNAction.waitForDuration(NSTimeInterval(0.2)) , SCNAction.moveTo(SCNVector3(x: nextStep.position.x, y: nextStep.position.y, z: 0), duration: 0.2)]))

                ++self.count

            }

        }

    }

    

    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {

        if !start {

            start = true

            self.sceneView?.scene?.rootNode.childNodes

                .filter {

                    if let check = ($0 as! SCNNode).name?.hasPrefix(“step”) { return check }

                    return false

                }

                .each { n -> Void in

                    if let n = n as? SCNNode {

                        var delay = 0.0

                        if let num = n.name?.componentsSeparatedByString(” “)[1].toInt() {

                            if num < 2 { return }

                            delay = Double(num) * 0.2

                        }

                        n.runAction(SCNAction.sequence([SCNAction.waitForDuration(NSTimeInterval(delay)) , SCNAction.moveByX(0, y: 0, z: –1, duration: 0.5)]))

                    }

                }

            return;

        }

        

        // jump

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

            if ((self.count1) / 5) % 2 == 0 {

                jump.physicsBody?.applyForce(SCNVector3(x: 1.6, y: 4, z: 0), impulse: true)

            } else {

                jump.physicsBody?.applyForce(SCNVector3(x: –1.6, y: 4, z: 0), impulse: true)

            }

        }

    }

}

extension Array {

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

}