From 00fcca6893fed394267342062e8e0e6571a6d891 Mon Sep 17 00:00:00 2001 From: Charles Magahern Date: Wed, 30 Dec 2015 16:56:15 -0800 Subject: [PATCH] Animation when activating parts of the background cube --- .../BackgroundViewController.swift | 68 ++++++++++++++++--- .../Controllers/MainViewController.swift | 24 +++++++ 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/XIONControlPanel/Controllers/BackgroundViewController.swift b/XIONControlPanel/Controllers/BackgroundViewController.swift index 25e3c2d..aa1fdc5 100644 --- a/XIONControlPanel/Controllers/BackgroundViewController.swift +++ b/XIONControlPanel/Controllers/BackgroundViewController.swift @@ -19,11 +19,14 @@ class BackgroundViewController: UIViewController { private var _sceneView: SCNView? private var _cameraNode: SCNNode = SCNNode() private var _cubletsNode: SCNNode = SCNNode() + private var _cublets: [SCNNode] = [] static private let cubletsDimensions = 5 static private let cubletsSize = 1.0 static private let cubletsSpacing = 2.0 + // MARK: Overrides + override func loadView() { let opts = [SCNPreferredRenderingAPIKey : SCNRenderingAPI.OpenGLES2.rawValue] @@ -31,7 +34,7 @@ class BackgroundViewController: UIViewController { view.backgroundColor = UIColor.blackColor() view.scene = _scene view.allowsCameraControl = false - /* view.showsStatistics = true */ + view.showsStatistics = true _sceneView = view self.view = view @@ -59,6 +62,45 @@ class BackgroundViewController: UIViewController { _sceneView?.stop(nil) } + // MARK: API + + func setPercentActivated(percentage: Float, animated: Bool) + { + let cubletsCount = _cublets.count + let cubletsToActivate = UInt(percentage * Float(cubletsCount)) + var shuffledCublets = _cublets + var cubletsActivated: UInt = 0 + + for i in 0 ..< cubletsCount { + let rnd = Int(arc4random_uniform(UInt32(cubletsCount))) + let tmp = shuffledCublets[rnd] + shuffledCublets[rnd] = shuffledCublets[i] + shuffledCublets[i] = tmp + } + + for cublet in shuffledCublets { + _setCubletActivated(cublet, activated: (cubletsActivated < cubletsToActivate)) + ++cubletsActivated + } + + if (animated) { + let rx = Float(arc4random()) / Float(UInt32.max) + let ry = Float(arc4random()) / Float(UInt32.max) + let rz = Float(arc4random()) / Float(UInt32.max) + let rotAxis = SCNVector3Make(rx, ry, rz) + let rotCoeff = Float(arc4random() % 2 == 0 ? -1.0 : 1.0) + let rotAngle = CGFloat(rotCoeff * π / 4.0) + + let rotAction = SCNAction.rotateByAngle(rotAngle, aroundAxis: rotAxis, duration: 0.8) + rotAction.timingMode = .Linear + rotAction.timingFunction = { (t: Float) -> Float in + return min(((log10(4.0 * (t + 0.03)) + 1.0) / 1.5), 1.0) + } + + _cubletsNode.runAction(rotAction) + } + } + // MARK: Internal internal func _setupCamera() @@ -92,6 +134,8 @@ class BackgroundViewController: UIViewController { internal func _setupModel() { + _cublets.removeAll() + let sz = Float(BackgroundViewController.cubletsSize) let dim = BackgroundViewController.cubletsDimensions let dimf = Float(dim) @@ -99,15 +143,13 @@ class BackgroundViewController: UIViewController { let volume = (dimf * sz) + ((dimf - 1.0) * spacing) let orig = -volume / 2.0 - // setup material + // setup material and geometry. each node needs its own material for activation effect. + let geom = SCNBox(width: CGFloat(sz), height: CGFloat(sz), length: CGFloat(sz), chamferRadius: 0.0) let material = SCNMaterial() material.diffuse.contents = UIColor.whiteColor() material.transparency = 0.75 - // setup geometry - let geom = SCNBox(width: CGFloat(sz), height: CGFloat(sz), length: CGFloat(sz), chamferRadius: 0.0) - geom.firstMaterial = material - + // generate nodes for each cublet for var xi = 0; xi < dim; ++xi { let x = orig + Float(xi) * (sz + spacing) @@ -117,9 +159,13 @@ class BackgroundViewController: UIViewController { for var zi = 0; zi < dim; ++zi { let z = orig + Float(zi) * (sz + spacing) - let node = SCNNode(geometry: geom) + let nodeGeom = geom.copy() as! SCNGeometry + nodeGeom.firstMaterial = material.copy() as? SCNMaterial + + let node = SCNNode(geometry: nodeGeom) node.position = SCNVector3Make(x, y, z) _cubletsNode.addChildNode(node) + _cublets.append(node) } } } @@ -131,7 +177,7 @@ class BackgroundViewController: UIViewController { internal func _setupAnimation() { let rotAxis = SCNVector3Make(0.25, 1.75, 1.0) - let rotAngle = CGFloat(Float(2.0)*π) + let rotAngle = CGFloat(Float(2.0) * π) let rotAction = SCNAction.repeatActionForever(SCNAction.rotateByAngle(rotAngle, aroundAxis: rotAxis, duration: 40.0)) _cubletsNode.runAction(rotAction) } @@ -144,4 +190,10 @@ class BackgroundViewController: UIViewController { _sceneView?.technique = technique } + + internal func _setCubletActivated(cublet: SCNNode, activated: Bool) + { + let material = cublet.geometry?.firstMaterial + material?.diffuse.contents = (activated ? UIColor.redColor() : UIColor.whiteColor()) + } } diff --git a/XIONControlPanel/Controllers/MainViewController.swift b/XIONControlPanel/Controllers/MainViewController.swift index aba8138..3bc7456 100644 --- a/XIONControlPanel/Controllers/MainViewController.swift +++ b/XIONControlPanel/Controllers/MainViewController.swift @@ -11,6 +11,8 @@ import UIKit class MainViewController: UIViewController { private var _backgroundController: BackgroundViewController = BackgroundViewController() + // MARK: Overrides + override func viewDidLoad() { super.viewDidLoad() @@ -19,6 +21,15 @@ class MainViewController: UIViewController { self.addChildViewController(_backgroundController) self.view.addSubview(_backgroundController.view) + + let doubleTapGR = UITapGestureRecognizer(target: self, action: Selector("_handleDoubleFingerTap:")) + doubleTapGR.numberOfTouchesRequired = 2 + self.view.addGestureRecognizer(doubleTapGR) + + let singleTapGR = UITapGestureRecognizer(target: self, action: Selector("_handleSingleFingerTap:")) + singleTapGR.numberOfTouchesRequired = 1 + singleTapGR.requireGestureRecognizerToFail(doubleTapGR) + self.view.addGestureRecognizer(singleTapGR) } override func prefersStatusBarHidden() -> Bool @@ -33,4 +44,17 @@ class MainViewController: UIViewController { let bounds = self.view.bounds _backgroundController.view.frame = bounds } + + // MARK: Internal + + internal func _handleSingleFingerTap(gestureRecognizer: UITapGestureRecognizer) + { + let randomPercentage = Float(arc4random()) / Float(UInt32.max) + _backgroundController.setPercentActivated(randomPercentage, animated: true) + } + + internal func _handleDoubleFingerTap(gestureRecognizer: UITapGestureRecognizer) + { + _backgroundController.setPercentActivated(0.0, animated: true) + } }