diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100755 index 0000000..d9cd508 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,21 @@ +disabled_rules: + - variable_name +excluded: + - Carthage + - Pods +line_length: 128 +type_body_length: + - 500 # warning + - 700 # error +file_length: + warning: 500 + error: 1200 +warning_threshold: 1 + +custom_rules: + uiwebview_disabled: + included: ".*.swift" + name: "UIWebView Usage Disabled" + regex: "(UIWebView)" + message: "Do not use UIWebView. Use WKWebView Instead. https://developer.apple.com/reference/uikit/uiwebview" + severity: error \ No newline at end of file diff --git a/.tailor.yml b/.tailor.yml new file mode 100755 index 0000000..a460616 --- /dev/null +++ b/.tailor.yml @@ -0,0 +1,3 @@ +exclude: + - 'Pods' + - 'Carthage' \ No newline at end of file diff --git a/ARTest.xcodeproj/project.pbxproj b/ARTest.xcodeproj/project.pbxproj index 99dc217..6dc1262 100644 --- a/ARTest.xcodeproj/project.pbxproj +++ b/ARTest.xcodeproj/project.pbxproj @@ -94,6 +94,8 @@ 0AC0DA3A1EE99233006E2CC9 /* Sources */, 0AC0DA3B1EE99233006E2CC9 /* Frameworks */, 0AC0DA3C1EE99233006E2CC9 /* Resources */, + 0AA8505A1EF3FB4E00353B55 /* SwiftLint */, + 0AA8505B1EF3FBE200353B55 /* Tailor */, ); buildRules = ( ); @@ -151,6 +153,37 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 0AA8505A1EF3FB4E00353B55 /* SwiftLint */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = SwiftLint; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; + }; + 0AA8505B1EF3FBE200353B55 /* Tailor */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = Tailor; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if hash tailor 2>/dev/null; then\ntailor\nfi"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 0AC0DA3A1EE99233006E2CC9 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -303,7 +336,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.touchInstinct.ARTest; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Debug; }; @@ -317,7 +350,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.touchInstinct.ARTest; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Release; }; diff --git a/ARTest/AppDelegate.swift b/ARTest/AppDelegate.swift index 22e9d8e..af100db 100644 --- a/ARTest/AppDelegate.swift +++ b/ARTest/AppDelegate.swift @@ -23,38 +23,13 @@ import UIKit @UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { +final class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { return true } - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - } - diff --git a/ARTest/Base.lproj/LaunchScreen.storyboard b/ARTest/Base.lproj/LaunchScreen.storyboard index 14e2029..6fc4439 100644 --- a/ARTest/Base.lproj/LaunchScreen.storyboard +++ b/ARTest/Base.lproj/LaunchScreen.storyboard @@ -1,10 +1,11 @@ - + + @@ -12,10 +13,6 @@ - - - - @@ -50,16 +47,17 @@ - - - + + - - - - - + + + + + + + diff --git a/ARTest/Base.lproj/Main.storyboard b/ARTest/Base.lproj/Main.storyboard index 1629384..4a1f4e7 100644 --- a/ARTest/Base.lproj/Main.storyboard +++ b/ARTest/Base.lproj/Main.storyboard @@ -1,11 +1,12 @@ - + + @@ -13,10 +14,6 @@ - - - - @@ -53,20 +50,22 @@ - - + + - - + + + - - - - - - - + + + + + + + + diff --git a/ARTest/Objects/ARBullet.swift b/ARTest/Objects/ARBullet.swift index 31113c7..1cbb930 100644 --- a/ARTest/Objects/ARBullet.swift +++ b/ARTest/Objects/ARBullet.swift @@ -23,12 +23,22 @@ import UIKit import SceneKit -class ARBullet: SCNNode { +final class ARBullet: SCNNode { + + private static let sphereRadius: CGFloat = 0.025 override init() { super.init() + initialization() + } - let arKitBox = SCNSphere(radius: 0.025) + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + initialization() + } + + private func initialization() { + let arKitBox = SCNSphere(radius: ARBullet.sphereRadius) self.geometry = arKitBox let shape = SCNPhysicsShape(geometry: arKitBox, options: nil) self.physicsBody = SCNPhysicsBody(type: .dynamic, shape: shape) @@ -43,8 +53,4 @@ class ARBullet: SCNNode { self.geometry?.materials = [material] } - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - } diff --git a/ARTest/Objects/Logo.swift b/ARTest/Objects/Logo.swift index 7be4261..c6a3e6c 100644 --- a/ARTest/Objects/Logo.swift +++ b/ARTest/Objects/Logo.swift @@ -23,12 +23,25 @@ import UIKit import SceneKit -class Logo: SCNNode { +final class Logo: SCNNode { + + private static let boxSide: CGFloat = 0.1 override init() { super.init() + initialization() + } - let logo = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0) + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + initialization() + } + + private func initialization() { + let logo = SCNBox(width: Logo.boxSide, + height: Logo.boxSide, + length: Logo.boxSide, + chamferRadius: 0) self.geometry = logo let shape = SCNPhysicsShape(geometry: logo, options: nil) @@ -44,8 +57,4 @@ class Logo: SCNNode { self.geometry?.materials = [material, material, material, material, material, material] } - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - } diff --git a/ARTest/ViewController.swift b/ARTest/ViewController.swift index 857c82c..d33a655 100644 --- a/ARTest/ViewController.swift +++ b/ARTest/ViewController.swift @@ -28,21 +28,22 @@ private enum GameState { case shootting } -class ViewController: UIViewController, ARSCNViewDelegate { +final class ViewController: UIViewController, ARSCNViewDelegate { // MARK: - Constants private static let logoMaxCount = 3 + private static let cameraToLogoSpace: Float = -1 // MARK: - IBOutlets - @IBOutlet weak var sceneView: ARSCNView! - @IBOutlet weak var timeLabel: UILabel! - @IBOutlet weak var scoreLabel: UILabel! - @IBOutlet weak var prizelImageView: UIImageView! + @IBOutlet private weak var sceneView: ARSCNView! + @IBOutlet private weak var timeLabel: UILabel! + @IBOutlet private weak var scoreLabel: UILabel! + @IBOutlet private weak var prizelImageView: UIImageView! // MARK: - Properties - + fileprivate var state: GameState = .placing { didSet { prizelImageView.isHidden = state == .placing @@ -59,12 +60,12 @@ class ViewController: UIViewController, ARSCNViewDelegate { fileprivate var gameTimer: Timer? // MARK: - ViewController life cycle - + override func viewDidLoad() { super.viewDidLoad() sceneView.scene.physicsWorld.contactDelegate = self - + // Show statistics such as fps and timing information sceneView.showsStatistics = true @@ -73,10 +74,10 @@ class ViewController: UIViewController, ARSCNViewDelegate { logoCount = 0 } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + // Create a session configuration let configuration = ARSessionConfiguration.isSupported ? ARWorldTrackingSessionConfiguration() : ARSessionConfiguration() @@ -84,19 +85,14 @@ class ViewController: UIViewController, ARSCNViewDelegate { // Run the view's session sceneView.session.run(configuration) } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - + // Pause the view's session sceneView.session.pause() stopGame() } - - override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - // Release any cached data, images, etc that aren't in use. - } // MARK: - Actions @@ -118,7 +114,7 @@ class ViewController: UIViewController, ARSCNViewDelegate { sceneView.scene.rootNode.addChildNode(logo) var translation = matrix_identity_float4x4 - translation.columns.3.z = -1 + translation.columns.3.z = ViewController.cameraToLogoSpace logo.simdTransform = matrix_multiply(currentFrame.camera.transform, translation) logoCount += 1 @@ -168,12 +164,12 @@ extension ViewController { } fileprivate func configureTimeLabel() { - self.timeLabel.isHidden = self.gameSeconds == 0 + timeLabel.isHidden = self.gameSeconds == 0 let seconds = self.gameSeconds % 60 - let minutes = (self.gameSeconds / 60) % 60; + let minutes = (self.gameSeconds / 60) % 60 - self.timeLabel.text = String(format: "%02d:%02d", minutes, seconds) + timeLabel.text = String(format: "%02d:%02d", minutes, seconds) } }