Animation when activating parts of the background cube
This commit is contained in:
@@ -19,11 +19,14 @@ class BackgroundViewController: UIViewController {
|
|||||||
private var _sceneView: SCNView?
|
private var _sceneView: SCNView?
|
||||||
private var _cameraNode: SCNNode = SCNNode()
|
private var _cameraNode: SCNNode = SCNNode()
|
||||||
private var _cubletsNode: SCNNode = SCNNode()
|
private var _cubletsNode: SCNNode = SCNNode()
|
||||||
|
private var _cublets: [SCNNode] = []
|
||||||
|
|
||||||
static private let cubletsDimensions = 5
|
static private let cubletsDimensions = 5
|
||||||
static private let cubletsSize = 1.0
|
static private let cubletsSize = 1.0
|
||||||
static private let cubletsSpacing = 2.0
|
static private let cubletsSpacing = 2.0
|
||||||
|
|
||||||
|
// MARK: Overrides
|
||||||
|
|
||||||
override func loadView()
|
override func loadView()
|
||||||
{
|
{
|
||||||
let opts = [SCNPreferredRenderingAPIKey : SCNRenderingAPI.OpenGLES2.rawValue]
|
let opts = [SCNPreferredRenderingAPIKey : SCNRenderingAPI.OpenGLES2.rawValue]
|
||||||
@@ -31,7 +34,7 @@ class BackgroundViewController: UIViewController {
|
|||||||
view.backgroundColor = UIColor.blackColor()
|
view.backgroundColor = UIColor.blackColor()
|
||||||
view.scene = _scene
|
view.scene = _scene
|
||||||
view.allowsCameraControl = false
|
view.allowsCameraControl = false
|
||||||
/* view.showsStatistics = true */
|
view.showsStatistics = true
|
||||||
|
|
||||||
_sceneView = view
|
_sceneView = view
|
||||||
self.view = view
|
self.view = view
|
||||||
@@ -59,6 +62,45 @@ class BackgroundViewController: UIViewController {
|
|||||||
_sceneView?.stop(nil)
|
_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
|
// MARK: Internal
|
||||||
|
|
||||||
internal func _setupCamera()
|
internal func _setupCamera()
|
||||||
@@ -92,6 +134,8 @@ class BackgroundViewController: UIViewController {
|
|||||||
|
|
||||||
internal func _setupModel()
|
internal func _setupModel()
|
||||||
{
|
{
|
||||||
|
_cublets.removeAll()
|
||||||
|
|
||||||
let sz = Float(BackgroundViewController.cubletsSize)
|
let sz = Float(BackgroundViewController.cubletsSize)
|
||||||
let dim = BackgroundViewController.cubletsDimensions
|
let dim = BackgroundViewController.cubletsDimensions
|
||||||
let dimf = Float(dim)
|
let dimf = Float(dim)
|
||||||
@@ -99,15 +143,13 @@ class BackgroundViewController: UIViewController {
|
|||||||
let volume = (dimf * sz) + ((dimf - 1.0) * spacing)
|
let volume = (dimf * sz) + ((dimf - 1.0) * spacing)
|
||||||
let orig = -volume / 2.0
|
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()
|
let material = SCNMaterial()
|
||||||
material.diffuse.contents = UIColor.whiteColor()
|
material.diffuse.contents = UIColor.whiteColor()
|
||||||
material.transparency = 0.75
|
material.transparency = 0.75
|
||||||
|
|
||||||
// setup geometry
|
// generate nodes for each cublet
|
||||||
let geom = SCNBox(width: CGFloat(sz), height: CGFloat(sz), length: CGFloat(sz), chamferRadius: 0.0)
|
|
||||||
geom.firstMaterial = material
|
|
||||||
|
|
||||||
for var xi = 0; xi < dim; ++xi {
|
for var xi = 0; xi < dim; ++xi {
|
||||||
let x = orig + Float(xi) * (sz + spacing)
|
let x = orig + Float(xi) * (sz + spacing)
|
||||||
|
|
||||||
@@ -117,9 +159,13 @@ class BackgroundViewController: UIViewController {
|
|||||||
for var zi = 0; zi < dim; ++zi {
|
for var zi = 0; zi < dim; ++zi {
|
||||||
let z = orig + Float(zi) * (sz + spacing)
|
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)
|
node.position = SCNVector3Make(x, y, z)
|
||||||
_cubletsNode.addChildNode(node)
|
_cubletsNode.addChildNode(node)
|
||||||
|
_cublets.append(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,4 +190,10 @@ class BackgroundViewController: UIViewController {
|
|||||||
|
|
||||||
_sceneView?.technique = technique
|
_sceneView?.technique = technique
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal func _setCubletActivated(cublet: SCNNode, activated: Bool)
|
||||||
|
{
|
||||||
|
let material = cublet.geometry?.firstMaterial
|
||||||
|
material?.diffuse.contents = (activated ? UIColor.redColor() : UIColor.whiteColor())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import UIKit
|
|||||||
class MainViewController: UIViewController {
|
class MainViewController: UIViewController {
|
||||||
private var _backgroundController: BackgroundViewController = BackgroundViewController()
|
private var _backgroundController: BackgroundViewController = BackgroundViewController()
|
||||||
|
|
||||||
|
// MARK: Overrides
|
||||||
|
|
||||||
override func viewDidLoad()
|
override func viewDidLoad()
|
||||||
{
|
{
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
@@ -19,6 +21,15 @@ class MainViewController: UIViewController {
|
|||||||
|
|
||||||
self.addChildViewController(_backgroundController)
|
self.addChildViewController(_backgroundController)
|
||||||
self.view.addSubview(_backgroundController.view)
|
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
|
override func prefersStatusBarHidden() -> Bool
|
||||||
@@ -33,4 +44,17 @@ class MainViewController: UIViewController {
|
|||||||
let bounds = self.view.bounds
|
let bounds = self.view.bounds
|
||||||
_backgroundController.view.frame = 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user