├── .DS_Store
├── README.md
├── SkyNinja.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
│ └── xcuserdata
│ │ └── apiapia.xcuserdatad
│ │ ├── UserInterfaceState.xcuserstate
│ │ └── WorkspaceSettings.xcsettings
└── xcuserdata
│ └── apiapia.xcuserdatad
│ └── xcschemes
│ ├── SkyNinja.xcscheme
│ └── xcschememanagement.plist
└── SkyNinja
├── .DS_Store
├── AppDelegate.swift
├── Assets.xcassets
├── .DS_Store
├── AppIcon.appiconset
│ ├── Contents.json
│ ├── icon-1024.png
│ ├── icon-20-ipad.png
│ ├── icon-20@2x-ipad.png
│ ├── icon-20@2x.png
│ ├── icon-20@3x.png
│ ├── icon-29-ipad.png
│ ├── icon-29.png
│ ├── icon-29@2x-ipad.png
│ ├── icon-29@2x.png
│ ├── icon-29@3x.png
│ ├── icon-40.png
│ ├── icon-40@2x.png
│ ├── icon-40@3x.png
│ ├── icon-50.png
│ ├── icon-50@2x.png
│ ├── icon-57.png
│ ├── icon-57@2x.png
│ ├── icon-60@2x.png
│ ├── icon-60@3x.png
│ ├── icon-72.png
│ ├── icon-72@2x.png
│ ├── icon-76.png
│ ├── icon-76@2x.png
│ └── icon-83.5@2x.png
├── Contents.json
├── Learning.imageset
│ ├── Contents.json
│ └── Learning.png
├── Star.imageset
│ ├── Contents.json
│ └── Star.png
├── bg.imageset
│ ├── Contents.json
│ └── bg.png
├── bomb.imageset
│ ├── Contents.json
│ └── bomb.png
├── coin.imageset
│ ├── Contents.json
│ └── coin.png
├── ground.imageset
│ ├── Contents.json
│ └── ground.png
├── ifiero-logo.imageset
│ ├── Contents.json
│ └── ifiero-logo.png
├── play.imageset
│ ├── Contents.json
│ └── play.png
├── t10001.imageset
│ ├── Contents.json
│ └── t10001.png
├── t1Mask.imageset
│ ├── Contents.json
│ └── t1Mask.png
├── tapToPlay.imageset
│ ├── Contents.json
│ └── tapToPlay.png
├── top.imageset
│ ├── Contents.json
│ └── top.png
├── tree.imageset
│ ├── Contents.json
│ └── cloud.png
├── youlose.imageset
│ ├── Contents.json
│ └── youlose.png
└── youwon.imageset
│ ├── Contents.json
│ └── youwon.png
├── Base.lproj
├── LaunchScreen.storyboard
└── Main.storyboard
├── Constant.swift
├── Elements Class
├── LineNode.swift
├── PlayerNodeClass.swift
└── SpawnElements.swift
├── GameScene.sks
├── GameScene.swift
├── GameStates
├── GameOverState.swift
├── PlayState.swift
└── WaitingState.swift
├── GameViewController.swift
├── Info.plist
├── Resources
├── .DS_Store
├── Images
│ ├── .DS_Store
│ └── Ninja.atlas
│ │ ├── .DS_Store
│ │ ├── t10001.png
│ │ ├── t10002.png
│ │ ├── t10003.png
│ │ ├── t10004.png
│ │ ├── t10005.png
│ │ ├── t10006.png
│ │ ├── t10007.png
│ │ └── t10008.png
├── Particles
│ ├── CollectNormal.sks
│ ├── Trail.sks
│ └── death.sks
├── SoundsFiles
│ ├── .DS_Store
│ ├── Bomb.wav
│ ├── background.mp3
│ ├── coin.wav
│ └── ninjaHit.wav
└── Utils
│ ├── CGFloat+Extension.swift
│ └── CGVector+Extensions.swift
└── death.caf
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/.DS_Store
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | SKY NINJA SpriteKit Game Tutorial
2 |
3 | GIF动画演示:https://upload-images.jianshu.io/upload_images/3896436-8488f7fa265bdeb1.gif?imageMogr2/auto-orient/strip
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | //
18 | // GameScene.swift
19 | // SkyNinja
20 | /*
21 | * *** 游戏元素使用条款及注意事项 ***
22 | *
23 | * 游戏中的所有元素全部由iFIERO所原创(除注明引用之外),包括人物、音乐、场景等;
24 | * 创作的初衷就是让更多的游戏爱好者可以在开发游戏中获得自豪感 -- 让手机游戏开发变得简单;
25 | * 秉着开源分享的原则,iFIERO发布的游戏都尽可能的易懂实用,并开放所有源码;
26 | * 任何使用者都可以使用游戏中的代码块,也可以进行拷贝、修改、更新、升级,无须再经过iFIERO的同意;
27 | * 但这并不表示可以任意复制、拆分其中的游戏元素:
28 | * 用于[商业目的]而不注明出处;
29 | * 用于[任何教学]而不注明出处;
30 | * 用于[游戏上架]而不注明出处;
31 | * 另外,iFIERO有商用授权游戏元素,获得iFIERO官方授权后,即无任何限制;
32 | * 请尊重帮助过你的iFIERO的知识产权,非常感谢;
33 | *
34 | * Created by VANGO杨 && ANDREW陈
35 | * Copyright © 2018 iFiero. All rights reserved.
36 | * www.iFIERO.com
37 | * iFIERO -- 让手机游戏开发变得简单
38 | *
39 | * SkyNinja 天猪之城 在此游戏中您将获得如下技能:
40 | *
41 | * 1、LaunchScreen 学习如何设置游戏启动画面
42 | * 2、Scene 学习如何切换游戏的游戏场景
43 | * 3、Scene Edit 学习直接使用可见即所得操作编辑游戏场景
44 | * 4、Random 利用可复用的随机函数生成Enemy
45 | * 5、SpriteNode class 学习建立独立的class精灵并引入场景scene
46 | * 6、Collision 学习有节点与节点之间的碰撞的原理及处理方法
47 | * 7、Animation&Atlas 学习如何导入动画帧及何为Atlas
48 | * 8、Camera 使用Camera实现endless背景滚动
49 | * 9、Grarity 学习如何点击屏幕时反转重力
50 | * 10、StateMachine GameplayKit 运用之场景切换;(**** 中级技能)
51 | * 11、Partilces 学习如何做特效及把特效发生碰撞时移出场景;(**** 中级技能)
52 | *
53 | */
54 |
55 | ```
56 | import SpriteKit
57 | import GameplayKit
58 |
59 | class GameScene: SKScene ,SKPhysicsContactDelegate{
60 |
61 | var moveAllowed = false /// 场景是否可以移动了;
62 |
63 | //MARK: - StateMachine 场景中各个舞台State
64 | lazy var stateMachine:GKStateMachine = GKStateMachine(states: [
65 | WaitingState(scene: self), //self 为 GameScene ,把GameScene专入State
66 | PlayState(scene: self),
67 | GameOverState(scene: self)
68 | ])
69 |
70 | //MARK: - 场景中的所有SpriteNode
71 | /*
72 | * 1.调用 Elements Class 的节点,须在GameScene的把节点的Custom Class设为PlayerNode
73 | * 2.Module 设为项目名称 SkyNinja
74 | * 3.为何要设置独立的class精灵,可以为GameScene减少代码,并有利于代码的复用;
75 | */
76 | var playerNode:PlayerNodeClass!
77 | var coinTempNode:SKSpriteNode!
78 | var bombTempNode:SKSpriteNode!
79 | var mainCamera:SKCameraNode!
80 | var groundNode:SKSpriteNode! /// 地面
81 | var skyNode:SKSpriteNode! /// 天空
82 | var spawnElements = SpawnElements() /// 生成节点工具 特别注意,这里非 spawnElements = SpawnElements!
83 |
84 | private var dt:TimeInterval = 0 /// 每一frame的时间差
85 | private var lastUpdateTimeInterval:TimeInterval = 0
86 |
87 | override func didMove(to view: SKView) {
88 | super.didMove(to: view)
89 | self.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8) /// 物理世界的重力
90 | self.physicsWorld.contactDelegate = self /// 碰撞代理
91 |
92 | initCamera() /// Camera
93 | initBgMusic() /// 背景音乐
94 | initPlayer() /// 初始化玩家
95 | initCoinBomb() /// 临时的Coin+Bomb
96 | initSkyGroundLine() // 建立物理天空+地面
97 | stateMachine.enter(WaitingState.self) /// 初始化以上的各个精灵SpriteNode后,再进入WaitingState 场景舞台State
98 | }
99 | //MARK: - 加入Camera
100 | func initCamera(){
101 | mainCamera = childNode(withName: "MainCamera") as! SKCameraNode
102 | }
103 | //MARK: - 移动Camera
104 | func moveCamera(){
105 | self.mainCamera.position.x += CAMERA_MOVE_XPOS ///向右移动
106 | }
107 | //MARK: - 停止Camera
108 | func stopCamera(){
109 | self.mainCamera.removeAllActions()
110 | }
111 | // MARK:-初始化玩家
112 | func initPlayer(){
113 |
114 | playerNode = childNode(withName: "Player") as! PlayerNodeClass
115 | playerNode.physicsBody?.affectedByGravity = true
116 | playerNode.initPlayer()
117 | }
118 | // MARK:-背景音乐
119 | func initBgMusic(){
120 |
121 | let bgMusic = SKAudioNode(fileNamed: "background.mp3")
122 | bgMusic.autoplayLooped = true
123 | addChild(bgMusic)
124 | }
125 |
126 | func initCoinBomb(){
127 | coinTempNode = childNode(withName: "CoinTemp") as! SKSpriteNode
128 | bombTempNode = childNode(withName: "BombTemp") as! SKSpriteNode
129 | }
130 | //MARK: - 物理线
131 | func initSkyGroundLine(){
132 |
133 | skyNode = childNode(withName: "Sky") as! SKSpriteNode
134 | let sykLine = LineNode() /// 生成新的节点 比如 let newNode = SKNode()
135 | sykLine.initSkyLine(size: size, yPos: skyNode.position.y + 10)
136 | addChild(sykLine)
137 |
138 |
139 | groundNode = childNode(withName: "Ground") as! SKSpriteNode
140 | let groundLine = LineNode()
141 | groundLine.initGroundLine(size: size, yPos: groundNode.position.y + groundNode.size.height - 10)
142 | addChild(groundLine)
143 |
144 | }
145 |
146 | // MARK: - 反转物理世界;
147 | func reverseGravity(){
148 | physicsWorld.gravity *= -1
149 | }
150 |
151 | // MARK: - 根据 camera.position.x 移动所有页面元素;
152 | ///因为节点anchorPoint为(0,0),且相机的初始位置为 1024,所以要把相机的位置扣除1024 即(camera.position.x - self.size.width / 2)
153 | func moveSprites(camera:SKCameraNode){
154 | /// 所有的天空精灵
155 | enumerateChildNodes(withName: "Sky") { (node, error) in
156 | if node.position.x + self.size.width < (camera.position.x - self.size.width / 2) {
157 | node.position.x += self.size.width * SCENE_NUMBERS
158 | }
159 | }
160 | /// 所有的地面精灵;
161 | enumerateChildNodes(withName: "Ground") { (node, error) in
162 | if node.position.x + self.size.width < (camera.position.x - self.size.width / 2 ) {
163 | node.position.x += self.size.width * SCENE_NUMBERS
164 | }
165 | /// print("所有的地面精灵",node.position.x,(camera.position.x - self.size.width / 2 ))
166 | }
167 | /// 所有线和Camera同步
168 | enumerateChildNodes(withName: "Line") { (node, error) in
169 | // let node = node as! SKNode
170 | node.position.x += CAMERA_MOVE_XPOS
171 | if node.position.x < -self.size.width {
172 | node.position.x += self.size.width * SCENE_NUMBERS
173 | }
174 | }
175 | /// 所有树
176 | /// 树为何不:(camera.position.x - self.size.width / 2 ),请注意树的 anchorPoint(0.5,0.5)
177 | enumerateChildNodes(withName: "Tree") { (node, error) in
178 | if node.position.x + self.size.width < (camera.position.x ) {
179 | node.position.x += self.size.width * SCENE_NUMBERS
180 | }
181 | }
182 | /// 所有背景
183 | enumerateChildNodes(withName: "Bg") { (node, error) in
184 |
185 | if node.position.x + self.size.width < (camera.position.x - self.size.width / 2 ) {
186 | node.position.x += self.size.width * SCENE_NUMBERS
187 | }
188 | }
189 | }
190 | // MARK: - 生成节点工具 class
191 | @objc func spawnCoins(){
192 | /// print(spawnElements.spawnCoin(camera: mainCamera))
193 | if moveAllowed {
194 | self.addChild(spawnElements.spawnCoin(camera: mainCamera)) /// 传入主相机位置
195 | }
196 |
197 | }
198 |
199 | @objc func spawnBombs(){
200 | if moveAllowed {
201 | addChild(spawnElements.spawnBomb(camera: mainCamera,scene: self)) /// 传入主相机位置
202 | }
203 | }
204 |
205 | @objc func removeCoins(){
206 | enumerateChildNodes(withName: "coin") { (node, error) in
207 | if node.position.x < self.mainCamera.position.x - self.size.width {
208 | /// print("移除coin")
209 | node.removeFromParent()
210 | }
211 | }
212 | }
213 | // MARK: - 不再生成了;
214 | func stopSpawning(){
215 |
216 | playerNode.removeAction(forKey: "jogging") /// 移除人物的运动;
217 |
218 | enumerateChildNodes(withName: "coin") { (node, error) in
219 | node.removeAllActions()
220 | }
221 | enumerateChildNodes(withName: "bomb") { (node, error) in
222 | node.removeAllActions()
223 | }
224 | }
225 |
226 | //MARK: - 重新开始游戏;
227 | func restartGame(){
228 |
229 | let newScene = GameScene(fileNamed: "GameScene")!
230 | newScene.size = CGSize(width: SCENE_WIDTH, height: SCENE_HEIGHT)
231 | newScene.anchorPoint = CGPoint(x: 0, y: 0)
232 | newScene.scaleMode = .aspectFill
233 | let transition = SKTransition.flipHorizontal(withDuration: 0.5)
234 | view?.presentScene(newScene, transition:transition)
235 | }
236 |
237 | // MARK: - 监测屏幕点击事件
238 | override func touchesBegan(_ touches: Set, with event: UIEvent?) {
239 | guard let touch = touches.first else {
240 | return
241 | }
242 | let touchLocation = touch.location(in: self) ///获得点击的位置
243 | /// 判断目前的GameScene场景舞台是哪个state
244 | switch stateMachine.currentState {
245 | case is WaitingState:
246 | /// 获得按钮的点击位置
247 | guard let body = physicsWorld.body(at: touchLocation) else {
248 | return
249 | }
250 | /// 判断是否是点击了PlayButton
251 | guard let playButton = body.node?.childNode(withName: "PlayButton") as? SKSpriteNode else {
252 | return
253 | }
254 | /// 如果点击位置是在PlayButton
255 | if (playButton.contains(touchLocation)){
256 | playButton.isHidden = true
257 | stateMachine.enter(PlayState.self) /// 进入开始游戏;
258 | }
259 |
260 | case is PlayState:
261 | reverseGravity() /// 反转物理世界;
262 |
263 | case is GameOverState:
264 |
265 | guard let body = physicsWorld.body(at: touchLocation) else {
266 | return
267 | }
268 | // TapToPlay按钮;
269 | if let tapToPlay = body.node?.childNode(withName: "tapToPlay"){
270 |
271 | if tapToPlay.contains(touchLocation){
272 | print("重新开始游戏!")
273 | restartGame()
274 | }
275 | }
276 |
277 | default:
278 | break;
279 |
280 |
281 | }
282 | }
283 | // MARK: - 监测碰撞
284 | func didBegin(_ contact: SKPhysicsContact) {
285 |
286 | let bodyA:SKPhysicsBody
287 | let bodyB:SKPhysicsBody
288 | if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
289 | bodyA = contact.bodyA
290 | bodyB = contact.bodyB
291 | }else{
292 | bodyA = contact.bodyB
293 | bodyB = contact.bodyA
294 | }
295 | ///检测碰到中间线
296 | if bodyA.categoryBitMask == PhysicsCategory.Player && bodyB.categoryBitMask == PhysicsCategory.MiddleLine {
297 | /// print("碰到屏幕线人物反转")
298 | playerNode.reversePlayer()
299 | }
300 |
301 | ///检测碰到coin
302 | if bodyA.categoryBitMask == PhysicsCategory.Player && bodyB.categoryBitMask == PhysicsCategory.Coin {
303 | /// print("碰到屏幕线人物反转")
304 | let coinAction = SKAction.playSoundFileNamed("coin.wav", waitForCompletion: false)
305 | run(coinAction)
306 | bodyB.node?.removeFromParent()
307 | }
308 |
309 | ///检测碰到Bomb
310 | if bodyA.categoryBitMask == PhysicsCategory.Player && bodyB.categoryBitMask == PhysicsCategory.Bomb {
311 | /// 播放音乐
312 | let bombAction = SKAction.playSoundFileNamed("ninjaHit.wav", waitForCompletion: false)
313 | run(bombAction)
314 | /// 移除BOMB
315 | /// bodyB.node?.removeFromParent()
316 | stateMachine.enter(GameOverState.self)
317 | }
318 |
319 | }
320 | // MARK: - 时时更新update
321 | override func update(_ currentTime: TimeInterval) {
322 |
323 | /// 获取时间差
324 | if lastUpdateTimeInterval == 0 {
325 | lastUpdateTimeInterval = currentTime
326 | }
327 | dt = currentTime - lastUpdateTimeInterval
328 | lastUpdateTimeInterval = currentTime
329 |
330 | stateMachine.update(deltaTime: dt) /// 把update传进各个State里;
331 | }
332 | }
333 | ```
334 |
335 |
源码传送门:https://github.com/apiapia/SkyNinjaGameSpriteKitTutorial
336 |
百度源码备份:https://pan.baidu.com/s/1_1rt4fZR2OuDSg-lFDAUQw
337 |
更多手机游戏教程:http://www.iFIERO.com
338 |
--------------------------------------------------------------------------------
/SkyNinja.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2103A5F620CE02C20061DA6A /* PlayerNodeClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2103A5F520CE02C20061DA6A /* PlayerNodeClass.swift */; };
11 | 2103A5F820CE0A590061DA6A /* Constant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2103A5F720CE0A590061DA6A /* Constant.swift */; };
12 | 2103A5FE20CE712F0061DA6A /* LineNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2103A5FD20CE712F0061DA6A /* LineNode.swift */; };
13 | 21302A6F20C8066E0014029B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21302A6E20C8066E0014029B /* AppDelegate.swift */; };
14 | 21302A7120C8066E0014029B /* GameScene.sks in Resources */ = {isa = PBXBuildFile; fileRef = 21302A7020C8066E0014029B /* GameScene.sks */; };
15 | 21302A7520C8066E0014029B /* GameScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21302A7420C8066E0014029B /* GameScene.swift */; };
16 | 21302A7720C8066E0014029B /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21302A7620C8066E0014029B /* GameViewController.swift */; };
17 | 21302A7A20C8066E0014029B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 21302A7820C8066E0014029B /* Main.storyboard */; };
18 | 21302A7C20C8066F0014029B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 21302A7B20C8066F0014029B /* Assets.xcassets */; };
19 | 21302A7F20C8066F0014029B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 21302A7D20C8066F0014029B /* LaunchScreen.storyboard */; };
20 | 21302A8720C807DD0014029B /* Ninja.atlas in Resources */ = {isa = PBXBuildFile; fileRef = 21302A8620C807DD0014029B /* Ninja.atlas */; };
21 | 21302A8B20C809410014029B /* background.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 21302A8A20C809410014029B /* background.mp3 */; };
22 | 21302A8F20C809CD0014029B /* ninjaHit.wav in Resources */ = {isa = PBXBuildFile; fileRef = 21302A8E20C809CD0014029B /* ninjaHit.wav */; };
23 | 21302A9120C809D80014029B /* Bomb.wav in Resources */ = {isa = PBXBuildFile; fileRef = 21302A9020C809D80014029B /* Bomb.wav */; };
24 | 21302A9320C80A900014029B /* coin.wav in Resources */ = {isa = PBXBuildFile; fileRef = 21302A9220C80A900014029B /* coin.wav */; };
25 | 21374EAC20F4A4E60018FD54 /* CollectNormal.sks in Resources */ = {isa = PBXBuildFile; fileRef = 21374EAB20F4A4E60018FD54 /* CollectNormal.sks */; };
26 | 21374EB320F4B1BF0018FD54 /* death.sks in Resources */ = {isa = PBXBuildFile; fileRef = 21374EB220F4B1BF0018FD54 /* death.sks */; };
27 | 21374EB620F4B5E70018FD54 /* death.caf in Resources */ = {isa = PBXBuildFile; fileRef = 21374EB520F4B58F0018FD54 /* death.caf */; };
28 | 21568E8020CD302800800669 /* CGVector+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21568E7F20CD302800800669 /* CGVector+Extensions.swift */; };
29 | 21568E8220CD302E00800669 /* CGFloat+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21568E8120CD302E00800669 /* CGFloat+Extension.swift */; };
30 | 21568E8720CD559600800669 /* PlayState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21568E8620CD559600800669 /* PlayState.swift */; };
31 | 21568E8920CD567500800669 /* GameOverState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21568E8820CD567500800669 /* GameOverState.swift */; };
32 | 21568E8D20CD592C00800669 /* WaitingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21568E8C20CD592C00800669 /* WaitingState.swift */; };
33 | 21FE2DD720CF4C4D0032CE81 /* SpawnElements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21FE2DD620CF4C4D0032CE81 /* SpawnElements.swift */; };
34 | 21FE2DDC20CF6F3D0032CE81 /* Trail.sks in Resources */ = {isa = PBXBuildFile; fileRef = 21FE2DDB20CF6F3D0032CE81 /* Trail.sks */; };
35 | /* End PBXBuildFile section */
36 |
37 | /* Begin PBXFileReference section */
38 | 2103A5F520CE02C20061DA6A /* PlayerNodeClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerNodeClass.swift; sourceTree = ""; };
39 | 2103A5F720CE0A590061DA6A /* Constant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constant.swift; sourceTree = ""; };
40 | 2103A5FD20CE712F0061DA6A /* LineNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineNode.swift; sourceTree = ""; };
41 | 21302A6B20C8066E0014029B /* SkyNinja.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SkyNinja.app; sourceTree = BUILT_PRODUCTS_DIR; };
42 | 21302A6E20C8066E0014029B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
43 | 21302A7020C8066E0014029B /* GameScene.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = GameScene.sks; sourceTree = ""; };
44 | 21302A7420C8066E0014029B /* GameScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameScene.swift; sourceTree = ""; };
45 | 21302A7620C8066E0014029B /* GameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; };
46 | 21302A7920C8066E0014029B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
47 | 21302A7B20C8066F0014029B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
48 | 21302A7E20C8066F0014029B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
49 | 21302A8020C8066F0014029B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
50 | 21302A8620C807DD0014029B /* Ninja.atlas */ = {isa = PBXFileReference; lastKnownFileType = folder.skatlas; path = Ninja.atlas; sourceTree = ""; };
51 | 21302A8A20C809410014029B /* background.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = background.mp3; sourceTree = ""; };
52 | 21302A8E20C809CD0014029B /* ninjaHit.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = ninjaHit.wav; sourceTree = ""; };
53 | 21302A9020C809D80014029B /* Bomb.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = Bomb.wav; sourceTree = ""; };
54 | 21302A9220C80A900014029B /* coin.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = coin.wav; sourceTree = ""; };
55 | 21374EAB20F4A4E60018FD54 /* CollectNormal.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = CollectNormal.sks; sourceTree = ""; };
56 | 21374EB220F4B1BF0018FD54 /* death.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = death.sks; sourceTree = ""; };
57 | 21374EB520F4B58F0018FD54 /* death.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = death.caf; path = SkyNinja/death.caf; sourceTree = SOURCE_ROOT; };
58 | 21568E7F20CD302800800669 /* CGVector+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGVector+Extensions.swift"; sourceTree = ""; };
59 | 21568E8120CD302E00800669 /* CGFloat+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGFloat+Extension.swift"; sourceTree = ""; };
60 | 21568E8620CD559600800669 /* PlayState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayState.swift; sourceTree = ""; };
61 | 21568E8820CD567500800669 /* GameOverState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameOverState.swift; sourceTree = ""; };
62 | 21568E8C20CD592C00800669 /* WaitingState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitingState.swift; sourceTree = ""; };
63 | 21FE2DD620CF4C4D0032CE81 /* SpawnElements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpawnElements.swift; sourceTree = ""; };
64 | 21FE2DDB20CF6F3D0032CE81 /* Trail.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = Trail.sks; sourceTree = ""; };
65 | /* End PBXFileReference section */
66 |
67 | /* Begin PBXFrameworksBuildPhase section */
68 | 21302A6820C8066E0014029B /* Frameworks */ = {
69 | isa = PBXFrameworksBuildPhase;
70 | buildActionMask = 2147483647;
71 | files = (
72 | );
73 | runOnlyForDeploymentPostprocessing = 0;
74 | };
75 | /* End PBXFrameworksBuildPhase section */
76 |
77 | /* Begin PBXGroup section */
78 | 2103A5F420CE02870061DA6A /* Elements Class */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 2103A5F520CE02C20061DA6A /* PlayerNodeClass.swift */,
82 | 2103A5FD20CE712F0061DA6A /* LineNode.swift */,
83 | 21FE2DD620CF4C4D0032CE81 /* SpawnElements.swift */,
84 | );
85 | path = "Elements Class";
86 | sourceTree = "";
87 | };
88 | 21302A6220C8066E0014029B = {
89 | isa = PBXGroup;
90 | children = (
91 | 21302A6D20C8066E0014029B /* SkyNinja */,
92 | 21302A6C20C8066E0014029B /* Products */,
93 | );
94 | sourceTree = "";
95 | };
96 | 21302A6C20C8066E0014029B /* Products */ = {
97 | isa = PBXGroup;
98 | children = (
99 | 21302A6B20C8066E0014029B /* SkyNinja.app */,
100 | );
101 | name = Products;
102 | sourceTree = "";
103 | };
104 | 21302A6D20C8066E0014029B /* SkyNinja */ = {
105 | isa = PBXGroup;
106 | children = (
107 | 21568E8320CD554300800669 /* GameStates */,
108 | 2103A5F420CE02870061DA6A /* Elements Class */,
109 | 21302A8820C809290014029B /* Resources */,
110 | 21302A6E20C8066E0014029B /* AppDelegate.swift */,
111 | 21302A7020C8066E0014029B /* GameScene.sks */,
112 | 21302A7420C8066E0014029B /* GameScene.swift */,
113 | 21302A7620C8066E0014029B /* GameViewController.swift */,
114 | 21302A7820C8066E0014029B /* Main.storyboard */,
115 | 2103A5F720CE0A590061DA6A /* Constant.swift */,
116 | 21302A7B20C8066F0014029B /* Assets.xcassets */,
117 | 21302A7D20C8066F0014029B /* LaunchScreen.storyboard */,
118 | 21302A8020C8066F0014029B /* Info.plist */,
119 | );
120 | path = SkyNinja;
121 | sourceTree = "";
122 | };
123 | 21302A8820C809290014029B /* Resources */ = {
124 | isa = PBXGroup;
125 | children = (
126 | 21FE2DD820CF6D210032CE81 /* Particles */,
127 | 21302A9520C821B60014029B /* Utils */,
128 | 21302A9420C821960014029B /* Images */,
129 | 21302A8920C809300014029B /* SoundsFiles */,
130 | );
131 | path = Resources;
132 | sourceTree = "";
133 | };
134 | 21302A8920C809300014029B /* SoundsFiles */ = {
135 | isa = PBXGroup;
136 | children = (
137 | 21374EB520F4B58F0018FD54 /* death.caf */,
138 | 21302A9220C80A900014029B /* coin.wav */,
139 | 21302A8A20C809410014029B /* background.mp3 */,
140 | 21302A8E20C809CD0014029B /* ninjaHit.wav */,
141 | 21302A9020C809D80014029B /* Bomb.wav */,
142 | );
143 | path = SoundsFiles;
144 | sourceTree = "";
145 | };
146 | 21302A9420C821960014029B /* Images */ = {
147 | isa = PBXGroup;
148 | children = (
149 | 21302A8620C807DD0014029B /* Ninja.atlas */,
150 | );
151 | path = Images;
152 | sourceTree = "";
153 | };
154 | 21302A9520C821B60014029B /* Utils */ = {
155 | isa = PBXGroup;
156 | children = (
157 | 21568E8120CD302E00800669 /* CGFloat+Extension.swift */,
158 | 21568E7F20CD302800800669 /* CGVector+Extensions.swift */,
159 | );
160 | path = Utils;
161 | sourceTree = "";
162 | };
163 | 21568E8320CD554300800669 /* GameStates */ = {
164 | isa = PBXGroup;
165 | children = (
166 | 21568E8C20CD592C00800669 /* WaitingState.swift */,
167 | 21568E8620CD559600800669 /* PlayState.swift */,
168 | 21568E8820CD567500800669 /* GameOverState.swift */,
169 | );
170 | path = GameStates;
171 | sourceTree = "";
172 | };
173 | 21FE2DD820CF6D210032CE81 /* Particles */ = {
174 | isa = PBXGroup;
175 | children = (
176 | 21374EB220F4B1BF0018FD54 /* death.sks */,
177 | 21374EAB20F4A4E60018FD54 /* CollectNormal.sks */,
178 | 21FE2DDB20CF6F3D0032CE81 /* Trail.sks */,
179 | );
180 | path = Particles;
181 | sourceTree = "";
182 | };
183 | /* End PBXGroup section */
184 |
185 | /* Begin PBXNativeTarget section */
186 | 21302A6A20C8066E0014029B /* SkyNinja */ = {
187 | isa = PBXNativeTarget;
188 | buildConfigurationList = 21302A8320C8066F0014029B /* Build configuration list for PBXNativeTarget "SkyNinja" */;
189 | buildPhases = (
190 | 21302A6720C8066E0014029B /* Sources */,
191 | 21302A6820C8066E0014029B /* Frameworks */,
192 | 21302A6920C8066E0014029B /* Resources */,
193 | );
194 | buildRules = (
195 | );
196 | dependencies = (
197 | );
198 | name = SkyNinja;
199 | productName = SkyNinja;
200 | productReference = 21302A6B20C8066E0014029B /* SkyNinja.app */;
201 | productType = "com.apple.product-type.application";
202 | };
203 | /* End PBXNativeTarget section */
204 |
205 | /* Begin PBXProject section */
206 | 21302A6320C8066E0014029B /* Project object */ = {
207 | isa = PBXProject;
208 | attributes = {
209 | LastSwiftUpdateCheck = 0940;
210 | LastUpgradeCheck = 0940;
211 | ORGANIZATIONNAME = iFiero;
212 | TargetAttributes = {
213 | 21302A6A20C8066E0014029B = {
214 | CreatedOnToolsVersion = 9.4;
215 | };
216 | };
217 | };
218 | buildConfigurationList = 21302A6620C8066E0014029B /* Build configuration list for PBXProject "SkyNinja" */;
219 | compatibilityVersion = "Xcode 9.3";
220 | developmentRegion = en;
221 | hasScannedForEncodings = 0;
222 | knownRegions = (
223 | en,
224 | Base,
225 | );
226 | mainGroup = 21302A6220C8066E0014029B;
227 | productRefGroup = 21302A6C20C8066E0014029B /* Products */;
228 | projectDirPath = "";
229 | projectRoot = "";
230 | targets = (
231 | 21302A6A20C8066E0014029B /* SkyNinja */,
232 | );
233 | };
234 | /* End PBXProject section */
235 |
236 | /* Begin PBXResourcesBuildPhase section */
237 | 21302A6920C8066E0014029B /* Resources */ = {
238 | isa = PBXResourcesBuildPhase;
239 | buildActionMask = 2147483647;
240 | files = (
241 | 21374EB620F4B5E70018FD54 /* death.caf in Resources */,
242 | 21302A8B20C809410014029B /* background.mp3 in Resources */,
243 | 21374EAC20F4A4E60018FD54 /* CollectNormal.sks in Resources */,
244 | 21302A7A20C8066E0014029B /* Main.storyboard in Resources */,
245 | 21302A7120C8066E0014029B /* GameScene.sks in Resources */,
246 | 21302A8F20C809CD0014029B /* ninjaHit.wav in Resources */,
247 | 21302A7C20C8066F0014029B /* Assets.xcassets in Resources */,
248 | 21302A9120C809D80014029B /* Bomb.wav in Resources */,
249 | 21FE2DDC20CF6F3D0032CE81 /* Trail.sks in Resources */,
250 | 21302A9320C80A900014029B /* coin.wav in Resources */,
251 | 21302A7F20C8066F0014029B /* LaunchScreen.storyboard in Resources */,
252 | 21374EB320F4B1BF0018FD54 /* death.sks in Resources */,
253 | 21302A8720C807DD0014029B /* Ninja.atlas in Resources */,
254 | );
255 | runOnlyForDeploymentPostprocessing = 0;
256 | };
257 | /* End PBXResourcesBuildPhase section */
258 |
259 | /* Begin PBXSourcesBuildPhase section */
260 | 21302A6720C8066E0014029B /* Sources */ = {
261 | isa = PBXSourcesBuildPhase;
262 | buildActionMask = 2147483647;
263 | files = (
264 | 21568E8020CD302800800669 /* CGVector+Extensions.swift in Sources */,
265 | 2103A5FE20CE712F0061DA6A /* LineNode.swift in Sources */,
266 | 21568E8D20CD592C00800669 /* WaitingState.swift in Sources */,
267 | 2103A5F620CE02C20061DA6A /* PlayerNodeClass.swift in Sources */,
268 | 21302A7520C8066E0014029B /* GameScene.swift in Sources */,
269 | 21568E8920CD567500800669 /* GameOverState.swift in Sources */,
270 | 21302A7720C8066E0014029B /* GameViewController.swift in Sources */,
271 | 21302A6F20C8066E0014029B /* AppDelegate.swift in Sources */,
272 | 21FE2DD720CF4C4D0032CE81 /* SpawnElements.swift in Sources */,
273 | 2103A5F820CE0A590061DA6A /* Constant.swift in Sources */,
274 | 21568E8220CD302E00800669 /* CGFloat+Extension.swift in Sources */,
275 | 21568E8720CD559600800669 /* PlayState.swift in Sources */,
276 | );
277 | runOnlyForDeploymentPostprocessing = 0;
278 | };
279 | /* End PBXSourcesBuildPhase section */
280 |
281 | /* Begin PBXVariantGroup section */
282 | 21302A7820C8066E0014029B /* Main.storyboard */ = {
283 | isa = PBXVariantGroup;
284 | children = (
285 | 21302A7920C8066E0014029B /* Base */,
286 | );
287 | name = Main.storyboard;
288 | sourceTree = "";
289 | };
290 | 21302A7D20C8066F0014029B /* LaunchScreen.storyboard */ = {
291 | isa = PBXVariantGroup;
292 | children = (
293 | 21302A7E20C8066F0014029B /* Base */,
294 | );
295 | name = LaunchScreen.storyboard;
296 | sourceTree = "";
297 | };
298 | /* End PBXVariantGroup section */
299 |
300 | /* Begin XCBuildConfiguration section */
301 | 21302A8120C8066F0014029B /* Debug */ = {
302 | isa = XCBuildConfiguration;
303 | buildSettings = {
304 | ALWAYS_SEARCH_USER_PATHS = NO;
305 | CLANG_ANALYZER_NONNULL = YES;
306 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
308 | CLANG_CXX_LIBRARY = "libc++";
309 | CLANG_ENABLE_MODULES = YES;
310 | CLANG_ENABLE_OBJC_ARC = YES;
311 | CLANG_ENABLE_OBJC_WEAK = YES;
312 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
313 | CLANG_WARN_BOOL_CONVERSION = YES;
314 | CLANG_WARN_COMMA = YES;
315 | CLANG_WARN_CONSTANT_CONVERSION = YES;
316 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
317 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
318 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
319 | CLANG_WARN_EMPTY_BODY = YES;
320 | CLANG_WARN_ENUM_CONVERSION = YES;
321 | CLANG_WARN_INFINITE_RECURSION = YES;
322 | CLANG_WARN_INT_CONVERSION = YES;
323 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
324 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
325 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
326 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
327 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
328 | CLANG_WARN_STRICT_PROTOTYPES = YES;
329 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
330 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
331 | CLANG_WARN_UNREACHABLE_CODE = YES;
332 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
333 | CODE_SIGN_IDENTITY = "iPhone Developer";
334 | COPY_PHASE_STRIP = NO;
335 | DEBUG_INFORMATION_FORMAT = dwarf;
336 | ENABLE_STRICT_OBJC_MSGSEND = YES;
337 | ENABLE_TESTABILITY = YES;
338 | GCC_C_LANGUAGE_STANDARD = gnu11;
339 | GCC_DYNAMIC_NO_PIC = NO;
340 | GCC_NO_COMMON_BLOCKS = YES;
341 | GCC_OPTIMIZATION_LEVEL = 0;
342 | GCC_PREPROCESSOR_DEFINITIONS = (
343 | "DEBUG=1",
344 | "$(inherited)",
345 | );
346 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
347 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
348 | GCC_WARN_UNDECLARED_SELECTOR = YES;
349 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
350 | GCC_WARN_UNUSED_FUNCTION = YES;
351 | GCC_WARN_UNUSED_VARIABLE = YES;
352 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
353 | MTL_ENABLE_DEBUG_INFO = YES;
354 | ONLY_ACTIVE_ARCH = YES;
355 | SDKROOT = iphoneos;
356 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
357 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
358 | };
359 | name = Debug;
360 | };
361 | 21302A8220C8066F0014029B /* Release */ = {
362 | isa = XCBuildConfiguration;
363 | buildSettings = {
364 | ALWAYS_SEARCH_USER_PATHS = NO;
365 | CLANG_ANALYZER_NONNULL = YES;
366 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
367 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
368 | CLANG_CXX_LIBRARY = "libc++";
369 | CLANG_ENABLE_MODULES = YES;
370 | CLANG_ENABLE_OBJC_ARC = YES;
371 | CLANG_ENABLE_OBJC_WEAK = YES;
372 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
373 | CLANG_WARN_BOOL_CONVERSION = YES;
374 | CLANG_WARN_COMMA = YES;
375 | CLANG_WARN_CONSTANT_CONVERSION = YES;
376 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
377 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
378 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
379 | CLANG_WARN_EMPTY_BODY = YES;
380 | CLANG_WARN_ENUM_CONVERSION = YES;
381 | CLANG_WARN_INFINITE_RECURSION = YES;
382 | CLANG_WARN_INT_CONVERSION = YES;
383 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
384 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
385 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
386 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
387 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
388 | CLANG_WARN_STRICT_PROTOTYPES = YES;
389 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
390 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
391 | CLANG_WARN_UNREACHABLE_CODE = YES;
392 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
393 | CODE_SIGN_IDENTITY = "iPhone Developer";
394 | COPY_PHASE_STRIP = NO;
395 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
396 | ENABLE_NS_ASSERTIONS = NO;
397 | ENABLE_STRICT_OBJC_MSGSEND = YES;
398 | GCC_C_LANGUAGE_STANDARD = gnu11;
399 | GCC_NO_COMMON_BLOCKS = YES;
400 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
401 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
402 | GCC_WARN_UNDECLARED_SELECTOR = YES;
403 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
404 | GCC_WARN_UNUSED_FUNCTION = YES;
405 | GCC_WARN_UNUSED_VARIABLE = YES;
406 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
407 | MTL_ENABLE_DEBUG_INFO = NO;
408 | SDKROOT = iphoneos;
409 | SWIFT_COMPILATION_MODE = wholemodule;
410 | SWIFT_OPTIMIZATION_LEVEL = "-O";
411 | VALIDATE_PRODUCT = YES;
412 | };
413 | name = Release;
414 | };
415 | 21302A8420C8066F0014029B /* Debug */ = {
416 | isa = XCBuildConfiguration;
417 | buildSettings = {
418 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
419 | CODE_SIGN_IDENTITY = "iPhone Developer";
420 | CODE_SIGN_STYLE = Automatic;
421 | DEVELOPMENT_TEAM = 48X349N2P7;
422 | INFOPLIST_FILE = SkyNinja/Info.plist;
423 | LD_RUNPATH_SEARCH_PATHS = (
424 | "$(inherited)",
425 | "@executable_path/Frameworks",
426 | );
427 | PRODUCT_BUNDLE_IDENTIFIER = com.iFiero.SkyNinjaGameTutorial;
428 | PRODUCT_NAME = "$(TARGET_NAME)";
429 | PROVISIONING_PROFILE = "";
430 | PROVISIONING_PROFILE_SPECIFIER = "";
431 | SWIFT_VERSION = 4.0;
432 | TARGETED_DEVICE_FAMILY = "1,2";
433 | };
434 | name = Debug;
435 | };
436 | 21302A8520C8066F0014029B /* Release */ = {
437 | isa = XCBuildConfiguration;
438 | buildSettings = {
439 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
440 | CODE_SIGN_IDENTITY = "iPhone Developer";
441 | CODE_SIGN_STYLE = Automatic;
442 | DEVELOPMENT_TEAM = 48X349N2P7;
443 | INFOPLIST_FILE = SkyNinja/Info.plist;
444 | LD_RUNPATH_SEARCH_PATHS = (
445 | "$(inherited)",
446 | "@executable_path/Frameworks",
447 | );
448 | PRODUCT_BUNDLE_IDENTIFIER = com.iFiero.SkyNinjaGameTutorial;
449 | PRODUCT_NAME = "$(TARGET_NAME)";
450 | PROVISIONING_PROFILE = "";
451 | PROVISIONING_PROFILE_SPECIFIER = "";
452 | SWIFT_VERSION = 4.0;
453 | TARGETED_DEVICE_FAMILY = "1,2";
454 | };
455 | name = Release;
456 | };
457 | /* End XCBuildConfiguration section */
458 |
459 | /* Begin XCConfigurationList section */
460 | 21302A6620C8066E0014029B /* Build configuration list for PBXProject "SkyNinja" */ = {
461 | isa = XCConfigurationList;
462 | buildConfigurations = (
463 | 21302A8120C8066F0014029B /* Debug */,
464 | 21302A8220C8066F0014029B /* Release */,
465 | );
466 | defaultConfigurationIsVisible = 0;
467 | defaultConfigurationName = Release;
468 | };
469 | 21302A8320C8066F0014029B /* Build configuration list for PBXNativeTarget "SkyNinja" */ = {
470 | isa = XCConfigurationList;
471 | buildConfigurations = (
472 | 21302A8420C8066F0014029B /* Debug */,
473 | 21302A8520C8066F0014029B /* Release */,
474 | );
475 | defaultConfigurationIsVisible = 0;
476 | defaultConfigurationName = Release;
477 | };
478 | /* End XCConfigurationList section */
479 | };
480 | rootObject = 21302A6320C8066E0014029B /* Project object */;
481 | }
482 |
--------------------------------------------------------------------------------
/SkyNinja.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SkyNinja.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SkyNinja.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/SkyNinja.xcodeproj/project.xcworkspace/xcuserdata/apiapia.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja.xcodeproj/project.xcworkspace/xcuserdata/apiapia.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/SkyNinja.xcodeproj/project.xcworkspace/xcuserdata/apiapia.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildLocationStyle
6 | UseAppPreferences
7 | CustomBuildLocationType
8 | RelativeToDerivedData
9 | DerivedDataLocationStyle
10 | Default
11 | EnabledFullIndexStoreVisibility
12 |
13 | IssueFilterStyle
14 | ShowActiveSchemeOnly
15 | LiveSourceIssuesEnabled
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/SkyNinja.xcodeproj/xcuserdata/apiapia.xcuserdatad/xcschemes/SkyNinja.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/SkyNinja.xcodeproj/xcuserdata/apiapia.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SkyNinja.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 21302A6A20C8066E0014029B
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SkyNinja/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/.DS_Store
--------------------------------------------------------------------------------
/SkyNinja/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SkyNinja
4 | //
5 | // Created by Chen on 2018/6/6.
6 | // Copyright © 2018 iFiero. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/.DS_Store
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "size": "20x20",
5 | "idiom": "iphone",
6 | "filename": "icon-20@2x.png",
7 | "scale": "2x"
8 | },
9 | {
10 | "size": "20x20",
11 | "idiom": "iphone",
12 | "filename": "icon-20@3x.png",
13 | "scale": "3x"
14 | },
15 | {
16 | "size": "29x29",
17 | "idiom": "iphone",
18 | "filename": "icon-29.png",
19 | "scale": "1x"
20 | },
21 | {
22 | "size": "29x29",
23 | "idiom": "iphone",
24 | "filename": "icon-29@2x.png",
25 | "scale": "2x"
26 | },
27 | {
28 | "size": "29x29",
29 | "idiom": "iphone",
30 | "filename": "icon-29@3x.png",
31 | "scale": "3x"
32 | },
33 | {
34 | "size": "40x40",
35 | "idiom": "iphone",
36 | "filename": "icon-40@2x.png",
37 | "scale": "2x"
38 | },
39 | {
40 | "size": "40x40",
41 | "idiom": "iphone",
42 | "filename": "icon-40@3x.png",
43 | "scale": "3x"
44 | },
45 | {
46 | "size": "57x57",
47 | "idiom": "iphone",
48 | "filename": "icon-57.png",
49 | "scale": "1x"
50 | },
51 | {
52 | "size": "57x57",
53 | "idiom": "iphone",
54 | "filename": "icon-57@2x.png",
55 | "scale": "2x"
56 | },
57 | {
58 | "size": "60x60",
59 | "idiom": "iphone",
60 | "filename": "icon-60@2x.png",
61 | "scale": "2x"
62 | },
63 | {
64 | "size": "60x60",
65 | "idiom": "iphone",
66 | "filename": "icon-60@3x.png",
67 | "scale": "3x"
68 | },
69 | {
70 | "size": "20x20",
71 | "idiom": "ipad",
72 | "filename": "icon-20-ipad.png",
73 | "scale": "1x"
74 | },
75 | {
76 | "size": "20x20",
77 | "idiom": "ipad",
78 | "filename": "icon-20@2x-ipad.png",
79 | "scale": "2x"
80 | },
81 | {
82 | "size": "29x29",
83 | "idiom": "ipad",
84 | "filename": "icon-29-ipad.png",
85 | "scale": "1x"
86 | },
87 | {
88 | "size": "29x29",
89 | "idiom": "ipad",
90 | "filename": "icon-29@2x-ipad.png",
91 | "scale": "2x"
92 | },
93 | {
94 | "size": "40x40",
95 | "idiom": "ipad",
96 | "filename": "icon-40.png",
97 | "scale": "1x"
98 | },
99 | {
100 | "size": "40x40",
101 | "idiom": "ipad",
102 | "filename": "icon-40@2x.png",
103 | "scale": "2x"
104 | },
105 | {
106 | "size": "50x50",
107 | "idiom": "ipad",
108 | "filename": "icon-50.png",
109 | "scale": "1x"
110 | },
111 | {
112 | "size": "50x50",
113 | "idiom": "ipad",
114 | "filename": "icon-50@2x.png",
115 | "scale": "2x"
116 | },
117 | {
118 | "size": "72x72",
119 | "idiom": "ipad",
120 | "filename": "icon-72.png",
121 | "scale": "1x"
122 | },
123 | {
124 | "size": "72x72",
125 | "idiom": "ipad",
126 | "filename": "icon-72@2x.png",
127 | "scale": "2x"
128 | },
129 | {
130 | "size": "76x76",
131 | "idiom": "ipad",
132 | "filename": "icon-76.png",
133 | "scale": "1x"
134 | },
135 | {
136 | "size": "76x76",
137 | "idiom": "ipad",
138 | "filename": "icon-76@2x.png",
139 | "scale": "2x"
140 | },
141 | {
142 | "size": "83.5x83.5",
143 | "idiom": "ipad",
144 | "filename": "icon-83.5@2x.png",
145 | "scale": "2x"
146 | },
147 | {
148 | "size": "1024x1024",
149 | "idiom": "ios-marketing",
150 | "filename": "icon-1024.png",
151 | "scale": "1x"
152 | }
153 | ],
154 | "info": {
155 | "version": 1,
156 | "author": "icon.wuruihong.com"
157 | }
158 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-1024.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-20-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-20-ipad.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-20@2x-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-20@2x-ipad.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-29-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-29-ipad.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-29.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-29@2x-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-29@2x-ipad.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-40.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-50.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-50@2x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-57.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-57@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-57@2x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-72.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-76.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/Learning.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Learning.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/Learning.imageset/Learning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/Learning.imageset/Learning.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/Star.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Star.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/Star.imageset/Star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/Star.imageset/Star.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/bg.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bg.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/bg.imageset/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/bg.imageset/bg.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/bomb.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bomb.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/bomb.imageset/bomb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/bomb.imageset/bomb.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/coin.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "coin.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/coin.imageset/coin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/coin.imageset/coin.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/ground.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "ground.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/ground.imageset/ground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/ground.imageset/ground.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/ifiero-logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "ifiero-logo.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/ifiero-logo.imageset/ifiero-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/ifiero-logo.imageset/ifiero-logo.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/play.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "play.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/play.imageset/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/play.imageset/play.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/t10001.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "t10001.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/t10001.imageset/t10001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/t10001.imageset/t10001.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/t1Mask.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "t1Mask.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/t1Mask.imageset/t1Mask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/t1Mask.imageset/t1Mask.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/tapToPlay.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "tapToPlay.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/tapToPlay.imageset/tapToPlay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/tapToPlay.imageset/tapToPlay.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/top.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "top.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/top.imageset/top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/top.imageset/top.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/tree.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "cloud.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/tree.imageset/cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/tree.imageset/cloud.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/youlose.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "youlose.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/youlose.imageset/youlose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/youlose.imageset/youlose.png
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/youwon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "youwon.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 | }
--------------------------------------------------------------------------------
/SkyNinja/Assets.xcassets/youwon.imageset/youwon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Assets.xcassets/youwon.imageset/youwon.png
--------------------------------------------------------------------------------
/SkyNinja/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
33 |
39 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/SkyNinja/Base.lproj/Main.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 |
--------------------------------------------------------------------------------
/SkyNinja/Constant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PhysicsCategory.swift
3 | // SkyNinja
4 | //
5 | // Created by Chen on 2018/6/11.
6 | // Copyright © 2018 iFiero. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SpriteKit
11 | import CoreGraphics
12 |
13 | public let SCENE_WIDTH:CGFloat = 2048
14 | public let SCENE_HEIGHT:CGFloat = 1536
15 | public let SCENE_NUMBERS:CGFloat = 2 // 二个场景 HardCode
16 | public let CAMERA_MOVE_XPOS:CGFloat = 18 /// 相机X-Axis移动的尺寸;
17 |
18 | // 物理标识;
19 | struct PhysicsCategory {
20 |
21 | static let None: UInt32 = 0x1 << 1
22 | static let Player: UInt32 = 0x1 << 2
23 | static let Bomb: UInt32 = 0x1 << 3
24 | static let Coin:UInt32 = 0x1 << 4
25 | static let GroudLine: UInt32 = 0x1 << 5
26 | static let SkyLine: UInt32 = 0x1 << 6
27 | static let MiddleLine:UInt32 = 0x1 << 7 // 中间物理碰撞线
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/SkyNinja/Elements Class/LineNode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MiddleNodeClass.swift
3 | // SkyNinja
4 | //
5 | // Created by Chen on 2018/6/11.
6 | // Copyright © 2018 iFiero. All rights reserved.
7 | //
8 |
9 | import SpriteKit
10 |
11 | class LineNode :SKNode {
12 |
13 | func initLine(size:CGSize,yPos:CGFloat){ // 传入scene的尺寸
14 | /// let yPos : CGFloat = size.height * 0.65
15 | let startPoint = CGPoint(x: 0, y: yPos)
16 | let endPoint = CGPoint(x: size.width * SCENE_NUMBERS, y: yPos)
17 | self.name = "Line"
18 | physicsBody = SKPhysicsBody(edgeFrom: startPoint, to: endPoint)
19 | physicsBody?.affectedByGravity = false
20 | physicsBody?.categoryBitMask = PhysicsCategory.MiddleLine
21 | physicsBody?.contactTestBitMask = PhysicsCategory.Player
22 | physicsBody?.collisionBitMask = PhysicsCategory.None /// 不会弹开
23 | }
24 |
25 | func initSkyLine(size:CGSize,yPos:CGFloat){ // 传入scene的尺寸
26 | /// let yPos : CGFloat = size.height * 0.65
27 | let startPoint = CGPoint(x: 0, y: yPos)
28 | let endPoint = CGPoint(x: size.width * SCENE_NUMBERS, y: yPos)
29 | self.name = "Line"
30 | physicsBody = SKPhysicsBody(edgeFrom: startPoint, to: endPoint)
31 | physicsBody?.affectedByGravity = false
32 | physicsBody?.categoryBitMask = PhysicsCategory.SkyLine
33 | physicsBody?.contactTestBitMask = PhysicsCategory.Player
34 | physicsBody?.collisionBitMask = PhysicsCategory.None /// 不会弹开
35 | }
36 |
37 | func initGroundLine(size:CGSize,yPos:CGFloat){ // 传入scene的尺寸
38 | /// let yPos : CGFloat = size.height * 0.65
39 | let startPoint = CGPoint(x: 0, y: yPos)
40 | let endPoint = CGPoint(x: size.width * SCENE_NUMBERS, y: yPos)
41 | self.name = "Line"
42 | physicsBody = SKPhysicsBody(edgeFrom: startPoint, to: endPoint)
43 | physicsBody?.affectedByGravity = false
44 | physicsBody?.categoryBitMask = PhysicsCategory.GroudLine
45 | physicsBody?.contactTestBitMask = PhysicsCategory.Player
46 | physicsBody?.collisionBitMask = PhysicsCategory.None /// 不会弹开
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/SkyNinja/Elements Class/PlayerNodeClass.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlayerNode.swift
3 | // SkyNinja
4 | //
5 | // Created by Chen on 2018/6/11.
6 | // Copyright © 2018 iFiero. All rights reserved.
7 | //
8 |
9 |
10 | import SpriteKit
11 |
12 | class PlayerNodeClass:SKSpriteNode {
13 |
14 | private var playerTextureAtlas = SKTextureAtlas()
15 | private var playerTextures = [SKTexture]()
16 | private var playerUpDown = false
17 |
18 | // MARK:-玩家
19 | func initPlayer(){
20 | /// Ninja.atlas名称 (位于目录Resources->Images)
21 | playerTextureAtlas = SKTextureAtlas(named: "Ninja")
22 | /// 把atlas里的图片append到PlayerTextures数组内
23 | for i in 1...playerTextureAtlas.textureNames.count {
24 | let imageName = "t1000\(i)"
25 | playerTextures.append(SKTexture(imageNamed: imageName))
26 | }
27 | /// 节点的物理特性
28 | /// 1.调用rectangleOf矩形物理外框
29 | /// self.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: self.size.width, height: self.size.height))
30 | ///2.调用物理体本身的图片 因为头重脚轻 上升到顶部时导致站不稳;
31 | // self.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "t10001"), size:CGSize(width: SKTexture(imageNamed: "t10001").size().width * 0.7, height: SKTexture(imageNamed: "t10001").size().height * 0.7))
32 | ///3.精确定制物理体t1Mask
33 | let playerMask = SKTexture(imageNamed: "t1Mask")
34 | self.physicsBody = SKPhysicsBody(texture: playerMask, size: CGSize(width: playerMask.size().width * 0.7, height: playerMask.size().height * 0.7)) /// 0.7 的意思是缩小0.7倍
35 | self.physicsBody?.restitution = 0 // bounciness物体落下时反弹跳力不会消减
36 | self.physicsBody?.categoryBitMask = PhysicsCategory.Player
37 | /// 和谁发生碰撞并发出通知 didBegin 会监测到碰撞通知
38 | self.physicsBody?.contactTestBitMask = PhysicsCategory.Bomb | PhysicsCategory.Coin
39 | /// 相撞后会相互作用吗?比如站立、弹开
40 | self.physicsBody?.collisionBitMask = PhysicsCategory.SkyLine | PhysicsCategory.GroudLine
41 | self.physicsBody?.isDynamic = true
42 |
43 | }
44 |
45 | func startPlayer(){
46 | /// 执行textures动画
47 | let playerAnimation = SKAction.animate(with: playerTextures, timePerFrame: 0.1)
48 | /// repeatForever执行
49 | let repeatAction = SKAction.repeatForever(playerAnimation)
50 | self.run(repeatAction, withKey: "jogging")
51 |
52 |
53 | }
54 | // MARK: - 停止动画
55 | func stopPlayer(){
56 | self.removeAction(forKey: "jogging")
57 | }
58 |
59 | // MARK: - 移动玩家 - 和Camera的步调一致
60 | func movePlayer(){
61 | self.position.x += CAMERA_MOVE_XPOS
62 | }
63 |
64 | // MARK: - 反转Player
65 | func reversePlayer(){
66 | // print(self.position.y,(scene?.size.height)! * 0.4)
67 |
68 | if self.position.y > (scene?.size.height)! * 0.6 {
69 | self.yScale = -1 * 0.7
70 | }
71 |
72 | if self.position.y < (scene?.size.height)! * 0.4 {
73 | self.yScale = 1 * 0.7
74 | }
75 |
76 |
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/SkyNinja/Elements Class/SpawnElements.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SpawnElements.swift
3 | // SkyNinja
4 | //
5 | // Created by Chen on 2018/6/12.
6 | // Copyright © 2018 iFiero. All rights reserved.
7 | //
8 |
9 | import SpriteKit
10 | import CoreGraphics
11 |
12 | /// 生成class 不用继承任何 SKSpriteNode
13 | class SpawnElements {
14 |
15 | private let minY = CGFloat(360) /// 地板
16 | private let maxY = CGFloat(1100) /// 天空的底线
17 | private var randomYPos :CGFloat = 0.0
18 |
19 | // MARK:- 生成Bomb+随机移动Bomb
20 | func spawnBomb(camera:SKCameraNode,scene:SKScene) -> SKSpriteNode{
21 |
22 | let item :SKSpriteNode!
23 | item = SKSpriteNode(imageNamed: "bomb") /// Assests.xcassets存放的图片名称,非场景中的Sprite的Node名称;
24 | item.name = "bomb"
25 | item.setScale(0.6) /// 原始图片太大了
26 | /// 新建节点
27 | let trailNode = SKNode()
28 | trailNode.zPosition = 4 /// 此处的位置要 < Bomb的Z-Axis轴
29 | scene.addChild(trailNode)
30 | /// 新建粒子效果
31 | let emitterNode = SKEmitterNode(fileNamed: "Trail")!
32 | emitterNode.targetNode = trailNode
33 | item.addChild(emitterNode)
34 |
35 | /// 物理引擎 SKPhysicsBody(rectangleOf: item.size)
36 | let bombTexture = SKTexture(imageNamed: "bomb")
37 | item.physicsBody = SKPhysicsBody(texture: bombTexture, size: CGSize(width: bombTexture.size().width * 0.7 * 0.8 , height: bombTexture.size().height * 0.7 * 0.8)) /// 大小缩小 0.7 * 0.8(透明区域)
38 | item.physicsBody?.affectedByGravity = false
39 | item.physicsBody?.allowsRotation = false
40 | item.physicsBody?.isDynamic = false /// 碰撞后物理体不进行动态反馈
41 | item.physicsBody?.categoryBitMask = PhysicsCategory.Bomb
42 | item.physicsBody?.contactTestBitMask = PhysicsCategory.Player
43 | item.physicsBody?.collisionBitMask = PhysicsCategory.None
44 |
45 | /// 随机位置
46 | randomYPos = CGFloat.random(minY, max: maxY) /// 扩展的CGFloat函数
47 | item.zPosition = 5
48 | item.position.x = camera.position.x + SCENE_WIDTH * 0.7 /// 位于Camera.position的位置右侧
49 | item.position.y = randomYPos
50 |
51 | /// 从右往左的随机速度
52 | let duration = CGFloat.random(CGFloat(6.0), max: CGFloat(12.0))
53 | let moveToLeft = SKAction.move(to: CGPoint(x: CGFloat(-item.size.width), y: randomYPos), duration: TimeInterval(duration))
54 | let remove = SKAction.removeFromParent()
55 | item.run(SKAction.sequence([moveToLeft,remove,
56 | SKAction.run {
57 | trailNode.removeFromParent() /// 记得也把emitter节点移除;
58 | }
59 | ])) /// 移出屏幕了;
60 |
61 | return item
62 | }
63 |
64 | // MARK:- 生成随机 coin
65 | func spawnCoin(camera:SKCameraNode) -> SKSpriteNode {
66 |
67 | let item:SKSpriteNode
68 | item = SKSpriteNode(imageNamed: "coin")
69 | item.name = "coin"
70 | item.setScale(0.7)
71 | /// 物理引擎
72 | item.physicsBody = SKPhysicsBody(circleOfRadius: item.size.width / 3)
73 | item.physicsBody?.affectedByGravity = false
74 | item.physicsBody?.categoryBitMask = PhysicsCategory.Coin
75 | item.physicsBody?.contactTestBitMask = PhysicsCategory.Player
76 | item.physicsBody?.collisionBitMask = PhysicsCategory.None
77 | /// 随机yPos位置
78 | randomYPos = CGFloat.random(minY, max: maxY) /// 扩展的CGFloat函数
79 | /// 随机xPos位置
80 | let minX = SCENE_WIDTH + SCENE_WIDTH * 0.1
81 | let maxX = SCENE_WIDTH + SCENE_WIDTH * 1.2
82 | let randomX = CGFloat.random(minX, max: maxX)
83 |
84 | item.zPosition = 5
85 | item.position.x = camera.position.x + randomX /// 位于Camera.position的位置右侧
86 | item.position.y = randomYPos
87 |
88 | /// item上下浮动
89 | let duration:CGFloat = CGFloat.random(1.5, max: 3.0)
90 | let moveUp = SKAction.moveBy(x: 0, y: 50, duration: TimeInterval(duration))
91 | moveUp.timingMode = .easeInEaseOut
92 | let moveDown = moveUp.reversed()
93 | let sequence = SKAction.sequence([moveUp,moveDown])
94 | let repeatWobble = SKAction.repeatForever(sequence)
95 | item.run(repeatWobble, withKey: "Wobble")
96 |
97 | return item
98 | }
99 |
100 | }
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/SkyNinja/GameScene.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/GameScene.sks
--------------------------------------------------------------------------------
/SkyNinja/GameScene.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GameScene.swift
3 | // SkyNinja
4 | /*
5 | * *** 游戏元素使用条款及注意事项 ***
6 | *
7 | * 游戏中的所有元素全部由iFIERO所原创(除注明引用之外),包括人物、音乐、场景等;
8 | * 创作的初衷就是让更多的游戏爱好者可以在开发游戏中获得自豪感 -- 让手机游戏开发变得简单;
9 | * 秉着开源分享的原则,iFIERO发布的游戏都尽可能的易懂实用,并开放所有源码;
10 | * 任何使用者都可以使用游戏中的代码块,也可以进行拷贝、修改、更新、升级,无须再经过iFIERO的同意;
11 | * 但这并不表示可以任意复制、拆分其中的游戏元素:
12 | * 用于[商业目的]而不注明出处;
13 | * 用于[任何教学]而不注明出处;
14 | * 用于[游戏上架]而不注明出处;
15 | * 另外,iFIERO有商用授权游戏元素,获得iFIERO官方授权后,即无任何限制;
16 | * 请尊重帮助过你的iFIERO的知识产权,非常感谢;
17 | *
18 | * Created by VANGO杨 && ANDREW陈
19 | * Copyright © 2018 iFiero. All rights reserved.
20 | * www.iFIERO.com
21 | * iFIERO -- 让手机游戏开发变得简单
22 | *
23 | * SkyNinja 天猪之城 在此游戏中您将获得如下技能:
24 | *
25 | * 1、LaunchScreen 学习如何设置游戏启动画面
26 | * 2、Scene 学习如何切换游戏的游戏场景
27 | * 3、Scene Edit 学习直接使用可见即所得操作编辑游戏场景
28 | * 4、Random 利用可复用的随机函数生成Enemy
29 | * 5、SpriteNode class 学习建立独立的class精灵并引入场景scene
30 | * 6、Collision 学习有节点与节点之间的碰撞的原理及处理方法
31 | * 7、Animation&Atlas 学习如何导入动画帧及何为Atlas
32 | * 8、Camera 使用Camera实现endless背景滚动
33 | * 9、Grarity 学习如何点击屏幕时反转重力
34 | * 10、StateMachine GameplayKit 运用之场景切换;(**** 中级技能)
35 | * 11、Partilces 学习如何做特效及把特效发生碰撞时移出场景;(**** 中级技能)
36 | *
37 | */
38 |
39 | import SpriteKit
40 | import GameplayKit
41 |
42 | class GameScene: SKScene ,SKPhysicsContactDelegate{
43 |
44 | var moveAllowed = false /// 场景是否可以移动了;
45 |
46 | //MARK: - StateMachine 场景中各个舞台State
47 | lazy var stateMachine:GKStateMachine = GKStateMachine(states: [
48 | WaitingState(scene: self), //self 为 GameScene ,把GameScene专入State
49 | PlayState(scene: self),
50 | GameOverState(scene: self)
51 | ])
52 |
53 | //MARK: - 场景中的所有SpriteNode
54 | /*
55 | * 1.调用 Elements Class 的节点,须在GameScene的把节点的Custom Class设为PlayerNode
56 | * 2.Module 设为项目名称 SkyNinja
57 | * 3.为何要设置独立的class精灵,可以为GameScene减少代码,并有利于代码的复用;
58 | */
59 | var playerNode:PlayerNodeClass!
60 | var learnTemp:SKSpriteNode!
61 | var coinTempNode:SKSpriteNode!
62 | var bombTempNode:SKSpriteNode!
63 | var mainCamera:SKCameraNode!
64 | var groundNode:SKSpriteNode! /// 地面
65 | var skyNode:SKSpriteNode! /// 天空
66 | var spawnElements = SpawnElements() /// 生成节点工具 特别注意,这里非 spawnElements = SpawnElements!
67 |
68 | private var dt:TimeInterval = 0 /// 每一frame的时间差
69 | private var lastUpdateTimeInterval:TimeInterval = 0
70 |
71 | override func didMove(to view: SKView) {
72 | super.didMove(to: view)
73 | self.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8) /// 物理世界的重力
74 | self.physicsWorld.contactDelegate = self /// 碰撞代理
75 |
76 | initCamera() /// Camera
77 | initBgMusic() /// 背景音乐
78 | initPlayer() /// 初始化玩家
79 | initCoinBomb() /// 临时的Coin+Bomb
80 | initSkyGroundLine() // 建立物理天空+地面
81 | stateMachine.enter(WaitingState.self) /// 初始化以上的各个精灵SpriteNode后,再进入WaitingState 场景舞台State
82 | }
83 | //MARK: - 加入Camera
84 | func initCamera(){
85 | mainCamera = childNode(withName: "MainCamera") as! SKCameraNode
86 | }
87 | //MARK: - 移动Camera
88 | func moveCamera(){
89 | self.mainCamera.position.x += CAMERA_MOVE_XPOS ///向右移动
90 | }
91 | //MARK: - 停止Camera
92 | func stopCamera(){
93 | self.mainCamera.removeAllActions()
94 | }
95 | // MARK:-初始化玩家
96 | func initPlayer(){
97 |
98 | playerNode = childNode(withName: "Player") as! PlayerNodeClass
99 | playerNode.physicsBody?.affectedByGravity = true
100 | playerNode.initPlayer()
101 | }
102 | // MARK:-背景音乐
103 | func initBgMusic(){
104 |
105 | let bgMusic = SKAudioNode(fileNamed: "background.mp3")
106 | bgMusic.autoplayLooped = true
107 | addChild(bgMusic)
108 | }
109 |
110 | func initCoinBomb(){
111 | coinTempNode = childNode(withName: "CoinTemp") as! SKSpriteNode
112 | bombTempNode = childNode(withName: "BombTemp") as! SKSpriteNode
113 | learnTemp = childNode(withName: "learnTemp") as! SKSpriteNode
114 | }
115 | //MARK: - 物理线
116 | func initSkyGroundLine(){
117 |
118 | skyNode = childNode(withName: "Sky") as! SKSpriteNode
119 | let sykLine = LineNode() /// 生成新的节点 比如 let newNode = SKNode()
120 | sykLine.initSkyLine(size: size, yPos: skyNode.position.y + 10)
121 | addChild(sykLine)
122 |
123 |
124 | groundNode = childNode(withName: "Ground") as! SKSpriteNode
125 | let groundLine = LineNode()
126 | groundLine.initGroundLine(size: size, yPos: groundNode.position.y + groundNode.size.height - 10)
127 | addChild(groundLine)
128 |
129 | }
130 |
131 | // MARK: - 反转物理世界;
132 | func reverseGravity(){
133 | physicsWorld.gravity *= -1
134 | }
135 |
136 | // MARK: - 根据 camera.position.x 移动所有页面元素;
137 | ///因为节点anchorPoint为(0,0),且相机的初始位置为 1024,所以要把相机的位置扣除1024 即(camera.position.x - self.size.width / 2)
138 | func moveSprites(camera:SKCameraNode){
139 | /// 所有的天空精灵
140 | enumerateChildNodes(withName: "Sky") { (node, error) in
141 | if node.position.x + self.size.width < (camera.position.x - self.size.width / 2) {
142 | node.position.x += self.size.width * SCENE_NUMBERS
143 | }
144 | }
145 | /// 所有的地面精灵;
146 | enumerateChildNodes(withName: "Ground") { (node, error) in
147 | if node.position.x + self.size.width < (camera.position.x - self.size.width / 2 ) {
148 | node.position.x += self.size.width * SCENE_NUMBERS
149 | }
150 | /// print("所有的地面精灵",node.position.x,(camera.position.x - self.size.width / 2 ))
151 | }
152 | /// 所有线和Camera同步
153 | enumerateChildNodes(withName: "Line") { (node, error) in
154 | // let node = node as! SKNode
155 | node.position.x += CAMERA_MOVE_XPOS
156 | if node.position.x < -self.size.width {
157 | node.position.x += self.size.width * SCENE_NUMBERS
158 | }
159 | }
160 | /// 所有树
161 | /// 树为何不:(camera.position.x - self.size.width / 2 ),请注意树的 anchorPoint(0.5,0.5)
162 | enumerateChildNodes(withName: "Tree") { (node, error) in
163 | if node.position.x + self.size.width < (camera.position.x ) {
164 | node.position.x += self.size.width * SCENE_NUMBERS
165 | }
166 | }
167 | /// 所有背景
168 | enumerateChildNodes(withName: "Bg") { (node, error) in
169 |
170 | if node.position.x + self.size.width < (camera.position.x - self.size.width / 2 ) {
171 | node.position.x += self.size.width * SCENE_NUMBERS
172 | }
173 | }
174 | }
175 | // MARK: - 生成节点工具 class
176 | @objc func spawnCoins(){
177 | /// print(spawnElements.spawnCoin(camera: mainCamera))
178 | if moveAllowed {
179 | self.addChild(spawnElements.spawnCoin(camera: mainCamera)) /// 传入主相机位置
180 | }
181 |
182 | }
183 |
184 | @objc func spawnBombs(){
185 | if moveAllowed {
186 | addChild(spawnElements.spawnBomb(camera: mainCamera,scene: self)) /// 传入主相机位置
187 | }
188 | }
189 |
190 | @objc func removeCoins(){
191 | enumerateChildNodes(withName: "coin") { (node, error) in
192 | if node.position.x < self.mainCamera.position.x - self.size.width {
193 | /// print("移除coin")
194 | node.removeFromParent()
195 | }
196 | }
197 | }
198 | // MARK: - 不再生成了;
199 | func stopSpawning(){
200 |
201 | playerNode.removeAction(forKey: "jogging") /// 移除人物的运动;
202 |
203 | enumerateChildNodes(withName: "coin") { (node, error) in
204 | node.removeAllActions()
205 | }
206 | enumerateChildNodes(withName: "bomb") { (node, error) in
207 | node.removeAllActions()
208 | }
209 | }
210 |
211 | //MARK: - 重新开始游戏;
212 | func restartGame(){
213 |
214 | let newScene = GameScene(fileNamed: "GameScene")!
215 | newScene.size = CGSize(width: SCENE_WIDTH, height: SCENE_HEIGHT)
216 | newScene.anchorPoint = CGPoint(x: 0, y: 0)
217 | newScene.scaleMode = .aspectFill
218 | let transition = SKTransition.flipHorizontal(withDuration: 0.5)
219 | view?.presentScene(newScene, transition:transition)
220 | }
221 |
222 | // MARK: - 监测屏幕点击事件
223 | override func touchesBegan(_ touches: Set, with event: UIEvent?) {
224 | guard let touch = touches.first else {
225 | return
226 | }
227 | let touchLocation = touch.location(in: self) ///获得点击的位置
228 | /// 判断目前的GameScene场景舞台是哪个state
229 | switch stateMachine.currentState {
230 | case is WaitingState:
231 | /// 获得按钮的点击位置
232 | guard let body = physicsWorld.body(at: touchLocation) else {
233 | return
234 | }
235 | /// 判断是否是点击了PlayButton
236 | guard let playButton = body.node?.childNode(withName: "PlayButton") as? SKSpriteNode else {
237 | return
238 | }
239 | /// 如果点击位置是在PlayButton
240 | if (playButton.contains(touchLocation)){
241 | playButton.isHidden = true
242 | stateMachine.enter(PlayState.self) /// 进入开始游戏;
243 | }
244 |
245 | guard let learnTempNode = body.node?.childNode(withName: "learnTemp") as? SKSpriteNode else {
246 | return
247 | }
248 | if (learnTempNode.contains(touchLocation)){
249 | UIApplication.shared.open(URL(string: "http://www.iFIERO.com")!, options: [:], completionHandler: { (error) in
250 | print("jump to http://www.iFiero.com")
251 | })
252 | }
253 |
254 | case is PlayState:
255 | reverseGravity() /// 反转物理世界;
256 |
257 | case is GameOverState:
258 |
259 | guard let body = physicsWorld.body(at: touchLocation) else {
260 | return
261 | }
262 | // TapToPlay按钮;
263 | if let tapToPlay = body.node?.childNode(withName: "tapToPlay"){
264 |
265 | if tapToPlay.contains(touchLocation){
266 | print("重新开始游戏!")
267 | restartGame()
268 | }
269 | }
270 | default:
271 | break;
272 | }
273 | }
274 | // MARK: - 监测碰撞
275 | func didBegin(_ contact: SKPhysicsContact) {
276 |
277 | let bodyA:SKPhysicsBody
278 | let bodyB:SKPhysicsBody
279 | if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
280 | bodyA = contact.bodyA
281 | bodyB = contact.bodyB
282 | }else{
283 | bodyA = contact.bodyB
284 | bodyB = contact.bodyA
285 | }
286 | ///检测碰到中间线
287 | /*
288 | if bodyA.categoryBitMask == PhysicsCategory.Player && bodyB.categoryBitMask == PhysicsCategory.MiddleLine {
289 | /// print("碰到屏幕线人物反转")
290 | playerNode.reversePlayer()
291 | }
292 | */
293 |
294 | ///检测碰到coin
295 | if bodyA.categoryBitMask == PhysicsCategory.Player && bodyB.categoryBitMask == PhysicsCategory.Coin {
296 | /// print("碰到屏幕线人物反转")
297 | let coinAction = SKAction.playSoundFileNamed("coin.wav", waitForCompletion: false)
298 | run(coinAction)
299 | bodyB.categoryBitMask = PhysicsCategory.None /// 去除双响;
300 |
301 | /// 加入收集coin特效 position位置;
302 | let coinEmitter = SKEmitterNode(fileNamed: "CollectNormal")
303 | coinEmitter?.position = (bodyB.node?.position)!
304 | coinEmitter?.zPosition = 3
305 | self.addChild(coinEmitter!)
306 | //移除coin
307 | bodyB.node?.run(SKAction.sequence([
308 | SKAction.scale(to: 0.01, duration: 0.05),
309 | SKAction.removeFromParent()]))
310 | //移除coin特效节点
311 | coinEmitter?.run(SKAction.sequence([
312 | SKAction.wait(forDuration: TimeInterval(0.7)),
313 | SKAction.removeFromParent(),
314 |
315 | ]))
316 | }
317 |
318 | /// 检测碰到Bomb
319 | if bodyA.categoryBitMask == PhysicsCategory.Player && bodyB.categoryBitMask == PhysicsCategory.Bomb {
320 | /// 播放音乐
321 | /// let bombAction = SKAction.playSoundFileNamed("ninjaHit.wav", waitForCompletion: false)
322 | /// 无法播放音乐 在Build Phases -> Copy Bundle Resources 导入即可;
323 | let bombAction = SKAction.playSoundFileNamed("death.caf", waitForCompletion: false)
324 | run(bombAction)
325 | bodyA.categoryBitMask = PhysicsCategory.None /// 防止一直和Bomb碰撞 产生多重声音;
326 | /// 加入death 特效;
327 | let deathNode = SKNode()
328 | deathNode.position = (bodyA.node?.position)!
329 | self.addChild(deathNode)
330 |
331 | let deathEmitter = SKEmitterNode(fileNamed: "death")
332 | deathEmitter?.targetNode = deathNode
333 | deathNode.addChild(deathEmitter!)
334 | bodyA.node?.removeFromParent()
335 | deathEmitter?.run(SKAction.sequence([
336 | SKAction.wait(forDuration: TimeInterval(2.0)),
337 | SKAction.removeFromParent(),
338 | ]))
339 | bodyB.node?.removeFromParent() /// 移除Bomb
340 |
341 | stateMachine.enter(GameOverState.self)
342 | }
343 | }
344 | // MARK: - 时时更新update
345 | override func update(_ currentTime: TimeInterval) {
346 |
347 | /// 获取时间差
348 | if lastUpdateTimeInterval == 0 {
349 | lastUpdateTimeInterval = currentTime
350 | }
351 | dt = currentTime - lastUpdateTimeInterval
352 | lastUpdateTimeInterval = currentTime
353 |
354 | stateMachine.update(deltaTime: dt) /// 把update传进各个State里;
355 | }
356 | }
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
--------------------------------------------------------------------------------
/SkyNinja/GameStates/GameOverState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GameOverState.swift
3 | // SkyNinja
4 | //
5 | // Copyright © 2018 iFiero. All rights reserved.
6 | //
7 |
8 | import SpriteKit
9 | import GameplayKit
10 |
11 | class GameOverState:GKState {
12 |
13 | unowned let scene:GameScene
14 | init(scene:SKScene){
15 | self.scene = scene as! GameScene
16 | super.init()
17 | }
18 |
19 | override func didEnter(from previousState: GKState?) {
20 | scene.moveAllowed = false
21 | scene.stopSpawning()
22 | print("GameOver State 游戏结束")
23 | initGameOver()
24 |
25 | }
26 |
27 | func initGameOver(){
28 | ///CAMERA有移动了;
29 | let xPos = scene.mainCamera.position.x
30 | let yPos = scene.mainCamera.position.y
31 |
32 | let loseNode = SKSpriteNode(imageNamed: "youlose")
33 | loseNode.setScale(0.7)
34 | loseNode.zPosition = 6
35 | loseNode.position = CGPoint(x: xPos, y: yPos + 60)
36 | scene.addChild(loseNode)
37 |
38 | let tapNode = SKSpriteNode(imageNamed: "tapToPlay")
39 | tapNode.name = "tapToPlay"
40 | tapNode.position = CGPoint(x: xPos, y: yPos - 60)
41 | tapNode.setScale(0.7)
42 | tapNode.zPosition = 6
43 | scene.addChild(tapNode)
44 |
45 | }
46 |
47 | override func isValidNextState(_ stateClass: AnyClass) -> Bool {
48 | return stateClass is PlayState.Type
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/SkyNinja/GameStates/PlayState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlayState.swift
3 | // SkyNinja
4 | // Copyright © 2018 iFiero. All rights reserved.
5 | //
6 |
7 | import SpriteKit
8 | import GameplayKit
9 |
10 | class PlayState:GKState {
11 | unowned let scene:GameScene
12 |
13 | init(scene:SKScene){
14 | self.scene = scene as! GameScene
15 | super.init()
16 | print("Play State")
17 | }
18 |
19 | /// 前一State是WaitState
20 | override func didEnter(from previousState: GKState?) {
21 | scene.moveAllowed = true /// 场景可以移动了
22 | scene.bombTempNode.isHidden = true
23 | scene.coinTempNode.isHidden = true
24 | scene.learnTemp.isHidden = true
25 | scene.playerNode.startPlayer()
26 |
27 | initTopBottomLineNode() /// 加入上线二条碰撞线
28 | // 用Timer每隔1s调用 spawnBomb 注意此处是在State里,则target要为scene.self而不是self
29 | Timer.scheduledTimer(timeInterval: TimeInterval(3.0), target: scene.self, selector: #selector(scene.spawnBombs), userInfo: nil, repeats: true)
30 |
31 | Timer.scheduledTimer(timeInterval: TimeInterval(2.0), target: scene.self, selector: #selector(scene.spawnCoins), userInfo: nil, repeats: true)
32 |
33 |
34 | }
35 | // MARK:- 加入上线二条碰撞线
36 | func initTopBottomLineNode(){
37 |
38 | // let topLine = LineNode()
39 | // topLine.initLine(size: scene.size, yPos: scene.size.height * 0.7)
40 | // scene.addChild(topLine)
41 | //
42 | // let bottomLine = LineNode()
43 | // bottomLine.initLine(size: scene.size, yPos: scene.size.height * 0.3)
44 | // scene.addChild(bottomLine)
45 |
46 | }
47 | /// 下一State是GameOver
48 | override func isValidNextState(_ stateClass: AnyClass) -> Bool {
49 | return stateClass is GameOverState.Type
50 | }
51 | /// update
52 |
53 | override func update(deltaTime seconds: TimeInterval) {
54 |
55 | if scene.moveAllowed {
56 | scene.moveCamera() /// 移动camera
57 | scene.playerNode.movePlayer() /// 移动玩家
58 | scene.moveSprites(camera: scene.mainCamera!) /// 移动天空及地面;
59 | scene.playerNode.reversePlayer()
60 | }else {
61 | scene.stopCamera() /// 停止camera
62 | }
63 |
64 | scene.removeCoins()
65 |
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/SkyNinja/GameStates/WaitingState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WaitingState.swift
3 | // SkyNinja
4 | // Copyright © 2018 iFiero. All rights reserved.
5 | //
6 |
7 | import SpriteKit
8 | import GameplayKit
9 |
10 | class WaitingState:GKState {
11 |
12 | unowned let scene:GameScene
13 | var playButton:SKSpriteNode!
14 |
15 | init(scene:SKScene){
16 | self.scene = scene as! GameScene
17 | super.init()
18 | print("Waiting State")
19 | }
20 | //MARK: - 初始化PlayButton,但获得点击事件touchesBegan是在GameScene中进行判断;
21 | func initPlayButton() {
22 | /// 取得playButton节点
23 | playButton = scene.childNode(withName: "PlayButton") as! SKSpriteNode
24 | /// 播放按钮的动画;
25 | let zoomOut = SKAction.scale(by: 0.8, duration: 0.75)
26 | zoomOut.timingMode = .easeInEaseOut
27 | let zoomIn = zoomOut.reversed()
28 | zoomIn.timingMode = .easeInEaseOut
29 | /// 播放顺序
30 | let sequence = SKAction.sequence([zoomOut,zoomIn])
31 | let repeatAction = SKAction.repeatForever(sequence)
32 | /// 执行Action
33 | playButton.run(repeatAction)
34 |
35 | }
36 |
37 | override func didEnter(from previousState: GKState?) {
38 | scene.moveAllowed = false /// 初始进入WaitState人物+场景是不可以运动的;
39 | scene.coinTempNode.isHidden = false
40 | scene.bombTempNode.isHidden = false
41 | scene.learnTemp.isHidden = false
42 | initPlayButton()
43 | }
44 | // 正确无误 进入一下个State PlayState
45 | override func isValidNextState(_ stateClass: AnyClass) -> Bool {
46 | return stateClass is PlayState.Type
47 | }
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/SkyNinja/GameViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GameViewController.swift
3 | // SkyNinja
4 | /*
5 | * *** 游戏元素使用条款及注意事项 ***
6 | *
7 | * 游戏中的所有元素全部由iFIERO所原创(除注明引用之外),包括人物、音乐、场景等;
8 | * 创作的初衷就是让更多的游戏爱好者可以在开发游戏中获得自豪感 -- 让手机游戏开发变得简单;
9 | * 秉着开源分享的原则,iFIERO发布的游戏都尽可能的易懂实用,并开放所有源码;
10 | * 任何使用者都可以使用游戏中的代码块,也可以进行拷贝、修改、更新、升级,无须再经过iFIERO的同意;
11 | * 但这并不表示可以任意复制、拆分其中的游戏元素:
12 | * 用于[商业目的]而不注明出处;
13 | * 用于[任何教学]而不注明出处;
14 | * 用于[游戏上架]而不注明出处;
15 | * 另外,iFIERO有商用授权游戏元素,获得iFIERO官方授权后,即无任何限制;
16 | * 请尊重帮助过你的iFIERO的知识产权,非常感谢;
17 | *
18 | * Created by VANGO杨 && ANDREW陈
19 | * Copyright © 2018 iFiero. All rights reserved.
20 | * www.iFIERO.com
21 | * iFIERO -- 让手机游戏开发变得简单
22 | *
23 | * SkyNinja 天猪之城 在此游戏中您将获得如下技能:
24 | *
25 | * 1、LaunchScreen 学习如何设置游戏启动画面
26 | * 2、Scene 学习如何切换游戏的游戏场景
27 | * 3、Scene Edit 学习直接使用可见即所得操作编辑游戏场景
28 | * 4、Random 利用可复用的随机函数生成Enemy
29 | * 5、SpriteNode class 学习建立独立的class精灵并引入场景scene
30 | * 6、Collision 学习有节点与节点之间的碰撞的原理及处理方法
31 | * 7、Animation&Atlas 学习如何导入动画帧及何为Atlas
32 | * 8、Camera 使用Camera实现endless背景滚动
33 | * 9、Grarity 学习如何点击屏幕时反转重力
34 | * 10、StateMachine GameplayKit 运用之场景切换;(**** 中级技能)
35 | * 11、Partilces 学习如何做特效及把特效发生碰撞时移出场景;(**** 中级技能)
36 | *
37 | */
38 |
39 | import UIKit
40 | import SpriteKit
41 | import GameplayKit
42 |
43 |
44 | class GameViewController: UIViewController {
45 |
46 | override func viewDidLoad() {
47 | super.viewDidLoad()
48 |
49 | if let view = self.view as! SKView? {
50 |
51 | if let scene = GameScene(fileNamed: "GameScene") {
52 | scene.scaleMode = .aspectFill
53 | scene.size = CGSize(width: SCENE_WIDTH, height: SCENE_HEIGHT)
54 | scene.anchorPoint = CGPoint(x: 0, y: 0) /// 设置anchorPoint为(0,0)
55 | view.presentScene(scene)
56 | }
57 | /* ***** 千万嫑嫑嫑小看了这一句的强大功效(监测物理体外框) ***** */
58 | // view.showsPhysics = true
59 | view.ignoresSiblingOrder = true /// 是否忽略图层自动排列 true
60 | view.showsFPS = true
61 | view.showsNodeCount = true
62 | }
63 | }
64 |
65 | override var shouldAutorotate: Bool {
66 | return true
67 | }
68 |
69 | override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
70 | if UIDevice.current.userInterfaceIdiom == .phone {
71 | return .allButUpsideDown
72 | } else {
73 | return .all
74 | }
75 | }
76 |
77 | override func didReceiveMemoryWarning() {
78 | super.didReceiveMemoryWarning()
79 | // Release any cached data, images, etc that aren't in use.
80 | }
81 |
82 | override var prefersStatusBarHidden: Bool {
83 | return true
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/SkyNinja/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | 天猪之城
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.1
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UIRequiresFullScreen
34 |
35 | UIStatusBarHidden
36 |
37 | UISupportedInterfaceOrientations
38 |
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/SkyNinja/Resources/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/.DS_Store
--------------------------------------------------------------------------------
/SkyNinja/Resources/Images/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Images/.DS_Store
--------------------------------------------------------------------------------
/SkyNinja/Resources/Images/Ninja.atlas/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Images/Ninja.atlas/.DS_Store
--------------------------------------------------------------------------------
/SkyNinja/Resources/Images/Ninja.atlas/t10001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Images/Ninja.atlas/t10001.png
--------------------------------------------------------------------------------
/SkyNinja/Resources/Images/Ninja.atlas/t10002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Images/Ninja.atlas/t10002.png
--------------------------------------------------------------------------------
/SkyNinja/Resources/Images/Ninja.atlas/t10003.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Images/Ninja.atlas/t10003.png
--------------------------------------------------------------------------------
/SkyNinja/Resources/Images/Ninja.atlas/t10004.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Images/Ninja.atlas/t10004.png
--------------------------------------------------------------------------------
/SkyNinja/Resources/Images/Ninja.atlas/t10005.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Images/Ninja.atlas/t10005.png
--------------------------------------------------------------------------------
/SkyNinja/Resources/Images/Ninja.atlas/t10006.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Images/Ninja.atlas/t10006.png
--------------------------------------------------------------------------------
/SkyNinja/Resources/Images/Ninja.atlas/t10007.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Images/Ninja.atlas/t10007.png
--------------------------------------------------------------------------------
/SkyNinja/Resources/Images/Ninja.atlas/t10008.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Images/Ninja.atlas/t10008.png
--------------------------------------------------------------------------------
/SkyNinja/Resources/Particles/CollectNormal.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Particles/CollectNormal.sks
--------------------------------------------------------------------------------
/SkyNinja/Resources/Particles/Trail.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Particles/Trail.sks
--------------------------------------------------------------------------------
/SkyNinja/Resources/Particles/death.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/Particles/death.sks
--------------------------------------------------------------------------------
/SkyNinja/Resources/SoundsFiles/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/SoundsFiles/.DS_Store
--------------------------------------------------------------------------------
/SkyNinja/Resources/SoundsFiles/Bomb.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/SoundsFiles/Bomb.wav
--------------------------------------------------------------------------------
/SkyNinja/Resources/SoundsFiles/background.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/SoundsFiles/background.mp3
--------------------------------------------------------------------------------
/SkyNinja/Resources/SoundsFiles/coin.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/SoundsFiles/coin.wav
--------------------------------------------------------------------------------
/SkyNinja/Resources/SoundsFiles/ninjaHit.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/Resources/SoundsFiles/ninjaHit.wav
--------------------------------------------------------------------------------
/SkyNinja/Resources/Utils/CGFloat+Extension.swift:
--------------------------------------------------------------------------------
1 | /* 注:此文件中的代码为iFIERO所引用,即原创版权非iFIERO所持有 */
2 |
3 | import CoreGraphics
4 | import SpriteKit
5 | /** π as a CGFloat 180度 */
6 | let π = CGFloat(Double.pi)
7 |
8 | public extension CGFloat {
9 | /**
10 | * 角度转化为弧度.
11 | */
12 | public func degreesToRadians() -> CGFloat {
13 | return π * self / 180.0
14 | }
15 |
16 | /**
17 | * 弧度转化为角度.
18 | */
19 | public func radiansToDegrees() -> CGFloat {
20 | return self * 180.0 / π
21 | }
22 |
23 | /**
24 | * 0.0 and 1.0 随机数.
25 | */
26 | public static func random() -> CGFloat {
27 | return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
28 | }
29 |
30 | /**
31 | * min...max 的随机数.
32 | */
33 | public static func random(_ min: CGFloat, max: CGFloat) -> CGFloat {
34 | assert(min < max)
35 | return CGFloat.random() * (max - min) + min
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/SkyNinja/Resources/Utils/CGVector+Extensions.swift:
--------------------------------------------------------------------------------
1 | /* 注:此文件中的代码为iFIERO所引用,即原创版权非iFIERO所持有 */
2 |
3 | import CoreGraphics
4 | import SpriteKit
5 |
6 | public extension CGVector {
7 | /**
8 | * Creates a new CGVector given a CGPoint.
9 | */
10 | public init(point: CGPoint) {
11 | self.init(dx: point.x, dy: point.y)
12 | }
13 |
14 | /**
15 | * Given an angle in radians, creates a vector of length 1.0 and returns the
16 | * result as a new CGVector. An angle of 0 is assumed to point to the right.
17 | */
18 | public init(angle: CGFloat) {
19 | self.init(dx: cos(angle), dy: sin(angle))
20 | }
21 |
22 | /**
23 | * Adds (dx, dy) to the vector.
24 | */
25 | public mutating func offset(_ dx: CGFloat, dy: CGFloat) -> CGVector {
26 | self.dx += dx
27 | self.dy += dy
28 | return self
29 | }
30 |
31 | /**
32 | * Returns the length (magnitude) of the vector described by the CGVector.
33 | */
34 | public func length() -> CGFloat {
35 | return sqrt(dx*dx + dy*dy)
36 | }
37 |
38 | /**
39 | * Returns the squared length of the vector described by the CGVector.
40 | */
41 | public func lengthSquared() -> CGFloat {
42 | return dx*dx + dy*dy
43 | }
44 |
45 | /**
46 | * Normalizes the vector described by the CGVector to length 1.0 and returns
47 | * the result as a new CGVector.
48 | public */
49 | func normalized() -> CGVector {
50 | let len = length()
51 | return len>0 ? self / len : CGVector.zero
52 | }
53 |
54 | /**
55 | * Normalizes the vector described by the CGVector to length 1.0.
56 | */
57 | public mutating func normalize() -> CGVector {
58 | self = normalized()
59 | return self
60 | }
61 |
62 | /**
63 | * Calculates the distance between two CGVectors. Pythagoras!
64 | */
65 | public func distanceTo(_ vector: CGVector) -> CGFloat {
66 | return (self - vector).length()
67 | }
68 |
69 | /**
70 | * Returns the angle in radians of the vector described by the CGVector.
71 | * The range of the angle is -π to π; an angle of 0 points to the right.
72 | */
73 | public var angle: CGFloat {
74 | return atan2(dy, dx)
75 | }
76 | }
77 |
78 | /**
79 | * Adds two CGVector values and returns the result as a new CGVector.
80 | */
81 | public func + (left: CGVector, right: CGVector) -> CGVector {
82 | return CGVector(dx: left.dx + right.dx, dy: left.dy + right.dy)
83 | }
84 |
85 | /**
86 | * Increments a CGVector with the value of another.
87 | */
88 | public func += (left: inout CGVector, right: CGVector) {
89 | left = left + right
90 | }
91 |
92 | /**
93 | * Subtracts two CGVector values and returns the result as a new CGVector.
94 | */
95 | public func - (left: CGVector, right: CGVector) -> CGVector {
96 | return CGVector(dx: left.dx - right.dx, dy: left.dy - right.dy)
97 | }
98 |
99 | /**
100 | * Decrements a CGVector with the value of another.
101 | */
102 | public func -= (left: inout CGVector, right: CGVector) {
103 | left = left - right
104 | }
105 |
106 | /**
107 | * Multiplies two CGVector values and returns the result as a new CGVector.
108 | */
109 | public func * (left: CGVector, right: CGVector) -> CGVector {
110 | return CGVector(dx: left.dx * right.dx, dy: left.dy * right.dy)
111 | }
112 |
113 | /**
114 | * Multiplies a CGVector with another.
115 | */
116 | public func *= (left: inout CGVector, right: CGVector) {
117 | left = left * right
118 | }
119 |
120 | /**
121 | * Multiplies the x and y fields of a CGVector with the same scalar value and
122 | * returns the result as a new CGVector.
123 | */
124 | public func * (vector: CGVector, scalar: CGFloat) -> CGVector {
125 | return CGVector(dx: vector.dx * scalar, dy: vector.dy * scalar)
126 | }
127 |
128 | /**
129 | * Multiplies the x and y fields of a CGVector with the same scalar value.
130 | */
131 | public func *= (vector: inout CGVector, scalar: CGFloat) {
132 | vector = vector * scalar
133 | }
134 |
135 | /**
136 | * Divides two CGVector values and returns the result as a new CGVector.
137 | */
138 | public func / (left: CGVector, right: CGVector) -> CGVector {
139 | return CGVector(dx: left.dx / right.dx, dy: left.dy / right.dy)
140 | }
141 |
142 | /**
143 | * Divides a CGVector by another.
144 | */
145 | public func /= (left: inout CGVector, right: CGVector) {
146 | left = left / right
147 | }
148 |
149 | /**
150 | * Divides the dx and dy fields of a CGVector by the same scalar value and
151 | * returns the result as a new CGVector.
152 | */
153 | public func / (vector: CGVector, scalar: CGFloat) -> CGVector {
154 | return CGVector(dx: vector.dx / scalar, dy: vector.dy / scalar)
155 | }
156 |
157 | /**
158 | * Divides the dx and dy fields of a CGVector by the same scalar value.
159 | */
160 | public func /= (vector: inout CGVector, scalar: CGFloat) {
161 | vector = vector / scalar
162 | }
163 |
164 | /**
165 | * Performs a linear interpolation between two CGVector values.
166 | */
167 | public func lerp(_ start: CGVector, end: CGVector, t: CGFloat) -> CGVector {
168 | return start + (end - start) * t
169 | }
170 |
--------------------------------------------------------------------------------
/SkyNinja/death.caf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiapia/SkyNinjaGameSpriteKitTutorial/729df1f7209fcefd6317c3da976edb4d8c6bc55d/SkyNinja/death.caf
--------------------------------------------------------------------------------