├── .gitignore ├── LICENSE.txt ├── README.md ├── README2.md ├── SceneKitVehicle.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── dev.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── dev.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── SceneKitVehicle.xcscheme │ └── xcschememanagement.plist └── SceneKitVehicle ├── AAPLAppDelegate.h ├── AAPLAppDelegate.m ├── AAPLGameView.h ├── AAPLGameView.m ├── AAPLGameViewController.h ├── AAPLGameViewController.m ├── AAPLOverlayScene.h ├── AAPLOverlayScene.m ├── AppDelegate.swift ├── Base.lproj ├── Main_iPad.storyboard └── Main_iPhone.storyboard ├── GameView.swift ├── GameViewController.swift ├── Images.xcassets ├── AppIcon.appiconset │ ├── Contents.json │ ├── icon-1.png │ ├── icon-1024.png │ ├── icon-2.png │ ├── icon-3.png │ ├── icon-4.png │ ├── icon-5.png │ ├── icon-6.png │ ├── icon-7.png │ ├── icon-8.png │ ├── icon-9.png │ └── icon.png ├── LaunchImage.launchimage │ ├── Contents.json │ ├── launch-1.png │ ├── launch-4.png │ └── launch.png └── texture.imageset │ ├── Contents.json │ └── texture.png ├── OverlayScene.swift ├── SceneKitVehicle-Info.plist ├── SceneKitVehicle-Prefix.pch ├── en.lproj └── InfoPlist.strings ├── main.m └── resources ├── WoodCubeA.jpg ├── WoodCubeB.jpg ├── WoodCubeC.jpg ├── ball.jpg ├── book_back.jpg ├── book_front.jpg ├── book_side.jpg ├── book_side_title.jpg ├── carpet.jpg ├── carpetOld.jpg ├── click.caf ├── icon.png ├── krStar.png ├── launch.png ├── needle.png ├── rc_car.dae ├── rc_car_texture.png ├── reactor.scnp ├── smoke.png ├── smoke.scnp ├── spark.png ├── speedGauge.png ├── starBurst.skn ├── tex_smoke.png ├── tire.jpg ├── train_flat.dae ├── train_wood.jpg ├── video_camera.png ├── video_camera@2x.png ├── wall.jpg ├── wheel.png └── wood.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Sample code project: SceneKit Vehicle Demo 2 | Version: 1.0 3 | 4 | IMPORTANT: This Apple software is supplied to you by Apple 5 | Inc. ("Apple") in consideration of your agreement to the following 6 | terms, and your use, installation, modification or redistribution of 7 | this Apple software constitutes acceptance of these terms. If you do 8 | not agree with these terms, please do not use, install, modify or 9 | redistribute this Apple software. 10 | 11 | In consideration of your agreement to abide by the following terms, and 12 | subject to these terms, Apple grants you a personal, non-exclusive 13 | license, under Apple's copyrights in this original Apple software (the 14 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 15 | Software, with or without modifications, in source and/or binary forms; 16 | provided that if you redistribute the Apple Software in its entirety and 17 | without modifications, you must retain this notice and the following 18 | text and disclaimers in all such redistributions of the Apple Software. 19 | Neither the name, trademarks, service marks or logos of Apple Inc. may 20 | be used to endorse or promote products derived from the Apple Software 21 | without specific prior written permission from Apple. Except as 22 | expressly stated in this notice, no other rights or licenses, express or 23 | implied, are granted by Apple herein, including but not limited to any 24 | patent rights that may be infringed by your derivative works or by other 25 | works in which the Apple Software may be incorporated. 26 | 27 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 28 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 29 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 30 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 31 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 32 | 33 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 34 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 36 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 37 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 38 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 39 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 40 | POSSIBILITY OF SUCH DAMAGE. 41 | 42 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SceneKit Vehicle Demo 2 | 3 | This sample code shows how to simulate a vehicle using the SCNPhysicsVehicle behaviour. The vehicle can be controller with either the accelerometer or a game controller. It also illustrate basic physics interaction and game overlays done with SpriteKit. 4 | 5 | ## Requirements 6 | 7 | ### Build 8 | 9 | iOS 8 10 | 11 | ### Runtime 12 | 13 | iOS 8 14 | 15 | Copyright (C) 2014 Apple Inc. All rights reserved. 16 | -------------------------------------------------------------------------------- /README2.md: -------------------------------------------------------------------------------- 1 | #SceneKitVehicle 2 | 3 | Translated by OOPer in cooperation with shlab.jp, on 2015/2/15. 4 | 5 | Based on 6 | 7 | 2014-09-17. 8 | 9 | As this is a line-by-line translation from the original sample code, "redistribute the Apple Software in its entirety and without modifications" would apply. See LICENSE.txt . 10 | Some faults caused by my translation may exist. Not all features tested. 11 | You should not contact to Apple or SHLab(jp) about any faults caused by my translation. 12 | 13 | ## Requirements 14 | 15 | ### Build 16 | 17 | iOS 12.2 SDK, Xcode 10.2 18 | -------------------------------------------------------------------------------- /SceneKitVehicle.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 116C81F2192EA73E0001FC16 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 116C81F1192EA73E0001FC16 /* UIKit.framework */; }; 11 | 116C81F4192EA78F0001FC16 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 116C81F3192EA78F0001FC16 /* GameController.framework */; }; 12 | 116C81F6192EA7980001FC16 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 116C81F5192EA7980001FC16 /* CoreMotion.framework */; }; 13 | 116C81F8192EA8E80001FC16 /* SceneKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 116C81F7192EA8E80001FC16 /* SceneKit.framework */; }; 14 | 116C81FA192EA8EF0001FC16 /* SpriteKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 116C81F9192EA8EF0001FC16 /* SpriteKit.framework */; }; 15 | 945AD79E18F1FB0800351CB5 /* reactor.scnp in Resources */ = {isa = PBXBuildFile; fileRef = 945AD79D18F1FB0800351CB5 /* reactor.scnp */; }; 16 | 945AD7A118F1FB2500351CB5 /* smoke.scnp in Resources */ = {isa = PBXBuildFile; fileRef = 945AD79F18F1FB2500351CB5 /* smoke.scnp */; }; 17 | 945AD7A218F1FB2500351CB5 /* smoke.png in Resources */ = {isa = PBXBuildFile; fileRef = 945AD7A018F1FB2500351CB5 /* smoke.png */; }; 18 | 9461831918F08C1D00FDFE48 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9461831718F08C1D00FDFE48 /* InfoPlist.strings */; }; 19 | 9461832218F08C1D00FDFE48 /* Main_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9461832018F08C1D00FDFE48 /* Main_iPhone.storyboard */; }; 20 | 9461832518F08C1D00FDFE48 /* Main_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9461832318F08C1D00FDFE48 /* Main_iPad.storyboard */; }; 21 | 9461832A18F08C1D00FDFE48 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9461832918F08C1D00FDFE48 /* Images.xcassets */; }; 22 | 94A4856318F1FAB200775D5E /* ball.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4854518F1FAB200775D5E /* ball.jpg */; }; 23 | 94A4856418F1FAB200775D5E /* book_back.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4854618F1FAB200775D5E /* book_back.jpg */; }; 24 | 94A4856518F1FAB200775D5E /* book_front.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4854718F1FAB200775D5E /* book_front.jpg */; }; 25 | 94A4856618F1FAB200775D5E /* book_side_title.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4854818F1FAB200775D5E /* book_side_title.jpg */; }; 26 | 94A4856718F1FAB200775D5E /* book_side.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4854918F1FAB200775D5E /* book_side.jpg */; }; 27 | 94A4856818F1FAB200775D5E /* carpet.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4854A18F1FAB200775D5E /* carpet.jpg */; }; 28 | 94A4856918F1FAB200775D5E /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 94A4854B18F1FAB200775D5E /* icon.png */; }; 29 | 94A4856A18F1FAB200775D5E /* krStar.png in Resources */ = {isa = PBXBuildFile; fileRef = 94A4854C18F1FAB200775D5E /* krStar.png */; }; 30 | 94A4856B18F1FAB200775D5E /* launch.png in Resources */ = {isa = PBXBuildFile; fileRef = 94A4854D18F1FAB200775D5E /* launch.png */; }; 31 | 94A4856C18F1FAB200775D5E /* needle.png in Resources */ = {isa = PBXBuildFile; fileRef = 94A4854E18F1FAB200775D5E /* needle.png */; }; 32 | 94A4857018F1FAB200775D5E /* spark.png in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855218F1FAB200775D5E /* spark.png */; }; 33 | 94A4857118F1FAB200775D5E /* speedGauge.png in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855318F1FAB200775D5E /* speedGauge.png */; }; 34 | 94A4857218F1FAB200775D5E /* starBurst.skn in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855418F1FAB200775D5E /* starBurst.skn */; }; 35 | 94A4857418F1FAB200775D5E /* tex_smoke.png in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855618F1FAB200775D5E /* tex_smoke.png */; }; 36 | 94A4857518F1FAB200775D5E /* tire.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855718F1FAB200775D5E /* tire.jpg */; }; 37 | 94A4857618F1FAB200775D5E /* train_flat.dae in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855818F1FAB200775D5E /* train_flat.dae */; }; 38 | 94A4857718F1FAB200775D5E /* train_wood.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855918F1FAB200775D5E /* train_wood.jpg */; }; 39 | 94A4857818F1FAB200775D5E /* video_camera.png in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855A18F1FAB200775D5E /* video_camera.png */; }; 40 | 94A4857918F1FAB200775D5E /* video_camera@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855B18F1FAB200775D5E /* video_camera@2x.png */; }; 41 | 94A4857A18F1FAB200775D5E /* wall.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855C18F1FAB200775D5E /* wall.jpg */; }; 42 | 94A4857B18F1FAB200775D5E /* wheel.png in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855D18F1FAB200775D5E /* wheel.png */; }; 43 | 94A4857C18F1FAB200775D5E /* wood.png in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855E18F1FAB200775D5E /* wood.png */; }; 44 | 94A4857D18F1FAB200775D5E /* WoodCubeA.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4855F18F1FAB200775D5E /* WoodCubeA.jpg */; }; 45 | 94A4857E18F1FAB200775D5E /* WoodCubeB.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4856018F1FAB200775D5E /* WoodCubeB.jpg */; }; 46 | 94A4857F18F1FAB200775D5E /* WoodCubeC.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 94A4856118F1FAB200775D5E /* WoodCubeC.jpg */; }; 47 | 9655E4E819265809006C3A3B /* click.caf in Resources */ = {isa = PBXBuildFile; fileRef = 9655E4E719265697006C3A3B /* click.caf */; }; 48 | 9C765F11193561FE00C1D23C /* rc_car_texture.png in Resources */ = {isa = PBXBuildFile; fileRef = 9C765F10193561FE00C1D23C /* rc_car_texture.png */; }; 49 | 9CF4337B19354D75001A1D66 /* rc_car.dae in Resources */ = {isa = PBXBuildFile; fileRef = 9CF4337A19354D75001A1D66 /* rc_car.dae */; }; 50 | D75314AA19B795110021B0F8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75314A919B795110021B0F8 /* AppDelegate.swift */; }; 51 | D79862B419B358F200ADDB1D /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D7D2EC19A0CEE90065D098 /* GameViewController.swift */; }; 52 | D7D7D2BB19A034B20065D098 /* OverlayScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D7D2BA19A034B20065D098 /* OverlayScene.swift */; }; 53 | D7D7D2EB19A0CA7D0065D098 /* GameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D7D2EA19A0CA7D0065D098 /* GameView.swift */; }; 54 | /* End PBXBuildFile section */ 55 | 56 | /* Begin PBXFileReference section */ 57 | 116C81F1192EA73E0001FC16 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 58 | 116C81F3192EA78F0001FC16 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; }; 59 | 116C81F5192EA7980001FC16 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = System/Library/Frameworks/CoreMotion.framework; sourceTree = SDKROOT; }; 60 | 116C81F7192EA8E80001FC16 /* SceneKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SceneKit.framework; path = System/Library/Frameworks/SceneKit.framework; sourceTree = SDKROOT; }; 61 | 116C81F9192EA8EF0001FC16 /* SpriteKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SpriteKit.framework; path = System/Library/Frameworks/SpriteKit.framework; sourceTree = SDKROOT; }; 62 | 945AD79D18F1FB0800351CB5 /* reactor.scnp */ = {isa = PBXFileReference; lastKnownFileType = file.scp; path = reactor.scnp; sourceTree = ""; }; 63 | 945AD79F18F1FB2500351CB5 /* smoke.scnp */ = {isa = PBXFileReference; lastKnownFileType = file.scp; path = smoke.scnp; sourceTree = ""; }; 64 | 945AD7A018F1FB2500351CB5 /* smoke.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = smoke.png; sourceTree = ""; }; 65 | 9461831218F08C1D00FDFE48 /* SceneKitVehicle.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SceneKitVehicle.app; sourceTree = BUILT_PRODUCTS_DIR; }; 66 | 9461831618F08C1D00FDFE48 /* SceneKitVehicle-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SceneKitVehicle-Info.plist"; sourceTree = ""; }; 67 | 9461831818F08C1D00FDFE48 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 68 | 9461832118F08C1D00FDFE48 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main_iPhone.storyboard; sourceTree = ""; }; 69 | 9461832418F08C1D00FDFE48 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main_iPad.storyboard; sourceTree = ""; }; 70 | 9461832918F08C1D00FDFE48 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 71 | 94A4854518F1FAB200775D5E /* ball.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = ball.jpg; sourceTree = ""; }; 72 | 94A4854618F1FAB200775D5E /* book_back.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = book_back.jpg; sourceTree = ""; }; 73 | 94A4854718F1FAB200775D5E /* book_front.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = book_front.jpg; sourceTree = ""; }; 74 | 94A4854818F1FAB200775D5E /* book_side_title.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = book_side_title.jpg; sourceTree = ""; }; 75 | 94A4854918F1FAB200775D5E /* book_side.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = book_side.jpg; sourceTree = ""; }; 76 | 94A4854A18F1FAB200775D5E /* carpet.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = carpet.jpg; sourceTree = ""; }; 77 | 94A4854B18F1FAB200775D5E /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = ""; }; 78 | 94A4854C18F1FAB200775D5E /* krStar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = krStar.png; sourceTree = ""; }; 79 | 94A4854D18F1FAB200775D5E /* launch.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = launch.png; sourceTree = ""; }; 80 | 94A4854E18F1FAB200775D5E /* needle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = needle.png; sourceTree = ""; }; 81 | 94A4855218F1FAB200775D5E /* spark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = spark.png; sourceTree = ""; }; 82 | 94A4855318F1FAB200775D5E /* speedGauge.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = speedGauge.png; sourceTree = ""; }; 83 | 94A4855418F1FAB200775D5E /* starBurst.skn */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = starBurst.skn; sourceTree = ""; }; 84 | 94A4855618F1FAB200775D5E /* tex_smoke.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tex_smoke.png; sourceTree = ""; }; 85 | 94A4855718F1FAB200775D5E /* tire.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = tire.jpg; sourceTree = ""; }; 86 | 94A4855818F1FAB200775D5E /* train_flat.dae */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml.dae; path = train_flat.dae; sourceTree = ""; }; 87 | 94A4855918F1FAB200775D5E /* train_wood.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = train_wood.jpg; sourceTree = ""; }; 88 | 94A4855A18F1FAB200775D5E /* video_camera.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = video_camera.png; sourceTree = ""; }; 89 | 94A4855B18F1FAB200775D5E /* video_camera@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "video_camera@2x.png"; sourceTree = ""; }; 90 | 94A4855C18F1FAB200775D5E /* wall.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = wall.jpg; sourceTree = ""; }; 91 | 94A4855D18F1FAB200775D5E /* wheel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = wheel.png; sourceTree = ""; }; 92 | 94A4855E18F1FAB200775D5E /* wood.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = wood.png; sourceTree = ""; }; 93 | 94A4855F18F1FAB200775D5E /* WoodCubeA.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = WoodCubeA.jpg; sourceTree = ""; }; 94 | 94A4856018F1FAB200775D5E /* WoodCubeB.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = WoodCubeB.jpg; sourceTree = ""; }; 95 | 94A4856118F1FAB200775D5E /* WoodCubeC.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = WoodCubeC.jpg; sourceTree = ""; }; 96 | 9655E4E719265697006C3A3B /* click.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = click.caf; sourceTree = ""; }; 97 | 9C765F10193561FE00C1D23C /* rc_car_texture.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = rc_car_texture.png; sourceTree = ""; }; 98 | 9CF4337A19354D75001A1D66 /* rc_car.dae */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml.dae; path = rc_car.dae; sourceTree = ""; }; 99 | D75314A919B795110021B0F8 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 100 | D75EB98E1A9075210039D093 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 101 | D75EB98F1A9075210039D093 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 102 | D75EB9921A90756B0039D093 /* README2.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README2.md; sourceTree = ""; }; 103 | D7D7D2BA19A034B20065D098 /* OverlayScene.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverlayScene.swift; sourceTree = ""; }; 104 | D7D7D2EA19A0CA7D0065D098 /* GameView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameView.swift; sourceTree = ""; }; 105 | D7D7D2EC19A0CEE90065D098 /* GameViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; }; 106 | /* End PBXFileReference section */ 107 | 108 | /* Begin PBXFrameworksBuildPhase section */ 109 | 9461830F18F08C1D00FDFE48 /* Frameworks */ = { 110 | isa = PBXFrameworksBuildPhase; 111 | buildActionMask = 2147483647; 112 | files = ( 113 | 116C81FA192EA8EF0001FC16 /* SpriteKit.framework in Frameworks */, 114 | 116C81F8192EA8E80001FC16 /* SceneKit.framework in Frameworks */, 115 | 116C81F6192EA7980001FC16 /* CoreMotion.framework in Frameworks */, 116 | 116C81F4192EA78F0001FC16 /* GameController.framework in Frameworks */, 117 | 116C81F2192EA73E0001FC16 /* UIKit.framework in Frameworks */, 118 | ); 119 | runOnlyForDeploymentPostprocessing = 0; 120 | }; 121 | /* End PBXFrameworksBuildPhase section */ 122 | 123 | /* Begin PBXGroup section */ 124 | 116C81FB192EAD9E0001FC16 /* Frameworks */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 116C81F9192EA8EF0001FC16 /* SpriteKit.framework */, 128 | 116C81F7192EA8E80001FC16 /* SceneKit.framework */, 129 | 116C81F5192EA7980001FC16 /* CoreMotion.framework */, 130 | 116C81F3192EA78F0001FC16 /* GameController.framework */, 131 | 116C81F1192EA73E0001FC16 /* UIKit.framework */, 132 | ); 133 | name = Frameworks; 134 | sourceTree = ""; 135 | }; 136 | 944CD35318F1D91500F4DCDA /* Resources */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 94A4854518F1FAB200775D5E /* ball.jpg */, 140 | 94A4854618F1FAB200775D5E /* book_back.jpg */, 141 | 94A4854718F1FAB200775D5E /* book_front.jpg */, 142 | 94A4854818F1FAB200775D5E /* book_side_title.jpg */, 143 | 94A4854918F1FAB200775D5E /* book_side.jpg */, 144 | 94A4854A18F1FAB200775D5E /* carpet.jpg */, 145 | 94A4854B18F1FAB200775D5E /* icon.png */, 146 | 94A4854C18F1FAB200775D5E /* krStar.png */, 147 | 94A4854D18F1FAB200775D5E /* launch.png */, 148 | 94A4854E18F1FAB200775D5E /* needle.png */, 149 | 94A4855218F1FAB200775D5E /* spark.png */, 150 | 94A4855318F1FAB200775D5E /* speedGauge.png */, 151 | 9655E4E719265697006C3A3B /* click.caf */, 152 | 94A4855418F1FAB200775D5E /* starBurst.skn */, 153 | 94A4855618F1FAB200775D5E /* tex_smoke.png */, 154 | 94A4855718F1FAB200775D5E /* tire.jpg */, 155 | 94A4855918F1FAB200775D5E /* train_wood.jpg */, 156 | 94A4855A18F1FAB200775D5E /* video_camera.png */, 157 | 94A4855B18F1FAB200775D5E /* video_camera@2x.png */, 158 | 94A4855C18F1FAB200775D5E /* wall.jpg */, 159 | 94A4855D18F1FAB200775D5E /* wheel.png */, 160 | 94A4855E18F1FAB200775D5E /* wood.png */, 161 | 94A4855F18F1FAB200775D5E /* WoodCubeA.jpg */, 162 | 94A4856018F1FAB200775D5E /* WoodCubeB.jpg */, 163 | 94A4856118F1FAB200775D5E /* WoodCubeC.jpg */, 164 | 94A4855818F1FAB200775D5E /* train_flat.dae */, 165 | 9CF4337A19354D75001A1D66 /* rc_car.dae */, 166 | 9C765F10193561FE00C1D23C /* rc_car_texture.png */, 167 | 945AD79D18F1FB0800351CB5 /* reactor.scnp */, 168 | 945AD79F18F1FB2500351CB5 /* smoke.scnp */, 169 | 945AD7A018F1FB2500351CB5 /* smoke.png */, 170 | ); 171 | name = Resources; 172 | path = SceneKitVehicle/resources; 173 | sourceTree = ""; 174 | }; 175 | 9461830918F08C1D00FDFE48 = { 176 | isa = PBXGroup; 177 | children = ( 178 | D75EB98E1A9075210039D093 /* LICENSE.txt */, 179 | D75EB98F1A9075210039D093 /* README.md */, 180 | D75EB9921A90756B0039D093 /* README2.md */, 181 | 9461831418F08C1D00FDFE48 /* SceneKitVehicle */, 182 | 944CD35318F1D91500F4DCDA /* Resources */, 183 | 116C81FB192EAD9E0001FC16 /* Frameworks */, 184 | 9461831318F08C1D00FDFE48 /* Products */, 185 | ); 186 | sourceTree = ""; 187 | }; 188 | 9461831318F08C1D00FDFE48 /* Products */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | 9461831218F08C1D00FDFE48 /* SceneKitVehicle.app */, 192 | ); 193 | name = Products; 194 | sourceTree = ""; 195 | }; 196 | 9461831418F08C1D00FDFE48 /* SceneKitVehicle */ = { 197 | isa = PBXGroup; 198 | children = ( 199 | D75314A919B795110021B0F8 /* AppDelegate.swift */, 200 | D7D7D2EC19A0CEE90065D098 /* GameViewController.swift */, 201 | D7D7D2EA19A0CA7D0065D098 /* GameView.swift */, 202 | D7D7D2BA19A034B20065D098 /* OverlayScene.swift */, 203 | 9461832918F08C1D00FDFE48 /* Images.xcassets */, 204 | 9461832018F08C1D00FDFE48 /* Main_iPhone.storyboard */, 205 | 9461832318F08C1D00FDFE48 /* Main_iPad.storyboard */, 206 | 9461831518F08C1D00FDFE48 /* Supporting Files */, 207 | ); 208 | path = SceneKitVehicle; 209 | sourceTree = ""; 210 | }; 211 | 9461831518F08C1D00FDFE48 /* Supporting Files */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | 9461831618F08C1D00FDFE48 /* SceneKitVehicle-Info.plist */, 215 | 9461831718F08C1D00FDFE48 /* InfoPlist.strings */, 216 | ); 217 | name = "Supporting Files"; 218 | sourceTree = ""; 219 | }; 220 | /* End PBXGroup section */ 221 | 222 | /* Begin PBXNativeTarget section */ 223 | 9461831118F08C1D00FDFE48 /* SceneKitVehicle */ = { 224 | isa = PBXNativeTarget; 225 | buildConfigurationList = 9461833C18F08C1D00FDFE48 /* Build configuration list for PBXNativeTarget "SceneKitVehicle" */; 226 | buildPhases = ( 227 | 9461830E18F08C1D00FDFE48 /* Sources */, 228 | 9461830F18F08C1D00FDFE48 /* Frameworks */, 229 | 9461831018F08C1D00FDFE48 /* Resources */, 230 | ); 231 | buildRules = ( 232 | ); 233 | dependencies = ( 234 | ); 235 | name = SceneKitVehicle; 236 | productName = SceneKitVehicle; 237 | productReference = 9461831218F08C1D00FDFE48 /* SceneKitVehicle.app */; 238 | productType = "com.apple.product-type.application"; 239 | }; 240 | /* End PBXNativeTarget section */ 241 | 242 | /* Begin PBXProject section */ 243 | 9461830A18F08C1D00FDFE48 /* Project object */ = { 244 | isa = PBXProject; 245 | attributes = { 246 | CLASSPREFIX = AAPL; 247 | LastSwiftUpdateCheck = 0700; 248 | LastUpgradeCheck = 1010; 249 | ORGANIZATIONNAME = "Apple Inc."; 250 | TargetAttributes = { 251 | 9461831118F08C1D00FDFE48 = { 252 | LastSwiftMigration = 0830; 253 | }; 254 | }; 255 | }; 256 | buildConfigurationList = 9461830D18F08C1D00FDFE48 /* Build configuration list for PBXProject "SceneKitVehicle" */; 257 | compatibilityVersion = "Xcode 3.2"; 258 | developmentRegion = en; 259 | hasScannedForEncodings = 0; 260 | knownRegions = ( 261 | en, 262 | Base, 263 | ); 264 | mainGroup = 9461830918F08C1D00FDFE48; 265 | productRefGroup = 9461831318F08C1D00FDFE48 /* Products */; 266 | projectDirPath = ""; 267 | projectRoot = ""; 268 | targets = ( 269 | 9461831118F08C1D00FDFE48 /* SceneKitVehicle */, 270 | ); 271 | }; 272 | /* End PBXProject section */ 273 | 274 | /* Begin PBXResourcesBuildPhase section */ 275 | 9461831018F08C1D00FDFE48 /* Resources */ = { 276 | isa = PBXResourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | 9461832518F08C1D00FDFE48 /* Main_iPad.storyboard in Resources */, 280 | 94A4857018F1FAB200775D5E /* spark.png in Resources */, 281 | 945AD7A218F1FB2500351CB5 /* smoke.png in Resources */, 282 | 94A4857B18F1FAB200775D5E /* wheel.png in Resources */, 283 | 9C765F11193561FE00C1D23C /* rc_car_texture.png in Resources */, 284 | 94A4857618F1FAB200775D5E /* train_flat.dae in Resources */, 285 | 94A4856318F1FAB200775D5E /* ball.jpg in Resources */, 286 | 945AD7A118F1FB2500351CB5 /* smoke.scnp in Resources */, 287 | 94A4856618F1FAB200775D5E /* book_side_title.jpg in Resources */, 288 | 9461832A18F08C1D00FDFE48 /* Images.xcassets in Resources */, 289 | 94A4857918F1FAB200775D5E /* video_camera@2x.png in Resources */, 290 | 9461832218F08C1D00FDFE48 /* Main_iPhone.storyboard in Resources */, 291 | 9655E4E819265809006C3A3B /* click.caf in Resources */, 292 | 94A4857D18F1FAB200775D5E /* WoodCubeA.jpg in Resources */, 293 | 94A4857F18F1FAB200775D5E /* WoodCubeC.jpg in Resources */, 294 | 9461831918F08C1D00FDFE48 /* InfoPlist.strings in Resources */, 295 | 94A4857818F1FAB200775D5E /* video_camera.png in Resources */, 296 | 94A4856918F1FAB200775D5E /* icon.png in Resources */, 297 | 94A4857118F1FAB200775D5E /* speedGauge.png in Resources */, 298 | 94A4857518F1FAB200775D5E /* tire.jpg in Resources */, 299 | 94A4856418F1FAB200775D5E /* book_back.jpg in Resources */, 300 | 94A4857418F1FAB200775D5E /* tex_smoke.png in Resources */, 301 | 94A4856C18F1FAB200775D5E /* needle.png in Resources */, 302 | 94A4857718F1FAB200775D5E /* train_wood.jpg in Resources */, 303 | 94A4856A18F1FAB200775D5E /* krStar.png in Resources */, 304 | 94A4856518F1FAB200775D5E /* book_front.jpg in Resources */, 305 | 94A4857E18F1FAB200775D5E /* WoodCubeB.jpg in Resources */, 306 | 94A4857218F1FAB200775D5E /* starBurst.skn in Resources */, 307 | 94A4856818F1FAB200775D5E /* carpet.jpg in Resources */, 308 | 945AD79E18F1FB0800351CB5 /* reactor.scnp in Resources */, 309 | 94A4856718F1FAB200775D5E /* book_side.jpg in Resources */, 310 | 94A4857C18F1FAB200775D5E /* wood.png in Resources */, 311 | 94A4856B18F1FAB200775D5E /* launch.png in Resources */, 312 | 9CF4337B19354D75001A1D66 /* rc_car.dae in Resources */, 313 | 94A4857A18F1FAB200775D5E /* wall.jpg in Resources */, 314 | ); 315 | runOnlyForDeploymentPostprocessing = 0; 316 | }; 317 | /* End PBXResourcesBuildPhase section */ 318 | 319 | /* Begin PBXSourcesBuildPhase section */ 320 | 9461830E18F08C1D00FDFE48 /* Sources */ = { 321 | isa = PBXSourcesBuildPhase; 322 | buildActionMask = 2147483647; 323 | files = ( 324 | D75314AA19B795110021B0F8 /* AppDelegate.swift in Sources */, 325 | D7D7D2EB19A0CA7D0065D098 /* GameView.swift in Sources */, 326 | D79862B419B358F200ADDB1D /* GameViewController.swift in Sources */, 327 | D7D7D2BB19A034B20065D098 /* OverlayScene.swift in Sources */, 328 | ); 329 | runOnlyForDeploymentPostprocessing = 0; 330 | }; 331 | /* End PBXSourcesBuildPhase section */ 332 | 333 | /* Begin PBXVariantGroup section */ 334 | 9461831718F08C1D00FDFE48 /* InfoPlist.strings */ = { 335 | isa = PBXVariantGroup; 336 | children = ( 337 | 9461831818F08C1D00FDFE48 /* en */, 338 | ); 339 | name = InfoPlist.strings; 340 | sourceTree = ""; 341 | }; 342 | 9461832018F08C1D00FDFE48 /* Main_iPhone.storyboard */ = { 343 | isa = PBXVariantGroup; 344 | children = ( 345 | 9461832118F08C1D00FDFE48 /* Base */, 346 | ); 347 | name = Main_iPhone.storyboard; 348 | sourceTree = ""; 349 | }; 350 | 9461832318F08C1D00FDFE48 /* Main_iPad.storyboard */ = { 351 | isa = PBXVariantGroup; 352 | children = ( 353 | 9461832418F08C1D00FDFE48 /* Base */, 354 | ); 355 | name = Main_iPad.storyboard; 356 | sourceTree = ""; 357 | }; 358 | /* End PBXVariantGroup section */ 359 | 360 | /* Begin XCBuildConfiguration section */ 361 | 9461833A18F08C1D00FDFE48 /* Debug */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | ALWAYS_SEARCH_USER_PATHS = NO; 365 | AXLE_ENABLE_DEBUG_INFO = YES; 366 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 367 | CLANG_CXX_LIBRARY = "libc++"; 368 | CLANG_ENABLE_MODULES = YES; 369 | CLANG_ENABLE_OBJC_ARC = YES; 370 | CLANG_WARN_ASSIGN_ENUM = YES; 371 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 372 | CLANG_WARN_BOOL_CONVERSION = YES; 373 | CLANG_WARN_COMMA = YES; 374 | CLANG_WARN_CONSTANT_CONVERSION = YES; 375 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 376 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 377 | CLANG_WARN_EMPTY_BODY = YES; 378 | CLANG_WARN_ENUM_CONVERSION = YES; 379 | CLANG_WARN_INFINITE_RECURSION = YES; 380 | CLANG_WARN_INT_CONVERSION = YES; 381 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 382 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 383 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 384 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 385 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 386 | CLANG_WARN_STRICT_PROTOTYPES = YES; 387 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 388 | CLANG_WARN_UNREACHABLE_CODE = YES; 389 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 390 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 391 | COPY_PHASE_STRIP = NO; 392 | ENABLE_STRICT_OBJC_MSGSEND = YES; 393 | ENABLE_TESTABILITY = YES; 394 | GCC_C_LANGUAGE_STANDARD = gnu99; 395 | GCC_DYNAMIC_NO_PIC = NO; 396 | GCC_NO_COMMON_BLOCKS = YES; 397 | GCC_OPTIMIZATION_LEVEL = 0; 398 | GCC_PREPROCESSOR_DEFINITIONS = ( 399 | "DEBUG=1", 400 | "$(inherited)", 401 | ); 402 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 403 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 404 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 405 | GCC_WARN_UNDECLARED_SELECTOR = YES; 406 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 407 | GCC_WARN_UNUSED_FUNCTION = YES; 408 | GCC_WARN_UNUSED_VARIABLE = YES; 409 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 410 | ONLY_ACTIVE_ARCH = YES; 411 | SDKROOT = iphoneos; 412 | TARGETED_DEVICE_FAMILY = "1,2"; 413 | }; 414 | name = Debug; 415 | }; 416 | 9461833B18F08C1D00FDFE48 /* Release */ = { 417 | isa = XCBuildConfiguration; 418 | buildSettings = { 419 | ALWAYS_SEARCH_USER_PATHS = NO; 420 | AXLE_ENABLE_DEBUG_INFO = NO; 421 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 422 | CLANG_CXX_LIBRARY = "libc++"; 423 | CLANG_ENABLE_MODULES = YES; 424 | CLANG_ENABLE_OBJC_ARC = YES; 425 | CLANG_WARN_ASSIGN_ENUM = YES; 426 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 427 | CLANG_WARN_BOOL_CONVERSION = YES; 428 | CLANG_WARN_COMMA = YES; 429 | CLANG_WARN_CONSTANT_CONVERSION = YES; 430 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 431 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 432 | CLANG_WARN_EMPTY_BODY = YES; 433 | CLANG_WARN_ENUM_CONVERSION = YES; 434 | CLANG_WARN_INFINITE_RECURSION = YES; 435 | CLANG_WARN_INT_CONVERSION = YES; 436 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 437 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 438 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 439 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 440 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 441 | CLANG_WARN_STRICT_PROTOTYPES = YES; 442 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 443 | CLANG_WARN_UNREACHABLE_CODE = YES; 444 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 445 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 446 | COPY_PHASE_STRIP = YES; 447 | ENABLE_NS_ASSERTIONS = NO; 448 | ENABLE_STRICT_OBJC_MSGSEND = YES; 449 | GCC_C_LANGUAGE_STANDARD = gnu99; 450 | GCC_NO_COMMON_BLOCKS = YES; 451 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 452 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 453 | GCC_WARN_UNDECLARED_SELECTOR = YES; 454 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 455 | GCC_WARN_UNUSED_FUNCTION = YES; 456 | GCC_WARN_UNUSED_VARIABLE = YES; 457 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 458 | SDKROOT = iphoneos; 459 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 460 | TARGETED_DEVICE_FAMILY = "1,2"; 461 | VALIDATE_PRODUCT = YES; 462 | }; 463 | name = Release; 464 | }; 465 | 9461833D18F08C1D00FDFE48 /* Debug */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 469 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 470 | CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; 471 | CLANG_ENABLE_MODULES = YES; 472 | CODE_SIGN_IDENTITY = "iPhone Developer"; 473 | DEVELOPMENT_TEAM = ""; 474 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 475 | GCC_PREFIX_HEADER = "SceneKitVehicle/SceneKitVehicle-Prefix.pch"; 476 | INFOPLIST_FILE = "SceneKitVehicle/SceneKitVehicle-Info.plist"; 477 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 478 | PRODUCT_BUNDLE_IDENTIFIER = "com.apple.scenekit.${PRODUCT_NAME:rfc1034identifier}"; 479 | PRODUCT_NAME = "$(TARGET_NAME)"; 480 | SDKROOT = iphoneos; 481 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 482 | SWIFT_VERSION = 5.0; 483 | }; 484 | name = Debug; 485 | }; 486 | 9461833E18F08C1D00FDFE48 /* Release */ = { 487 | isa = XCBuildConfiguration; 488 | buildSettings = { 489 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 490 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 491 | CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; 492 | CLANG_ENABLE_MODULES = YES; 493 | CODE_SIGN_IDENTITY = "iPhone Developer"; 494 | DEVELOPMENT_TEAM = ""; 495 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 496 | GCC_PREFIX_HEADER = "SceneKitVehicle/SceneKitVehicle-Prefix.pch"; 497 | INFOPLIST_FILE = "SceneKitVehicle/SceneKitVehicle-Info.plist"; 498 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 499 | PRODUCT_BUNDLE_IDENTIFIER = "com.apple.scenekit.${PRODUCT_NAME:rfc1034identifier}"; 500 | PRODUCT_NAME = "$(TARGET_NAME)"; 501 | SDKROOT = iphoneos; 502 | SWIFT_VERSION = 5.0; 503 | }; 504 | name = Release; 505 | }; 506 | /* End XCBuildConfiguration section */ 507 | 508 | /* Begin XCConfigurationList section */ 509 | 9461830D18F08C1D00FDFE48 /* Build configuration list for PBXProject "SceneKitVehicle" */ = { 510 | isa = XCConfigurationList; 511 | buildConfigurations = ( 512 | 9461833A18F08C1D00FDFE48 /* Debug */, 513 | 9461833B18F08C1D00FDFE48 /* Release */, 514 | ); 515 | defaultConfigurationIsVisible = 0; 516 | defaultConfigurationName = Release; 517 | }; 518 | 9461833C18F08C1D00FDFE48 /* Build configuration list for PBXNativeTarget "SceneKitVehicle" */ = { 519 | isa = XCConfigurationList; 520 | buildConfigurations = ( 521 | 9461833D18F08C1D00FDFE48 /* Debug */, 522 | 9461833E18F08C1D00FDFE48 /* Release */, 523 | ); 524 | defaultConfigurationIsVisible = 0; 525 | defaultConfigurationName = Release; 526 | }; 527 | /* End XCConfigurationList section */ 528 | }; 529 | rootObject = 9461830A18F08C1D00FDFE48 /* Project object */; 530 | } 531 | -------------------------------------------------------------------------------- /SceneKitVehicle.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SceneKitVehicle.xcodeproj/project.xcworkspace/xcuserdata/dev.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle.xcodeproj/project.xcworkspace/xcuserdata/dev.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SceneKitVehicle.xcodeproj/xcuserdata/dev.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /SceneKitVehicle.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/SceneKitVehicle.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /SceneKitVehicle.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SceneKitVehicle.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 9461831118F08C1D00FDFE48 16 | 17 | primary 18 | 19 | 20 | 9461832E18F08C1D00FDFE48 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SceneKitVehicle/AAPLAppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | 7 | The application delegate. 8 | 9 | */ 10 | 11 | #import 12 | 13 | @interface AAPLAppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /SceneKitVehicle/AAPLAppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | */ 6 | 7 | #import "AAPLAppDelegate.h" 8 | 9 | @implementation AAPLAppDelegate 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /SceneKitVehicle/AAPLGameView.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | 7 | A SceneKit view that handles touch events. 8 | 9 | */ 10 | 11 | #import 12 | #import 13 | 14 | @interface AAPLGameView : SCNView 15 | 16 | @property NSUInteger touchCount; 17 | @property BOOL inCarView; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /SceneKitVehicle/AAPLGameView.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | */ 6 | 7 | #import 8 | #import "AAPLGameView.h" 9 | 10 | @implementation AAPLGameView 11 | 12 | - (void)changePointOfView 13 | { 14 | // retrieve the list of point of views 15 | NSArray *pointOfViews = [self.scene.rootNode childNodesPassingTest:^BOOL(SCNNode *child, BOOL *stop) { 16 | return child.camera != nil; 17 | }]; 18 | 19 | SCNNode *currentPointOfView = self.pointOfView; 20 | 21 | // select the next one 22 | NSUInteger index = [pointOfViews indexOfObject:currentPointOfView]; 23 | index++; 24 | if (index >= [pointOfViews count]) index = 0; 25 | 26 | self.inCarView = (index==0); 27 | 28 | // set it with an implicit transaction 29 | [SCNTransaction begin]; 30 | [SCNTransaction setAnimationDuration:0.75]; 31 | self.pointOfView = [pointOfViews objectAtIndex:index]; 32 | [SCNTransaction commit]; 33 | } 34 | 35 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 36 | { 37 | UITouch *touch = [touches anyObject]; 38 | 39 | //test if we hit the camera button 40 | SKScene *scene = self.overlaySKScene; 41 | CGPoint p = [touch locationInView:self]; 42 | p = [scene convertPointFromView:p]; 43 | SKNode *node = [scene nodeAtPoint:p]; 44 | 45 | if ([node.name isEqualToString:@"camera"]) { 46 | //play a sound 47 | [node runAction:[SKAction playSoundFileNamed:@"click.caf" waitForCompletion:NO]]; 48 | 49 | //change the point of view 50 | [self changePointOfView]; 51 | return; 52 | } 53 | 54 | //update the total number of touches on screen 55 | NSSet *allTouches = [event allTouches]; 56 | _touchCount = [allTouches count]; 57 | } 58 | 59 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 60 | { 61 | _touchCount = 0; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /SceneKitVehicle/AAPLGameViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | 7 | A view controller that conforms to SCNSceneRendererDelegate and implements the game logic. 8 | 9 | */ 10 | 11 | #import 12 | #import 13 | #import 14 | #import 15 | 16 | @interface AAPLGameViewController : UIViewController 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /SceneKitVehicle/AAPLGameViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | */ 6 | 7 | #import 8 | #import 9 | #import 10 | 11 | #import "AAPLGameViewController.h" 12 | #import "AAPLGameView.h" 13 | #import "AAPLOverlayScene.h" 14 | 15 | #define MAX_SPEED 250 16 | 17 | @implementation AAPLGameViewController { 18 | //some node references for manipulation 19 | SCNNode *_spotLightNode; 20 | SCNNode *_cameraNode; //the node that owns the camera 21 | SCNNode *_vehicleNode; 22 | SCNPhysicsVehicle *_vehicle; 23 | SCNParticleSystem *_reactor; 24 | 25 | //accelerometer 26 | CMMotionManager *_motionManager; 27 | UIAccelerationValue _accelerometer[3]; 28 | CGFloat _orientation; 29 | 30 | //reactor's particle birth rate 31 | CGFloat _reactorDefaultBirthRate; 32 | 33 | // steering factor 34 | CGFloat _vehicleSteering; 35 | } 36 | 37 | - (NSString *)deviceName 38 | { 39 | static NSString *deviceName = nil; 40 | 41 | if (deviceName == nil) { 42 | struct utsname systemInfo; 43 | uname(&systemInfo); 44 | 45 | deviceName = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; 46 | } 47 | return deviceName; 48 | } 49 | 50 | - (BOOL)isHighEndDevice 51 | { 52 | //return YES for iPhone 5s and iPad air, NO otherwise 53 | if ([[self deviceName] hasPrefix:@"iPad4"] 54 | || [[self deviceName] hasPrefix:@"iPhone6"]) { 55 | return YES; 56 | } 57 | 58 | return NO; 59 | } 60 | 61 | - (void)setupEnvironment:(SCNScene *)scene 62 | { 63 | // add an ambient light 64 | SCNNode *ambientLight = [SCNNode node]; 65 | ambientLight.light = [SCNLight light]; 66 | ambientLight.light.type = SCNLightTypeAmbient; 67 | ambientLight.light.color = [UIColor colorWithWhite:0.3 alpha:1.0]; 68 | [[scene rootNode] addChildNode:ambientLight]; 69 | 70 | //add a key light to the scene 71 | SCNNode *lightNode = [SCNNode node]; 72 | lightNode.light = [SCNLight light]; 73 | lightNode.light.type = SCNLightTypeSpot; 74 | if ([self isHighEndDevice]) 75 | lightNode.light.castsShadow = YES; 76 | lightNode.light.color = [UIColor colorWithWhite:0.8 alpha:1.0]; 77 | lightNode.position = SCNVector3Make(0, 80, 30); 78 | lightNode.rotation = SCNVector4Make(1,0,0,-M_PI/2.8); 79 | lightNode.light.spotInnerAngle = 0; 80 | lightNode.light.spotOuterAngle = 50; 81 | lightNode.light.shadowColor = [SKColor blackColor]; 82 | lightNode.light.zFar = 500; 83 | lightNode.light.zNear = 50; 84 | [[scene rootNode] addChildNode:lightNode]; 85 | 86 | //keep an ivar for later manipulation 87 | _spotLightNode = lightNode; 88 | 89 | //floor 90 | SCNNode*floor = [SCNNode node]; 91 | floor.geometry = [SCNFloor floor]; 92 | floor.geometry.firstMaterial.diffuse.contents = @"wood.png"; 93 | floor.geometry.firstMaterial.diffuse.contentsTransform = SCNMatrix4MakeScale(2, 2, 1); //scale the wood texture 94 | floor.geometry.firstMaterial.locksAmbientWithDiffuse = YES; 95 | if ([self isHighEndDevice]) 96 | ((SCNFloor*)floor.geometry).reflectionFalloffEnd = 10; 97 | 98 | SCNPhysicsBody *staticBody = [SCNPhysicsBody staticBody]; 99 | floor.physicsBody = staticBody; 100 | [[scene rootNode] addChildNode:floor]; 101 | } 102 | 103 | - (void)addTrainToScene:(SCNScene *)scene atPosition:(SCNVector3)pos 104 | { 105 | SCNScene *trainScene = [SCNScene sceneNamed:@"train_flat"]; 106 | 107 | //physicalize the train with simple boxes 108 | [trainScene.rootNode.childNodes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 109 | SCNNode *node = (SCNNode *)obj; 110 | if (node.geometry != nil) { 111 | node.position = SCNVector3Make(node.position.x + pos.x, node.position.y + pos.y, node.position.z + pos.z); 112 | 113 | SCNVector3 min, max; 114 | [node getBoundingBoxMin:&min max:&max]; 115 | 116 | SCNPhysicsBody *body = [SCNPhysicsBody dynamicBody]; 117 | SCNBox *boxShape = [SCNBox boxWithWidth:max.x - min.x height:max.y - min.y length:max.z - min.z chamferRadius:0.0]; 118 | body.physicsShape = [SCNPhysicsShape shapeWithGeometry:boxShape options:nil]; 119 | 120 | node.pivot = SCNMatrix4MakeTranslation(0, -min.y, 0); 121 | node.physicsBody = body; 122 | [[scene rootNode] addChildNode:node]; 123 | } 124 | }]; 125 | 126 | //add smoke 127 | SCNNode *smokeHandle = [scene.rootNode childNodeWithName:@"Smoke" recursively:YES]; 128 | [smokeHandle addParticleSystem:[SCNParticleSystem particleSystemNamed:@"smoke" inDirectory:nil]]; 129 | 130 | //add physics constraints between engine and wagons 131 | SCNNode *engineCar = [scene.rootNode childNodeWithName:@"EngineCar" recursively:NO]; 132 | SCNNode *wagon1 = [scene.rootNode childNodeWithName:@"Wagon1" recursively:NO]; 133 | SCNNode *wagon2 = [scene.rootNode childNodeWithName:@"Wagon2" recursively:NO]; 134 | 135 | SCNVector3 min, max; 136 | [engineCar getBoundingBoxMin:&min max:&max]; 137 | 138 | SCNVector3 wmin, wmax; 139 | [wagon1 getBoundingBoxMin:&wmin max:&wmax]; 140 | 141 | // Tie EngineCar & Wagon1 142 | SCNPhysicsBallSocketJoint *joint = [SCNPhysicsBallSocketJoint jointWithBodyA:engineCar.physicsBody anchorA:SCNVector3Make(max.x, min.y, 0) 143 | bodyB:wagon1.physicsBody anchorB:SCNVector3Make(wmin.x, wmin.y, 0)]; 144 | [scene.physicsWorld addBehavior:joint]; 145 | 146 | // Wagon1 & Wagon2 147 | joint = [SCNPhysicsBallSocketJoint jointWithBodyA:wagon1.physicsBody anchorA:SCNVector3Make(wmax.x + 0.1, wmin.y, 0) 148 | bodyB:wagon2.physicsBody anchorB:SCNVector3Make(wmin.x - 0.1, wmin.y, 0)]; 149 | [scene.physicsWorld addBehavior:joint]; 150 | } 151 | 152 | 153 | - (void)addWoodenBlockToScene:(SCNScene *)scene withImageNamed:(NSString *)imageName atPosition:(SCNVector3)position 154 | { 155 | //create a new node 156 | SCNNode *block = [SCNNode node]; 157 | 158 | //place it 159 | block.position = position; 160 | 161 | //attach a box of 5x5x5 162 | block.geometry = [SCNBox boxWithWidth:5 height:5 length:5 chamferRadius:0]; 163 | 164 | //use the specified images named as the texture 165 | block.geometry.firstMaterial.diffuse.contents = imageName; 166 | 167 | //turn on mipmapping 168 | block.geometry.firstMaterial.diffuse.mipFilter = SCNFilterModeLinear; 169 | 170 | //make it physically based 171 | block.physicsBody = [SCNPhysicsBody dynamicBody]; 172 | 173 | //add to the scene 174 | [[scene rootNode] addChildNode:block]; 175 | } 176 | 177 | - (void)setupSceneElements:(SCNScene *)scene 178 | { 179 | // add a train 180 | [self addTrainToScene:scene atPosition:SCNVector3Make(-5, 20, -40)]; 181 | 182 | // add wooden blocks 183 | [self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeA.jpg" atPosition:SCNVector3Make(-10, 15, 10)]; 184 | [self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeB.jpg" atPosition:SCNVector3Make( -9, 10, 10)]; 185 | [self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeC.jpg" atPosition:SCNVector3Make(20, 15, -11)]; 186 | [self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeA.jpg" atPosition:SCNVector3Make(25, 5, -20)]; 187 | 188 | // add walls 189 | SCNNode *wall = [SCNNode nodeWithGeometry:[SCNBox boxWithWidth:400 height:100 length:4 chamferRadius:0]]; 190 | wall.geometry.firstMaterial.diffuse.contents = @"wall.jpg"; 191 | wall.geometry.firstMaterial.diffuse.contentsTransform = SCNMatrix4Mult(SCNMatrix4MakeScale(24, 2, 1), SCNMatrix4MakeTranslation(0, 1, 0)); 192 | wall.geometry.firstMaterial.diffuse.wrapS = SCNWrapModeRepeat; 193 | wall.geometry.firstMaterial.diffuse.wrapT = SCNWrapModeMirror; 194 | wall.geometry.firstMaterial.doubleSided = NO; 195 | wall.castsShadow = NO; 196 | wall.geometry.firstMaterial.locksAmbientWithDiffuse = YES; 197 | 198 | wall.position = SCNVector3Make(0, 50, -92); 199 | wall.physicsBody = [SCNPhysicsBody staticBody]; 200 | [scene.rootNode addChildNode:wall]; 201 | 202 | wall = [wall clone]; 203 | wall.position = SCNVector3Make(-202, 50, 0); 204 | wall.rotation = SCNVector4Make(0, 1, 0, M_PI_2); 205 | [scene.rootNode addChildNode:wall]; 206 | 207 | wall = [wall clone]; 208 | wall.position = SCNVector3Make(202, 50, 0); 209 | wall.rotation = SCNVector4Make(0, 1, 0, -M_PI_2); 210 | [scene.rootNode addChildNode:wall]; 211 | 212 | SCNNode *backWall = [SCNNode nodeWithGeometry:[SCNPlane planeWithWidth:400 height:100]]; 213 | backWall.geometry.firstMaterial = wall.geometry.firstMaterial; 214 | backWall.position = SCNVector3Make(0, 50, 200); 215 | backWall.rotation = SCNVector4Make(0, 1, 0, M_PI); 216 | backWall.castsShadow = NO; 217 | backWall.physicsBody = [SCNPhysicsBody staticBody]; 218 | [scene.rootNode addChildNode:backWall]; 219 | 220 | // add ceil 221 | SCNNode *ceilNode = [SCNNode nodeWithGeometry:[SCNPlane planeWithWidth:400 height:400]]; 222 | ceilNode.position = SCNVector3Make(0, 100, 0); 223 | ceilNode.rotation = SCNVector4Make(1, 0, 0, M_PI_2); 224 | ceilNode.geometry.firstMaterial.doubleSided = NO; 225 | ceilNode.castsShadow = NO; 226 | ceilNode.geometry.firstMaterial.locksAmbientWithDiffuse = YES; 227 | [scene.rootNode addChildNode:ceilNode]; 228 | 229 | //add more block 230 | for(int i=0;i<4; i++) { 231 | [self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeA.jpg" atPosition:SCNVector3Make(rand()%60 - 30, 20, rand()%40 - 20)]; 232 | [self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeB.jpg" atPosition:SCNVector3Make(rand()%60 - 30, 20, rand()%40 - 20)]; 233 | [self addWoodenBlockToScene:scene withImageNamed:@"WoodCubeC.jpg" atPosition:SCNVector3Make(rand()%60 - 30, 20, rand()%40 - 20)]; 234 | } 235 | 236 | // add cartoon book 237 | SCNNode *block = [SCNNode node]; 238 | block.position = SCNVector3Make(20, 10, -16); 239 | block.rotation = SCNVector4Make(0, 1, 0, -M_PI_4); 240 | block.geometry = [SCNBox boxWithWidth:22 height:0.2 length:34 chamferRadius:0]; 241 | SCNMaterial *frontMat = [SCNMaterial material]; 242 | frontMat.locksAmbientWithDiffuse = YES; 243 | frontMat.diffuse.contents = @"book_front.jpg"; 244 | frontMat.diffuse.mipFilter = SCNFilterModeLinear; 245 | SCNMaterial *backMat = [SCNMaterial material]; 246 | backMat.locksAmbientWithDiffuse = YES; 247 | backMat.diffuse.contents = @"book_back.jpg"; 248 | backMat.diffuse.mipFilter = SCNFilterModeLinear; 249 | block.geometry.materials = @[frontMat, backMat]; 250 | block.physicsBody = [SCNPhysicsBody dynamicBody]; 251 | [[scene rootNode] addChildNode:block]; 252 | 253 | // add carpet 254 | SCNNode *rug = [SCNNode node]; 255 | rug.position = SCNVector3Make(0, 0.01, 0); 256 | rug.rotation = SCNVector4Make(1, 0, 0, M_PI_2); 257 | UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(-50, -30, 100, 50) cornerRadius:2.5]; 258 | path.flatness = 0.1; 259 | rug.geometry = [SCNShape shapeWithPath:path extrusionDepth:0.05]; 260 | rug.geometry.firstMaterial.locksAmbientWithDiffuse = YES; 261 | rug.geometry.firstMaterial.diffuse.contents = @"carpet.jpg"; 262 | [[scene rootNode] addChildNode:rug]; 263 | 264 | // add ball 265 | SCNNode *ball = [SCNNode node]; 266 | ball.position = SCNVector3Make(-5, 5, -18); 267 | ball.geometry = [SCNSphere sphereWithRadius:5]; 268 | ball.geometry.firstMaterial.locksAmbientWithDiffuse = YES; 269 | ball.geometry.firstMaterial.diffuse.contents = @"ball.jpg"; 270 | ball.geometry.firstMaterial.diffuse.contentsTransform = SCNMatrix4MakeScale(2, 1, 1); 271 | ball.geometry.firstMaterial.diffuse.wrapS = SCNWrapModeMirror; 272 | ball.physicsBody = [SCNPhysicsBody dynamicBody]; 273 | ball.physicsBody.restitution = 0.9; 274 | [[scene rootNode] addChildNode:ball]; 275 | } 276 | 277 | 278 | - (SCNNode *)setupVehicle:(SCNScene *)scene 279 | { 280 | SCNScene *carScene = [SCNScene sceneNamed:@"rc_car"]; 281 | SCNNode *chassisNode = [carScene.rootNode childNodeWithName:@"rccarBody" recursively:NO]; 282 | 283 | // setup the chassis 284 | chassisNode.position = SCNVector3Make(0, 10, 30); 285 | chassisNode.rotation = SCNVector4Make(0, 1, 0, M_PI); 286 | 287 | SCNPhysicsBody *body = [SCNPhysicsBody dynamicBody]; 288 | body.allowsResting = NO; 289 | body.mass = 80; 290 | body.restitution = 0.1; 291 | body.friction = 0.5; 292 | body.rollingFriction = 0; 293 | 294 | chassisNode.physicsBody = body; 295 | [scene.rootNode addChildNode:chassisNode]; 296 | 297 | SCNNode *pipeNode = [chassisNode childNodeWithName:@"pipe" recursively:YES]; 298 | _reactor = [SCNParticleSystem particleSystemNamed:@"reactor" inDirectory:nil]; 299 | _reactorDefaultBirthRate = _reactor.birthRate; 300 | _reactor.birthRate = 0; 301 | [pipeNode addParticleSystem:_reactor]; 302 | 303 | //add wheels 304 | SCNNode *wheel0Node = [chassisNode childNodeWithName:@"wheelLocator_FL" recursively:YES]; 305 | SCNNode *wheel1Node = [chassisNode childNodeWithName:@"wheelLocator_FR" recursively:YES]; 306 | SCNNode *wheel2Node = [chassisNode childNodeWithName:@"wheelLocator_RL" recursively:YES]; 307 | SCNNode *wheel3Node = [chassisNode childNodeWithName:@"wheelLocator_RR" recursively:YES]; 308 | 309 | SCNPhysicsVehicleWheel *wheel0 = [SCNPhysicsVehicleWheel wheelWithNode:wheel0Node]; 310 | SCNPhysicsVehicleWheel *wheel1 = [SCNPhysicsVehicleWheel wheelWithNode:wheel1Node]; 311 | SCNPhysicsVehicleWheel *wheel2 = [SCNPhysicsVehicleWheel wheelWithNode:wheel2Node]; 312 | SCNPhysicsVehicleWheel *wheel3 = [SCNPhysicsVehicleWheel wheelWithNode:wheel3Node]; 313 | 314 | SCNVector3 min, max; 315 | [wheel0Node getBoundingBoxMin:&min max:&max]; 316 | CGFloat wheelHalfWidth = 0.5 * (max.x - min.x); 317 | 318 | wheel0.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel0Node convertPosition:SCNVector3Zero toNode:chassisNode]) + (vector_float3){wheelHalfWidth, 0.0, 0.0}); 319 | wheel1.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel1Node convertPosition:SCNVector3Zero toNode:chassisNode]) - (vector_float3){wheelHalfWidth, 0.0, 0.0}); 320 | wheel2.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel2Node convertPosition:SCNVector3Zero toNode:chassisNode]) + (vector_float3){wheelHalfWidth, 0.0, 0.0}); 321 | wheel3.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel3Node convertPosition:SCNVector3Zero toNode:chassisNode]) - (vector_float3){wheelHalfWidth, 0.0, 0.0}); 322 | 323 | // create the physics vehicle 324 | SCNPhysicsVehicle *vehicle = [SCNPhysicsVehicle vehicleWithChassisBody:chassisNode.physicsBody wheels:@[wheel0, wheel1, wheel2, wheel3]]; 325 | [scene.physicsWorld addBehavior:vehicle]; 326 | 327 | _vehicle = vehicle; 328 | 329 | return chassisNode; 330 | } 331 | 332 | - (SCNScene *)setupScene 333 | { 334 | // create a new scene 335 | SCNScene *scene = [SCNScene scene]; 336 | 337 | //global environment 338 | [self setupEnvironment:scene]; 339 | 340 | //add elements 341 | [self setupSceneElements:scene]; 342 | 343 | //setup vehicle 344 | _vehicleNode = [self setupVehicle:scene]; 345 | 346 | //create a main camera 347 | _cameraNode = [[SCNNode alloc] init]; 348 | _cameraNode.camera = [SCNCamera camera]; 349 | _cameraNode.camera.zFar = 500; 350 | _cameraNode.position = SCNVector3Make(0, 60, 50); 351 | _cameraNode.rotation = SCNVector4Make(1, 0, 0, -M_PI_4*0.75); 352 | [scene.rootNode addChildNode:_cameraNode]; 353 | 354 | //add a secondary camera to the car 355 | SCNNode *frontCameraNode = [SCNNode node]; 356 | frontCameraNode.position = SCNVector3Make(0, 3.5, 2.5); 357 | frontCameraNode.rotation = SCNVector4Make(0, 1, 0, M_PI); 358 | frontCameraNode.camera = [SCNCamera camera]; 359 | frontCameraNode.camera.xFov = 75; 360 | frontCameraNode.camera.zFar = 500; 361 | 362 | [_vehicleNode addChildNode:frontCameraNode]; 363 | 364 | return scene; 365 | } 366 | 367 | - (void)setupAccelerometer 368 | { 369 | //event 370 | _motionManager = [[CMMotionManager alloc] init]; 371 | AAPLGameViewController * __weak weakSelf = self; 372 | 373 | if ([[GCController controllers] count] == 0 && [_motionManager isAccelerometerAvailable] == YES) { 374 | [_motionManager setAccelerometerUpdateInterval:1/60.0]; 375 | [_motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) { 376 | [weakSelf accelerometerDidChange:accelerometerData.acceleration]; 377 | }]; 378 | } 379 | } 380 | 381 | - (BOOL)prefersStatusBarHidden { 382 | return YES; 383 | } 384 | 385 | - (void)viewDidLoad 386 | { 387 | [super viewDidLoad]; 388 | 389 | [[UIApplication sharedApplication] setStatusBarHidden:YES]; 390 | 391 | SCNView *scnView = (SCNView *) self.view; 392 | 393 | //set the background to back 394 | scnView.backgroundColor = [SKColor blackColor]; 395 | 396 | //setup the scene 397 | SCNScene *scene = [self setupScene]; 398 | 399 | //present it 400 | scnView.scene = scene; 401 | 402 | //tweak physics 403 | scnView.scene.physicsWorld.speed = 4.0; 404 | 405 | //setup overlays 406 | scnView.overlaySKScene = [[AAPLOverlayScene alloc] initWithSize:scnView.bounds.size]; 407 | 408 | //setup accelerometer 409 | [self setupAccelerometer]; 410 | 411 | //initial point of view 412 | scnView.pointOfView = _cameraNode; 413 | 414 | //plug game logic 415 | scnView.delegate = self; 416 | 417 | 418 | UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)]; 419 | doubleTap.numberOfTapsRequired = 2; 420 | doubleTap.numberOfTouchesRequired = 2; 421 | scnView.gestureRecognizers = @[doubleTap]; 422 | 423 | [super viewDidLoad]; 424 | } 425 | 426 | - (void) handleDoubleTap:(UITapGestureRecognizer *) gesture 427 | { 428 | SCNScene *scene = [self setupScene]; 429 | 430 | SCNView *scnView = (SCNView *) self.view; 431 | //present it 432 | scnView.scene = scene; 433 | 434 | //tweak physics 435 | scnView.scene.physicsWorld.speed = 4.0; 436 | 437 | //initial point of view 438 | scnView.pointOfView = _cameraNode; 439 | 440 | ((AAPLGameView*)scnView).touchCount = 0; 441 | } 442 | 443 | // game logic 444 | - (void)renderer:(id)aRenderer didSimulatePhysicsAtTime:(NSTimeInterval)time 445 | { 446 | const float defaultEngineForce = 300.0; 447 | const float defaultBrakingForce = 3.0; 448 | const float steeringClamp = 0.6; 449 | const float cameraDamping = 0.3; 450 | 451 | AAPLGameView *scnView = (AAPLGameView*)self.view; 452 | 453 | CGFloat engineForce = 0; 454 | CGFloat brakingForce = 0; 455 | 456 | NSArray* controllers = [GCController controllers]; 457 | 458 | float orientation = _orientation; 459 | 460 | //drive: 1 touch = accelerate, 2 touches = backward, 3 touches = brake 461 | if (scnView.touchCount == 1) { 462 | engineForce = defaultEngineForce; 463 | _reactor.birthRate = _reactorDefaultBirthRate; 464 | } 465 | else if (scnView.touchCount == 2) { 466 | engineForce = -defaultEngineForce; 467 | _reactor.birthRate = 0; 468 | } 469 | else if (scnView.touchCount == 3) { 470 | brakingForce = 100; 471 | _reactor.birthRate = 0; 472 | } 473 | else { 474 | brakingForce = defaultBrakingForce; 475 | _reactor.birthRate = 0; 476 | } 477 | 478 | //controller support 479 | if (controllers && [controllers count] > 0) { 480 | GCController *controller = controllers[0]; 481 | GCGamepad *pad = [controller gamepad]; 482 | GCControllerDirectionPad *dpad = [pad dpad]; 483 | 484 | static float orientationCum = 0; 485 | 486 | #define INCR_ORIENTATION 0.03 487 | #define DECR_ORIENTATION 0.8 488 | 489 | if (dpad.right.pressed) { 490 | if (orientationCum < 0) orientationCum *= DECR_ORIENTATION; 491 | orientationCum += INCR_ORIENTATION; 492 | if (orientationCum > 1) orientationCum = 1; 493 | } 494 | else if (dpad.left.pressed) { 495 | if (orientationCum > 0) orientationCum *= DECR_ORIENTATION; 496 | orientationCum -= INCR_ORIENTATION; 497 | if (orientationCum < -1) orientationCum = -1; 498 | } 499 | else { 500 | orientationCum *= DECR_ORIENTATION; 501 | } 502 | 503 | orientation = orientationCum; 504 | 505 | if (pad.buttonX.pressed) { 506 | engineForce = defaultEngineForce; 507 | _reactor.birthRate = _reactorDefaultBirthRate; 508 | } 509 | else if (pad.buttonA.pressed) { 510 | engineForce = -defaultEngineForce; 511 | _reactor.birthRate = 0; 512 | } 513 | else if (pad.buttonB.pressed) { 514 | brakingForce = 100; 515 | _reactor.birthRate = 0; 516 | } 517 | else { 518 | brakingForce = defaultBrakingForce; 519 | _reactor.birthRate = 0; 520 | } 521 | } 522 | 523 | _vehicleSteering = -orientation; 524 | if (orientation==0) 525 | _vehicleSteering *= 0.9; 526 | if (_vehicleSteering < -steeringClamp) 527 | _vehicleSteering = -steeringClamp; 528 | if (_vehicleSteering > steeringClamp) 529 | _vehicleSteering = steeringClamp; 530 | 531 | //update the vehicle steering and acceleration 532 | [_vehicle setSteeringAngle:_vehicleSteering forWheelAtIndex:0]; 533 | [_vehicle setSteeringAngle:_vehicleSteering forWheelAtIndex:1]; 534 | 535 | [_vehicle applyEngineForce:engineForce forWheelAtIndex:2]; 536 | [_vehicle applyEngineForce:engineForce forWheelAtIndex:3]; 537 | 538 | [_vehicle applyBrakingForce:brakingForce forWheelAtIndex:2]; 539 | [_vehicle applyBrakingForce:brakingForce forWheelAtIndex:3]; 540 | 541 | //check if the car is upside down 542 | [self reorientCarIfNeeded]; 543 | 544 | // make camera follow the car node 545 | SCNNode *car = [_vehicleNode presentationNode]; 546 | SCNVector3 carPos = car.position; 547 | vector_float3 targetPos = {carPos.x, 30., carPos.z + 25.}; 548 | vector_float3 cameraPos = SCNVector3ToFloat3(_cameraNode.position); 549 | cameraPos = vector_mix(cameraPos, targetPos, (vector_float3)(cameraDamping)); 550 | _cameraNode.position = SCNVector3FromFloat3(cameraPos); 551 | 552 | if (scnView.inCarView) { 553 | //move spot light in front of the camera 554 | SCNVector3 frontPosition = [scnView.pointOfView.presentationNode convertPosition:SCNVector3Make(0, 0, -30) toNode:nil]; 555 | _spotLightNode.position = SCNVector3Make(frontPosition.x, 80., frontPosition.z); 556 | _spotLightNode.rotation = SCNVector4Make(1,0,0,-M_PI/2); 557 | } 558 | else { 559 | //move spot light on top of the car 560 | _spotLightNode.position = SCNVector3Make(carPos.x, 80., carPos.z + 30.); 561 | _spotLightNode.rotation = SCNVector4Make(1,0,0,-M_PI/2.8); 562 | } 563 | 564 | //speed gauge 565 | AAPLOverlayScene *overlayScene = (AAPLOverlayScene*)scnView.overlaySKScene; 566 | overlayScene.speedNeedle.zRotation = -(_vehicle.speedInKilometersPerHour * M_PI / MAX_SPEED); 567 | } 568 | 569 | - (void)reorientCarIfNeeded 570 | { 571 | SCNNode *car = [_vehicleNode presentationNode]; 572 | SCNVector3 carPos = car.position; 573 | 574 | // make sure the car isn't upside down, and fix it if it is 575 | static int ticks = 0; 576 | static int check = 0; 577 | ticks++; 578 | if (ticks == 30) { 579 | SCNMatrix4 t = car.worldTransform; 580 | if (t.m22 <= 0.1) { 581 | check++; 582 | if (check == 3) { 583 | static int try = 0; 584 | try++; 585 | if (try == 3) { 586 | try = 0; 587 | 588 | //hard reset 589 | _vehicleNode.rotation = SCNVector4Make(0, 0, 0, 0); 590 | _vehicleNode.position = SCNVector3Make(carPos.x, carPos.y + 10, carPos.z); 591 | [_vehicleNode.physicsBody resetTransform]; 592 | } 593 | else { 594 | //try to upturn with an random impulse 595 | SCNVector3 pos = SCNVector3Make(-10*((rand()/(float)RAND_MAX)-0.5),0,-10*((rand()/(float)RAND_MAX)-0.5)); 596 | [_vehicleNode.physicsBody applyForce:SCNVector3Make(0, 300, 0) atPosition:pos impulse:YES]; 597 | } 598 | 599 | check = 0; 600 | } 601 | } 602 | else { 603 | check = 0; 604 | } 605 | 606 | ticks=0; 607 | } 608 | } 609 | 610 | - (void)accelerometerDidChange:(CMAcceleration)acceleration 611 | { 612 | #define kFilteringFactor 0.5 613 | 614 | //Use a basic low-pass filter to only keep the gravity in the accelerometer values 615 | _accelerometer[0] = acceleration.x * kFilteringFactor + _accelerometer[0] * (1.0 - kFilteringFactor); 616 | _accelerometer[1] = acceleration.y * kFilteringFactor + _accelerometer[1] * (1.0 - kFilteringFactor); 617 | _accelerometer[2] = acceleration.z * kFilteringFactor + _accelerometer[2] * (1.0 - kFilteringFactor); 618 | 619 | if (_accelerometer[0] > 0) { 620 | _orientation = _accelerometer[1]*1.3; 621 | } 622 | else { 623 | _orientation = -_accelerometer[1]*1.3; 624 | } 625 | } 626 | 627 | - (void)viewWillDisappear:(BOOL)animated 628 | { 629 | [_motionManager stopAccelerometerUpdates]; 630 | _motionManager = nil; 631 | } 632 | 633 | - (BOOL)shouldAutorotate 634 | { 635 | return YES; 636 | } 637 | 638 | - (NSUInteger)supportedInterfaceOrientations 639 | { 640 | return UIInterfaceOrientationMaskLandscape; 641 | } 642 | 643 | - (void)didReceiveMemoryWarning 644 | { 645 | [super didReceiveMemoryWarning]; 646 | // Release any cached data, images, etc that aren't in use. 647 | } 648 | 649 | @end 650 | -------------------------------------------------------------------------------- /SceneKitVehicle/AAPLOverlayScene.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | Abstract: 6 | 7 | A SpriteKit scene used as an overlay. 8 | 9 | */ 10 | 11 | #import 12 | 13 | @interface AAPLOverlayScene : SKScene 14 | 15 | @property (readonly) SKNode *speedNeedle; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /SceneKitVehicle/AAPLOverlayScene.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | */ 6 | 7 | #import "AAPLOverlayScene.h" 8 | 9 | @implementation AAPLOverlayScene 10 | 11 | -(id)initWithSize:(CGSize)size { 12 | if (self = [super initWithSize:size]) { 13 | //setup the overlay scene 14 | self.anchorPoint = CGPointMake(0.5, 0.5); 15 | 16 | //automatically resize to fill the viewport 17 | self.scaleMode = SKSceneScaleModeResizeFill; 18 | 19 | //make UI larger on iPads 20 | BOOL iPad = ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad); 21 | float scale = iPad ? 1.5 : 1; 22 | 23 | //add the speed gauge 24 | SKSpriteNode *myImage = [SKSpriteNode spriteNodeWithImageNamed:@"speedGauge.png"]; 25 | myImage.anchorPoint = CGPointMake(0.5, 0); 26 | myImage.position = CGPointMake(size.width*0.33, -size.height*0.5); 27 | myImage.xScale = 0.8 * scale; 28 | myImage.yScale = 0.8 * scale; 29 | [self addChild:myImage]; 30 | 31 | //add the needed 32 | SKNode *needleHandle = [SKNode node]; 33 | SKSpriteNode *needle = [SKSpriteNode spriteNodeWithImageNamed:@"needle.png"]; 34 | needleHandle.position = CGPointMake(0, 16); 35 | needle.anchorPoint = CGPointMake(0.5, 0); 36 | needle.xScale = 0.7; 37 | needle.yScale = 0.7; 38 | needle.zRotation = M_PI_2; 39 | [needleHandle addChild:needle]; 40 | [myImage addChild:needleHandle]; 41 | 42 | _speedNeedle = needleHandle; 43 | 44 | //add the camera button 45 | SKSpriteNode *cameraImage = [SKSpriteNode spriteNodeWithImageNamed:@"video_camera.png"]; 46 | cameraImage.position = CGPointMake(-size.width * 0.4, -size.height*0.4); 47 | cameraImage.name = @"camera"; 48 | cameraImage.xScale = 0.6 * scale; 49 | cameraImage.yScale = 0.6 * scale; 50 | [self addChild:cameraImage]; 51 | } 52 | return self; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /SceneKitVehicle/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SceneKitVehicle 4 | // 5 | // Translated by OOPer in cooperation with shlab.jp, on 2014/09/04. 6 | // Copyright (c) 2014年 Apple Inc. All rights reserved. 7 | // 8 | /* 9 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 10 | See LICENSE.txt for this sample’s licensing information 11 | 12 | Abstract: 13 | 14 | The application delegate. 15 | 16 | */ 17 | 18 | import UIKit 19 | 20 | @UIApplicationMain 21 | @objc(AAPLAppDelegate) 22 | class AppDelegate: UIResponder, UIApplicationDelegate { 23 | 24 | var window: UIWindow? 25 | 26 | } -------------------------------------------------------------------------------- /SceneKitVehicle/Base.lproj/Main_iPad.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /SceneKitVehicle/Base.lproj/Main_iPhone.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /SceneKitVehicle/GameView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameView.swift 3 | // SceneKitVehicle 4 | // 5 | // Translated by OOPer in cooperation with shlab.jp, on 2014/08/17. 6 | // 7 | // 8 | /* 9 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 10 | See LICENSE.txt for this sample’s licensing information 11 | 12 | Abstract: 13 | 14 | A SceneKit view that handles touch events. 15 | 16 | */ 17 | 18 | import UIKit 19 | import SceneKit 20 | import SpriteKit 21 | 22 | @objc(AAPLGameView) 23 | class GameView: SCNView { 24 | 25 | var touchCount: Int = 0 26 | var inCarView: Bool = false 27 | 28 | private func changePointOfView() { 29 | // retrieve the list of point of views 30 | let pointOfViews = scene!.rootNode.childNodes {child, stop in 31 | return child.camera != nil 32 | } 33 | 34 | let currentPointOfView = self.pointOfView 35 | 36 | // select the next one 37 | var index = pointOfViews.firstIndex(of: currentPointOfView!) ?? 0 38 | index += 1 39 | if index >= pointOfViews.count { 40 | index = 0 41 | } 42 | 43 | inCarView = (index == 0) 44 | 45 | // set it with an implicit transaction 46 | SCNTransaction.begin() 47 | SCNTransaction.animationDuration = 0.75 48 | self.pointOfView = pointOfViews[index] 49 | SCNTransaction.commit() 50 | } 51 | 52 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 53 | let touch = touches.first! 54 | 55 | //test if we hit the camera button 56 | let scene = overlaySKScene 57 | var p = touch.location(in: self) 58 | p = scene!.convertPoint(fromView: p) 59 | let node = scene!.atPoint(p) 60 | 61 | if node.name != nil && node.name == "camera" { 62 | //play a sound 63 | node.run(SKAction.playSoundFileNamed("click.caf", waitForCompletion: false)) 64 | //change the point of view 65 | changePointOfView() 66 | return 67 | } 68 | 69 | //update the total number of touches on screen 70 | let allTouches = event!.allTouches 71 | touchCount = allTouches!.count 72 | } 73 | 74 | override func touchesEnded(_ touches: Set, with event: UIEvent?) { 75 | touchCount = 0 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /SceneKitVehicle/GameViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameViewController.swift 3 | // SceneKitVehicle 4 | // 5 | // Translated by OOPer in cooperation with shlab.jp, on 2014/08/17. 6 | // Copyright (c) 2014年 Apple Inc. All rights reserved. 7 | // 8 | /* 9 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 10 | See LICENSE.txt for this sample’s licensing information 11 | 12 | Abstract: 13 | 14 | A view controller that conforms to SCNSceneRendererDelegate and implements the game logic. 15 | 16 | */ 17 | 18 | import UIKit 19 | import CoreMotion 20 | import SpriteKit 21 | import SceneKit 22 | import GameController 23 | import simd 24 | 25 | //--Global constants 26 | //let π = M_PI 27 | //let π_2 = M_PI_2 28 | //let π_4 = M_PI_4 29 | 30 | @objc(AAPLGameViewController) 31 | class GameViewController: UIViewController, SCNSceneRendererDelegate { 32 | 33 | private let MAX_SPEED: CGFloat = 250 34 | 35 | //some node references for manipulation 36 | private var _spotLightNode: SCNNode! 37 | private var _cameraNode: SCNNode! //the node that owns the camera 38 | private var _vehicleNode: SCNNode! 39 | private var _vehicle: SCNPhysicsVehicle! 40 | private var _reactor: SCNParticleSystem! 41 | 42 | //accelerometer 43 | private var _motionManager: CMMotionManager! 44 | private var _accelerometer = [UIAccelerationValue](repeating: 0.0, count: 3) 45 | private var _orientation: CGFloat = 0.0 46 | 47 | //reactor's particle birth rate 48 | private var _reactorDefaultBirthRate: CGFloat = 0.0 49 | 50 | // steering factor 51 | private var _vehicleSteering: CGFloat = 0.0 52 | 53 | private lazy var deviceName: String = { 54 | var systemInfo = utsname() 55 | uname(&systemInfo) 56 | return withUnsafePointer(to: systemInfo.machine) {machinePtr in 57 | String(cString: UnsafeRawPointer(machinePtr).assumingMemoryBound(to: CChar.self)) 58 | } 59 | }() 60 | 61 | private var isHighEndDevice: Bool { 62 | //return YES for iPhone 5s and iPad air, NO otherwise 63 | return deviceName.hasPrefix("iPad4") 64 | || deviceName.hasPrefix("iPhone6") 65 | //### Added later devices... 66 | || deviceName.hasPrefix("iPad5") 67 | || deviceName.hasPrefix("iPad6") 68 | || deviceName.hasPrefix("iPad7") 69 | || deviceName.hasPrefix("iPad8") 70 | || deviceName.hasPrefix("iPhone7") 71 | || deviceName.hasPrefix("iPhone8") 72 | || deviceName.hasPrefix("iPhone9") 73 | || deviceName.hasPrefix("iPhone10") 74 | || deviceName.hasPrefix("iPhone11") 75 | 76 | } 77 | 78 | private func setupEnvironment(_ scene: SCNScene) { 79 | // add an ambient light 80 | let ambientLight = SCNNode() 81 | ambientLight.light = SCNLight() 82 | ambientLight.light!.type = SCNLight.LightType.ambient 83 | ambientLight.light!.color = UIColor(white: 0.3, alpha: 1.0) 84 | scene.rootNode.addChildNode(ambientLight) 85 | 86 | //add a key light to the scene 87 | let lightNode = SCNNode() 88 | lightNode.light = SCNLight() 89 | lightNode.light!.type = SCNLight.LightType.spot 90 | if isHighEndDevice { 91 | lightNode.light!.castsShadow = true 92 | } 93 | lightNode.light!.color = UIColor(white: 0.8, alpha: 1.0) 94 | lightNode.position = SCNVector3Make(0, 80, 30) 95 | lightNode.rotation = SCNVector4Make(1, 0, 0, -Float.pi/2.8) 96 | lightNode.light!.spotInnerAngle = 0 97 | lightNode.light!.spotOuterAngle = 50 98 | lightNode.light!.shadowColor = SKColor.black 99 | lightNode.light!.zFar = 500 100 | lightNode.light!.zNear = 50 101 | scene.rootNode.addChildNode(lightNode) 102 | 103 | //keep an ivar for later manipulation 104 | _spotLightNode = lightNode 105 | 106 | //floor 107 | let floor = SCNNode() 108 | floor.geometry = SCNFloor() 109 | floor.geometry!.firstMaterial!.diffuse.contents = "wood.png" 110 | floor.geometry!.firstMaterial!.diffuse.contentsTransform = SCNMatrix4MakeScale(2, 2, 1) //scale the wood texture 111 | floor.geometry!.firstMaterial!.locksAmbientWithDiffuse = true 112 | if isHighEndDevice { 113 | (floor.geometry as! SCNFloor).reflectionFalloffEnd = 10 114 | } 115 | 116 | let staticBody = SCNPhysicsBody.static() 117 | floor.physicsBody = staticBody 118 | scene.rootNode.addChildNode(floor) 119 | } 120 | 121 | private func addTrainToScene(_ scene: SCNScene, atPosition pos: SCNVector3) { 122 | let trainScene = SCNScene(named: "train_flat")! 123 | 124 | //physicalize the train with simple boxes 125 | for node in trainScene.rootNode.childNodes { 126 | //let node = obj as! SCNNode 127 | if node.geometry != nil { 128 | node.position = SCNVector3Make(node.position.x + pos.x, node.position.y + pos.y, node.position.z + pos.z) 129 | 130 | let (min, max) = node.boundingBox 131 | 132 | let body = SCNPhysicsBody.dynamic() 133 | let boxShape = SCNBox(width:CGFloat(max.x - min.x), height:CGFloat(max.y - min.y), length:CGFloat(max.z - min.z), chamferRadius:0.0) 134 | body.physicsShape = SCNPhysicsShape(geometry: boxShape, options:nil) 135 | 136 | node.pivot = SCNMatrix4MakeTranslation(0, -min.y, 0) 137 | node.physicsBody = body 138 | scene.rootNode.addChildNode(node) 139 | } 140 | } 141 | 142 | //add smoke 143 | let smokeHandle = scene.rootNode.childNode(withName: "Smoke", recursively: true) 144 | smokeHandle!.addParticleSystem(SCNParticleSystem(named: "smoke", inDirectory: nil)!) 145 | 146 | //add physics constraints between engine and wagons 147 | let engineCar = scene.rootNode.childNode(withName: "EngineCar", recursively: false) 148 | let wagon1 = scene.rootNode.childNode(withName: "Wagon1", recursively: false) 149 | let wagon2 = scene.rootNode.childNode(withName: "Wagon2", recursively: false) 150 | 151 | let (min, max) = engineCar!.boundingBox 152 | 153 | let (wmin, wmax) = wagon1!.boundingBox 154 | 155 | // Tie EngineCar & Wagon1 156 | var joint = SCNPhysicsBallSocketJoint(bodyA: engineCar!.physicsBody!, anchorA: SCNVector3Make(max.x, min.y, 0), 157 | bodyB: wagon1!.physicsBody!, anchorB: SCNVector3Make(wmin.x, wmin.y, 0)) 158 | scene.physicsWorld.addBehavior(joint) 159 | 160 | // Wagon1 & Wagon2 161 | joint = SCNPhysicsBallSocketJoint(bodyA: wagon1!.physicsBody!, anchorA: SCNVector3Make(wmax.x + 0.1, wmin.y, 0), 162 | bodyB: wagon2!.physicsBody!, anchorB: SCNVector3Make(wmin.x - 0.1, wmin.y, 0)) 163 | scene.physicsWorld.addBehavior(joint) 164 | } 165 | 166 | 167 | private func addWoodenBlockToScene(_ scene:SCNScene, withImageNamed imageName:NSString, atPosition position:SCNVector3) { 168 | //create a new node 169 | let block = SCNNode() 170 | 171 | //place it 172 | block.position = position 173 | 174 | //attach a box of 5x5x5 175 | block.geometry = SCNBox(width: 5, height: 5, length: 5, chamferRadius: 0) 176 | 177 | //use the specified images named as the texture 178 | block.geometry!.firstMaterial!.diffuse.contents = imageName 179 | 180 | //turn on mipmapping 181 | block.geometry!.firstMaterial!.diffuse.mipFilter = .linear 182 | 183 | //make it physically based 184 | block.physicsBody = SCNPhysicsBody.dynamic() 185 | 186 | //add to the scene 187 | scene.rootNode.addChildNode(block) 188 | } 189 | 190 | private func setupSceneElements(_ scene: SCNScene) { 191 | // add a train 192 | addTrainToScene(scene, atPosition: SCNVector3Make(-5, 20, -40)) 193 | 194 | // add wooden blocks 195 | addWoodenBlockToScene(scene, withImageNamed: "WoodCubeA.jpg", atPosition: SCNVector3Make(-10, 15, 10)) 196 | addWoodenBlockToScene(scene, withImageNamed: "WoodCubeB.jpg", atPosition: SCNVector3Make(-9, 10, 10)) 197 | addWoodenBlockToScene(scene, withImageNamed: "WoodCubeC.jpg", atPosition: SCNVector3Make(20, 15, -11)) 198 | addWoodenBlockToScene(scene, withImageNamed: "WoodCubeA.jpg", atPosition: SCNVector3Make(25 , 5, -20)) 199 | 200 | // add walls 201 | let wall = SCNNode(geometry: SCNBox(width: 400, height: 100, length: 4, chamferRadius: 0)) 202 | wall.geometry!.firstMaterial!.diffuse.contents = "wall.jpg" 203 | wall.geometry!.firstMaterial!.diffuse.contentsTransform = SCNMatrix4Mult(SCNMatrix4MakeScale(24, 2, 1), SCNMatrix4MakeTranslation(0, 1, 0)) 204 | wall.geometry!.firstMaterial!.diffuse.wrapS = .repeat 205 | wall.geometry!.firstMaterial!.diffuse.wrapT = .mirror 206 | wall.geometry!.firstMaterial!.isDoubleSided = false 207 | wall.castsShadow = false 208 | wall.geometry!.firstMaterial!.locksAmbientWithDiffuse = true 209 | 210 | wall.position = SCNVector3Make(0, 50, -92) 211 | wall.physicsBody = SCNPhysicsBody.static() 212 | scene.rootNode.addChildNode(wall) 213 | 214 | let wallC = wall.clone() 215 | wallC.position = SCNVector3Make(-202, 50, 0) 216 | wallC.rotation = SCNVector4Make(0, 1, 0, .pi/2) 217 | scene.rootNode.addChildNode(wallC) 218 | 219 | let wallD = wall.clone() 220 | wallD.position = SCNVector3Make(202, 50, 0) 221 | wallD.rotation = SCNVector4Make(0, 1, 0, -Float.pi/2) 222 | scene.rootNode.addChildNode(wallD) 223 | 224 | let backWall = SCNNode(geometry: SCNPlane(width: 400, height: 100)) 225 | backWall.geometry!.firstMaterial = wall.geometry!.firstMaterial 226 | backWall.position = SCNVector3Make(0, 50, 200) 227 | backWall.rotation = SCNVector4Make(0, 1, 0, .pi) 228 | backWall.castsShadow = false 229 | backWall.physicsBody = SCNPhysicsBody.static() 230 | scene.rootNode.addChildNode(backWall) 231 | 232 | // add ceil 233 | let ceilNode = SCNNode(geometry: SCNPlane(width: 400, height: 400)) 234 | ceilNode.position = SCNVector3Make(0, 100, 0) 235 | ceilNode.rotation = SCNVector4Make(1, 0, 0, .pi/2) 236 | ceilNode.geometry!.firstMaterial!.isDoubleSided = false 237 | ceilNode.castsShadow = false 238 | ceilNode.geometry!.firstMaterial!.locksAmbientWithDiffuse = true 239 | scene.rootNode.addChildNode(ceilNode) 240 | 241 | //add more block 242 | for _ in 0 ..< 4 { 243 | addWoodenBlockToScene(scene, withImageNamed: "WoodCubeA.jpg", atPosition: SCNVector3Make(Float(arc4random_uniform(60)) - 30, 20, Float(arc4random_uniform(40)) - 20)) 244 | addWoodenBlockToScene(scene, withImageNamed: "WoodCubeB.jpg", atPosition: SCNVector3Make(Float(arc4random_uniform(60)) - 30, 20, Float(arc4random_uniform(40)) - 20)) 245 | addWoodenBlockToScene(scene, withImageNamed: "WoodCubeC.jpg", atPosition: SCNVector3Make(Float(arc4random_uniform(60)) - 30, 20, Float(arc4random_uniform(40)) - 20)) 246 | } 247 | 248 | // add cartoon book 249 | let block = SCNNode() 250 | block.position = SCNVector3Make(20, 10, -16) 251 | block.rotation = SCNVector4Make(0, 1, 0, -Float.pi/4) 252 | block.geometry = SCNBox(width: 22, height: 0.2, length: 34, chamferRadius: 0) 253 | let frontMat = SCNMaterial() 254 | frontMat.locksAmbientWithDiffuse = true 255 | frontMat.diffuse.contents = "book_front.jpg" 256 | frontMat.diffuse.mipFilter = .linear 257 | let backMat = SCNMaterial() 258 | backMat.locksAmbientWithDiffuse = true 259 | backMat.diffuse.contents = "book_back.jpg" 260 | backMat.diffuse.mipFilter = .linear 261 | block.geometry!.materials = [frontMat, backMat] 262 | block.physicsBody = SCNPhysicsBody.dynamic() 263 | scene.rootNode.addChildNode(block) 264 | 265 | // add carpet 266 | let rug = SCNNode() 267 | rug.position = SCNVector3Make(0, 0.01, 0) 268 | rug.rotation = SCNVector4Make(1, 0, 0, .pi/2) 269 | let path = UIBezierPath(roundedRect: CGRect(x: -50, y: -30, width: 100, height: 50), cornerRadius: 2.5) 270 | path.flatness = 0.1 271 | rug.geometry = SCNShape(path: path, extrusionDepth: 0.05) 272 | rug.geometry!.firstMaterial!.locksAmbientWithDiffuse = true 273 | rug.geometry!.firstMaterial!.diffuse.contents = "carpet.jpg" 274 | scene.rootNode.addChildNode(rug) 275 | 276 | // add ball 277 | let ball = SCNNode() 278 | ball.position = SCNVector3Make(-5, 5, -18) 279 | ball.geometry = SCNSphere(radius: 5) 280 | ball.geometry!.firstMaterial!.locksAmbientWithDiffuse = true 281 | ball.geometry!.firstMaterial!.diffuse.contents = "ball.jpg" 282 | ball.geometry!.firstMaterial!.diffuse.contentsTransform = SCNMatrix4MakeScale(2, 1, 1) 283 | ball.geometry!.firstMaterial!.diffuse.wrapS = .mirror 284 | ball.physicsBody = SCNPhysicsBody.dynamic() 285 | ball.physicsBody!.restitution = 0.9 286 | scene.rootNode.addChildNode(ball) 287 | } 288 | 289 | 290 | private func setupVehicle(_ scene: SCNScene) -> SCNNode { 291 | let carScene = SCNScene(named: "rc_car")! 292 | let chassisNode = carScene.rootNode.childNode(withName: "rccarBody", recursively: false) 293 | 294 | // setup the chassis 295 | chassisNode!.position = SCNVector3Make(0, 10, 30) 296 | chassisNode!.rotation = SCNVector4Make(0, 1, 0, .pi) 297 | 298 | let body = SCNPhysicsBody.dynamic() 299 | body.allowsResting = false 300 | body.mass = 80 301 | body.restitution = 0.1 302 | body.friction = 0.5 303 | body.rollingFriction = 0 304 | 305 | chassisNode!.physicsBody = body 306 | scene.rootNode.addChildNode(chassisNode!) 307 | 308 | let pipeNode = chassisNode!.childNode(withName: "pipe", recursively: true) 309 | _reactor = SCNParticleSystem(named: "reactor", inDirectory: nil) 310 | _reactorDefaultBirthRate = _reactor.birthRate 311 | _reactor.birthRate = 0 312 | pipeNode!.addParticleSystem(_reactor) 313 | 314 | //add wheels 315 | let wheel0Node = chassisNode!.childNode(withName: "wheelLocator_FL", recursively: true)! 316 | let wheel1Node = chassisNode!.childNode(withName: "wheelLocator_FR", recursively: true)! 317 | let wheel2Node = chassisNode!.childNode(withName: "wheelLocator_RL", recursively: true)! 318 | let wheel3Node = chassisNode!.childNode(withName: "wheelLocator_RR", recursively: true)! 319 | 320 | let wheel0 = SCNPhysicsVehicleWheel(node: wheel0Node) 321 | let wheel1 = SCNPhysicsVehicleWheel(node: wheel1Node) 322 | let wheel2 = SCNPhysicsVehicleWheel(node: wheel2Node) 323 | let wheel3 = SCNPhysicsVehicleWheel(node: wheel3Node) 324 | 325 | let (min, max) = wheel0Node.boundingBox 326 | let wheelHalfWidth = Float(0.5 * (max.x - min.x)) 327 | 328 | wheel0.connectionPosition = SCNVector3(float3(wheel0Node.convertPosition(SCNVector3Zero, to: chassisNode)) + float3(wheelHalfWidth, 0, 0)) 329 | wheel1.connectionPosition = SCNVector3(float3(wheel1Node.convertPosition(SCNVector3Zero, to: chassisNode)) - float3(wheelHalfWidth, 0, 0)) 330 | wheel2.connectionPosition = SCNVector3(float3(wheel2Node.convertPosition(SCNVector3Zero, to: chassisNode)) + float3(wheelHalfWidth, 0, 0)) 331 | wheel3.connectionPosition = SCNVector3(float3(wheel3Node.convertPosition(SCNVector3Zero, to: chassisNode)) - float3(wheelHalfWidth, 0, 0)) 332 | 333 | // create the physics vehicle 334 | let vehicle = SCNPhysicsVehicle(chassisBody: chassisNode!.physicsBody!, wheels: [wheel0, wheel1, wheel2, wheel3]) 335 | scene.physicsWorld.addBehavior(vehicle) 336 | 337 | _vehicle = vehicle 338 | 339 | return chassisNode! 340 | } 341 | 342 | private func setupScene() -> SCNScene { 343 | // create a new scene 344 | let scene = SCNScene() 345 | 346 | //global environment 347 | setupEnvironment(scene) 348 | 349 | //add elements 350 | setupSceneElements(scene) 351 | 352 | //setup vehicle 353 | _vehicleNode = setupVehicle(scene) 354 | 355 | //create a main camera 356 | _cameraNode = SCNNode() 357 | _cameraNode.camera = SCNCamera() 358 | _cameraNode.camera!.zFar = 500 359 | _cameraNode.position = SCNVector3Make(0, 60, 50) 360 | _cameraNode.rotation = SCNVector4Make(1, 0, 0, -Float.pi/4 * 0.75) 361 | scene.rootNode.addChildNode(_cameraNode) 362 | 363 | //add a secondary camera to the car 364 | let frontCameraNode = SCNNode() 365 | frontCameraNode.position = SCNVector3Make(0, 3.5, 2.5) 366 | frontCameraNode.rotation = SCNVector4Make(0, 1, 0, .pi) 367 | frontCameraNode.camera = SCNCamera() 368 | frontCameraNode.camera!.xFov = 75 369 | frontCameraNode.camera!.zFar = 500 370 | 371 | _vehicleNode.addChildNode(frontCameraNode) 372 | 373 | return scene 374 | } 375 | 376 | private func setupAccelerometer() { 377 | //event 378 | _motionManager = CMMotionManager() 379 | 380 | if GCController.controllers().count == 0 && _motionManager.isAccelerometerAvailable { 381 | _motionManager.accelerometerUpdateInterval = 1/60.0 382 | _motionManager.startAccelerometerUpdates(to: OperationQueue.main) {[weak self] accelerometerData, error in 383 | self!.accelerometerDidChange(accelerometerData!.acceleration) 384 | } 385 | } 386 | } 387 | 388 | override var prefersStatusBarHidden : Bool { 389 | return true 390 | } 391 | 392 | override func viewDidLoad() { 393 | super.viewDidLoad() 394 | 395 | UIApplication.shared.isStatusBarHidden = true 396 | 397 | let scnView = view as! SCNView 398 | 399 | //set the background to back 400 | scnView.backgroundColor = SKColor.black 401 | 402 | //setup the scene 403 | let scene = setupScene() 404 | 405 | //present it 406 | scnView.scene = scene 407 | 408 | //tweak physics 409 | scnView.scene!.physicsWorld.speed = 4.0 410 | 411 | //setup overlays 412 | scnView.overlaySKScene = OverlayScene(size: scnView.bounds.size) 413 | 414 | //setup accelerometer 415 | setupAccelerometer() 416 | 417 | //initial point of view 418 | scnView.pointOfView = _cameraNode 419 | 420 | //plug game logic 421 | scnView.delegate = self 422 | 423 | 424 | let doubleTap = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap(_:))) 425 | doubleTap.numberOfTapsRequired = 2 426 | doubleTap.numberOfTouchesRequired = 2 427 | scnView.gestureRecognizers = [doubleTap] 428 | 429 | super.viewDidLoad() 430 | } 431 | 432 | @objc func handleDoubleTap(_ gesture: UITapGestureRecognizer) { 433 | let scene = setupScene() 434 | 435 | let scnView = view as! SCNView 436 | //present it 437 | scnView.scene = scene 438 | 439 | //tweak physics 440 | scnView.scene!.physicsWorld.speed = 4.0 441 | 442 | //initial point of view 443 | scnView.pointOfView = _cameraNode 444 | 445 | (scnView as! GameView).touchCount = 0 446 | } 447 | 448 | // game logic 449 | func renderer(_ aRenderer: SCNSceneRenderer, didSimulatePhysicsAtTime time: TimeInterval) { 450 | let defaultEngineForce: CGFloat = 300.0 451 | let defaultBrakingForce: CGFloat = 3.0 452 | let steeringClamp: CGFloat = 0.6 453 | let cameraDamping: CGFloat = 0.3 454 | 455 | let scnView = view as! GameView 456 | 457 | var engineForce: CGFloat = 0 458 | var brakingForce: CGFloat = 0 459 | 460 | let controllers = GCController.controllers() 461 | 462 | var orientation = _orientation 463 | 464 | //drive: 1 touch = accelerate, 2 touches = backward, 3 touches = brake 465 | if scnView.touchCount == 1 { 466 | engineForce = defaultEngineForce 467 | _reactor.birthRate = _reactorDefaultBirthRate 468 | } else if scnView.touchCount == 2 { 469 | engineForce = -defaultEngineForce 470 | _reactor.birthRate = 0 471 | } else if scnView.touchCount == 3 { 472 | brakingForce = 100 473 | _reactor.birthRate = 0 474 | } else { 475 | brakingForce = defaultBrakingForce 476 | _reactor.birthRate = 0 477 | } 478 | 479 | //controller support 480 | if !controllers.isEmpty { 481 | let controller = controllers[0] 482 | let pad = controller.gamepad! 483 | let dpad = pad.dpad 484 | 485 | struct My { 486 | static var orientationCum: CGFloat = 0 487 | } 488 | 489 | let INCR_ORIENTATION: CGFloat = 0.03 490 | let DECR_ORIENTATION: CGFloat = 0.8 491 | 492 | if dpad.right.isPressed { 493 | if My.orientationCum < 0 { 494 | My.orientationCum *= DECR_ORIENTATION 495 | } 496 | My.orientationCum += INCR_ORIENTATION 497 | if My.orientationCum > 1 { 498 | My.orientationCum = 1 499 | } 500 | } else if dpad.left.isPressed { 501 | if My.orientationCum > 0 { 502 | My.orientationCum *= DECR_ORIENTATION 503 | } 504 | My.orientationCum -= INCR_ORIENTATION 505 | if My.orientationCum < -1 { 506 | My.orientationCum = -1 507 | } 508 | } else { 509 | My.orientationCum *= DECR_ORIENTATION 510 | } 511 | 512 | orientation = My.orientationCum 513 | 514 | if pad.buttonX.isPressed { 515 | engineForce = defaultEngineForce 516 | _reactor.birthRate = _reactorDefaultBirthRate 517 | } else if pad.buttonA.isPressed { 518 | engineForce = -defaultEngineForce 519 | _reactor.birthRate = 0 520 | } else if pad.buttonB.isPressed { 521 | brakingForce = 100 522 | _reactor.birthRate = 0 523 | } else { 524 | brakingForce = defaultBrakingForce 525 | _reactor.birthRate = 0 526 | } 527 | } 528 | 529 | _vehicleSteering = -orientation 530 | if orientation == 0 { 531 | _vehicleSteering *= 0.9 532 | } 533 | if _vehicleSteering < -steeringClamp { 534 | _vehicleSteering = -steeringClamp 535 | } 536 | if _vehicleSteering > steeringClamp { 537 | _vehicleSteering = steeringClamp 538 | } 539 | 540 | //update the vehicle steering and acceleration 541 | _vehicle.setSteeringAngle(_vehicleSteering, forWheelAt: 0) 542 | _vehicle.setSteeringAngle(_vehicleSteering, forWheelAt: 1) 543 | 544 | _vehicle.applyEngineForce(engineForce, forWheelAt: 2) 545 | _vehicle.applyEngineForce(engineForce, forWheelAt: 3) 546 | 547 | _vehicle.applyBrakingForce(brakingForce, forWheelAt: 2) 548 | _vehicle.applyBrakingForce(brakingForce, forWheelAt: 3) 549 | 550 | //check if the car is upside down 551 | reorientCarIfNeeded() 552 | 553 | // make camera follow the car node 554 | let car = _vehicleNode.presentation 555 | let carPos = car.position 556 | let targetPos = float3(carPos.x, Float(30), carPos.z + 25) 557 | var cameraPos = float3(_cameraNode.position) 558 | cameraPos = mix(cameraPos, targetPos, t: Float(cameraDamping)) 559 | _cameraNode.position = SCNVector3(cameraPos) 560 | 561 | if scnView.inCarView { 562 | //move spot light in front of the camera 563 | let frontPosition = scnView.pointOfView!.presentation.convertPosition(SCNVector3Make(0, 0, -30), to:nil) 564 | _spotLightNode.position = SCNVector3Make(frontPosition.x, 80, frontPosition.z) 565 | _spotLightNode.rotation = SCNVector4Make(1,0,0,-Float.pi/2) 566 | } else { 567 | //move spot light on top of the car 568 | _spotLightNode.position = SCNVector3Make(carPos.x, 80, carPos.z + 30) 569 | _spotLightNode.rotation = SCNVector4Make(1,0,0,-Float.pi/2.8) 570 | } 571 | 572 | //speed gauge 573 | let overlayScene = scnView.overlaySKScene as! OverlayScene 574 | overlayScene.speedNeedle.zRotation = -(_vehicle.speedInKilometersPerHour * .pi / MAX_SPEED) 575 | } 576 | 577 | private func reorientCarIfNeeded() { 578 | let car = _vehicleNode.presentation 579 | let carPos = car.position 580 | 581 | // make sure the car isn't upside down, and fix it if it is 582 | struct My { 583 | static var ticks = 0 584 | static var check = 0 585 | static var `try` = 0 586 | } 587 | func randf() -> Float { 588 | return Float(arc4random())/Float(UInt32.max) 589 | } 590 | My.ticks += 1 591 | if My.ticks == 30 { 592 | let t = car.worldTransform 593 | if t.m22 <= 0.1 { 594 | My.check += 1 595 | if My.check == 3 { 596 | My.try += 1 597 | if My.try == 3 { 598 | My.try = 0 599 | 600 | //hard reset 601 | _vehicleNode.rotation = SCNVector4Make(0, 0, 0, 0) 602 | _vehicleNode.position = SCNVector3Make(carPos.x, carPos.y + 10, carPos.z) 603 | _vehicleNode.physicsBody!.resetTransform() 604 | } else { 605 | //try to upturn with an random impulse 606 | let pos = SCNVector3Make(-10 * (randf() - 0.5), 0, -10 * (randf() - 0.5)) 607 | _vehicleNode.physicsBody!.applyForce(SCNVector3Make(0, 300, 0), at: pos, asImpulse: true) 608 | } 609 | 610 | My.check = 0 611 | } 612 | } else { 613 | My.check = 0 614 | } 615 | 616 | My.ticks = 0 617 | } 618 | } 619 | 620 | private func accelerometerDidChange(_ acceleration: CMAcceleration) { 621 | let kFilteringFactor = 0.5 622 | 623 | //Use a basic low-pass filter to only keep the gravity in the accelerometer values 624 | _accelerometer[0] = acceleration.x * kFilteringFactor + _accelerometer[0] * (1.0 - kFilteringFactor) 625 | _accelerometer[1] = acceleration.y * kFilteringFactor + _accelerometer[1] * (1.0 - kFilteringFactor) 626 | _accelerometer[2] = acceleration.z * kFilteringFactor + _accelerometer[2] * (1.0 - kFilteringFactor) 627 | 628 | if _accelerometer[0] > 0 { 629 | _orientation = CGFloat(_accelerometer[1] * 1.3) 630 | } else { 631 | _orientation = -CGFloat(_accelerometer[1] * 1.3) 632 | } 633 | } 634 | 635 | override func viewWillDisappear(_ animated: Bool) { 636 | _motionManager.stopAccelerometerUpdates() 637 | _motionManager = nil 638 | } 639 | 640 | override var shouldAutorotate : Bool { 641 | return true 642 | } 643 | 644 | override var supportedInterfaceOrientations : UIInterfaceOrientationMask { 645 | return UIInterfaceOrientationMask.landscape 646 | } 647 | 648 | override func didReceiveMemoryWarning() { 649 | super.didReceiveMemoryWarning() 650 | // Release any cached data, images, etc that aren't in use. 651 | } 652 | 653 | } 654 | -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "size" : "29x29", 15 | "idiom" : "iphone", 16 | "filename" : "icon.png", 17 | "scale" : "2x" 18 | }, 19 | { 20 | "idiom" : "iphone", 21 | "size" : "29x29", 22 | "scale" : "3x" 23 | }, 24 | { 25 | "size" : "40x40", 26 | "idiom" : "iphone", 27 | "filename" : "icon-1.png", 28 | "scale" : "2x" 29 | }, 30 | { 31 | "idiom" : "iphone", 32 | "size" : "40x40", 33 | "scale" : "3x" 34 | }, 35 | { 36 | "size" : "60x60", 37 | "idiom" : "iphone", 38 | "filename" : "icon-2.png", 39 | "scale" : "2x" 40 | }, 41 | { 42 | "idiom" : "iphone", 43 | "size" : "60x60", 44 | "scale" : "3x" 45 | }, 46 | { 47 | "idiom" : "ipad", 48 | "size" : "20x20", 49 | "scale" : "1x" 50 | }, 51 | { 52 | "idiom" : "ipad", 53 | "size" : "20x20", 54 | "scale" : "2x" 55 | }, 56 | { 57 | "size" : "29x29", 58 | "idiom" : "ipad", 59 | "filename" : "icon-3.png", 60 | "scale" : "1x" 61 | }, 62 | { 63 | "size" : "29x29", 64 | "idiom" : "ipad", 65 | "filename" : "icon-4.png", 66 | "scale" : "2x" 67 | }, 68 | { 69 | "size" : "40x40", 70 | "idiom" : "ipad", 71 | "filename" : "icon-5.png", 72 | "scale" : "1x" 73 | }, 74 | { 75 | "size" : "40x40", 76 | "idiom" : "ipad", 77 | "filename" : "icon-6.png", 78 | "scale" : "2x" 79 | }, 80 | { 81 | "size" : "76x76", 82 | "idiom" : "ipad", 83 | "filename" : "icon-7.png", 84 | "scale" : "1x" 85 | }, 86 | { 87 | "size" : "76x76", 88 | "idiom" : "ipad", 89 | "filename" : "icon-8.png", 90 | "scale" : "2x" 91 | }, 92 | { 93 | "size" : "83.5x83.5", 94 | "idiom" : "ipad", 95 | "filename" : "icon-9.png", 96 | "scale" : "2x" 97 | }, 98 | { 99 | "size" : "1024x1024", 100 | "idiom" : "ios-marketing", 101 | "filename" : "icon-1024.png", 102 | "scale" : "1x" 103 | } 104 | ], 105 | "info" : { 106 | "version" : 1, 107 | "author" : "xcode" 108 | } 109 | } -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-1.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-1024.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-2.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-3.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-4.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-5.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-6.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-7.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-8.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon-9.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/AppIcon.appiconset/icon.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "filename" : "launch.png", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "extent" : "full-screen", 13 | "idiom" : "iphone", 14 | "subtype" : "retina4", 15 | "filename" : "launch-1.png", 16 | "minimum-system-version" : "7.0", 17 | "orientation" : "portrait", 18 | "scale" : "2x" 19 | }, 20 | { 21 | "orientation" : "portrait", 22 | "idiom" : "ipad", 23 | "extent" : "full-screen", 24 | "minimum-system-version" : "7.0", 25 | "scale" : "1x" 26 | }, 27 | { 28 | "orientation" : "landscape", 29 | "idiom" : "ipad", 30 | "extent" : "full-screen", 31 | "minimum-system-version" : "7.0", 32 | "filename" : "launch-4.png", 33 | "scale" : "1x" 34 | }, 35 | { 36 | "orientation" : "portrait", 37 | "idiom" : "ipad", 38 | "extent" : "full-screen", 39 | "minimum-system-version" : "7.0", 40 | "scale" : "2x" 41 | }, 42 | { 43 | "orientation" : "landscape", 44 | "idiom" : "ipad", 45 | "extent" : "full-screen", 46 | "minimum-system-version" : "7.0", 47 | "scale" : "2x" 48 | } 49 | ], 50 | "info" : { 51 | "version" : 1, 52 | "author" : "xcode" 53 | } 54 | } -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/LaunchImage.launchimage/launch-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/LaunchImage.launchimage/launch-1.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/LaunchImage.launchimage/launch-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/LaunchImage.launchimage/launch-4.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/LaunchImage.launchimage/launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/LaunchImage.launchimage/launch.png -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/texture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "texture.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /SceneKitVehicle/Images.xcassets/texture.imageset/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/Images.xcassets/texture.imageset/texture.png -------------------------------------------------------------------------------- /SceneKitVehicle/OverlayScene.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OverlayScene.swift 3 | // SceneKitVehicle 4 | // 5 | // Translated by OOPer in cooperation with shlab.jp, on 2014/08/17. 6 | // 7 | // 8 | /* 9 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 10 | See LICENSE.txt for this sample’s licensing information 11 | 12 | Abstract: 13 | 14 | A SpriteKit scene used as an overlay. 15 | 16 | */ 17 | 18 | import SpriteKit 19 | 20 | @objc(AAPLOverlayScene) 21 | class OverlayScene: SKScene { 22 | 23 | private(set) var speedNeedle: SKNode! 24 | 25 | 26 | override init(size: CGSize) { 27 | super.init(size: size) 28 | //setup the overlay scene 29 | anchorPoint = CGPoint(x: 0.5, y: 0.5) 30 | 31 | //automatically resize to fill the viewport 32 | scaleMode = .resizeFill 33 | 34 | //make UI larger on iPads 35 | let iPad = UIDevice.current.userInterfaceIdiom == .pad 36 | let scale: CGFloat = iPad ? 1.5 : 1 37 | 38 | //add the speed gauge 39 | let myImage = SKSpriteNode(imageNamed: "speedGauge.png") 40 | myImage.anchorPoint = CGPoint(x: 0.5, y: 0) 41 | myImage.position = CGPoint(x: size.width * 0.33, y: -size.height * 0.5) 42 | myImage.xScale = 0.8 * scale 43 | myImage.yScale = 0.8 * scale 44 | addChild(myImage) 45 | 46 | //add the needed 47 | let needleHandle = SKNode() 48 | let needle = SKSpriteNode(imageNamed: "needle.png") 49 | needleHandle.position = CGPoint(x: 0, y: 16) 50 | needle.anchorPoint = CGPoint(x: 0.5, y: 0) 51 | needle.xScale = 0.7 52 | needle.yScale = 0.7 53 | needle.zRotation = .pi/2 54 | needleHandle.addChild(needle) 55 | myImage.addChild(needleHandle) 56 | 57 | speedNeedle = needleHandle 58 | 59 | //add the camera button 60 | let cameraImage = SKSpriteNode(imageNamed: "video_camera.png") 61 | cameraImage.position = CGPoint(x: -size.width * 0.4, y: -size.height * 0.4) 62 | cameraImage.name = "camera" 63 | cameraImage.xScale = 0.6 * scale 64 | cameraImage.yScale = 0.6 * scale 65 | addChild(cameraImage) 66 | } 67 | required init?(coder aDecoder: NSCoder) { 68 | super.init(coder: aDecoder) 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /SceneKitVehicle/SceneKitVehicle-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main_iPhone 29 | UIMainStoryboardFile~ipad 30 | Main_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UIRequiresFullScreen 36 | 37 | UIStatusBarHidden 38 | 39 | UISupportedInterfaceOrientations 40 | 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /SceneKitVehicle/SceneKitVehicle-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #import 10 | #endif 11 | -------------------------------------------------------------------------------- /SceneKitVehicle/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /SceneKitVehicle/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Apple Inc. All Rights Reserved. 3 | See LICENSE.txt for this sample’s licensing information 4 | 5 | */ 6 | 7 | #import 8 | 9 | #import "AAPLAppDelegate.h" 10 | 11 | int main(int argc, char * argv[]) 12 | { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AAPLAppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SceneKitVehicle/resources/WoodCubeA.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/WoodCubeA.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/WoodCubeB.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/WoodCubeB.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/WoodCubeC.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/WoodCubeC.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/ball.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/ball.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/book_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/book_back.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/book_front.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/book_front.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/book_side.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/book_side.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/book_side_title.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/book_side_title.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/carpet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/carpet.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/carpetOld.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/carpetOld.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/click.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/click.caf -------------------------------------------------------------------------------- /SceneKitVehicle/resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/icon.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/krStar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/krStar.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/launch.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/needle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/needle.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/rc_car_texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/rc_car_texture.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/reactor.scnp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/reactor.scnp -------------------------------------------------------------------------------- /SceneKitVehicle/resources/smoke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/smoke.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/smoke.scnp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/smoke.scnp -------------------------------------------------------------------------------- /SceneKitVehicle/resources/spark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/spark.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/speedGauge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/speedGauge.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/starBurst.skn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/starBurst.skn -------------------------------------------------------------------------------- /SceneKitVehicle/resources/tex_smoke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/tex_smoke.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/tire.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/tire.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/train_wood.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/train_wood.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/video_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/video_camera.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/video_camera@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/video_camera@2x.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/wall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/wall.jpg -------------------------------------------------------------------------------- /SceneKitVehicle/resources/wheel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/wheel.png -------------------------------------------------------------------------------- /SceneKitVehicle/resources/wood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ooper-shlab/SceneKitVehicle1.0-Swift/87e11d098cfbff4c363e5b7e9103f7c012a2caf9/SceneKitVehicle/resources/wood.png --------------------------------------------------------------------------------