> 原文:http://www.jianshu.com/p/85a2e9f29a24
> 作者:[PMST](http://www.jianshu.com/users/596f2ba91ce9/latest_articles)
## 01.項目文件介紹
首先請打開項目,先介紹項目已有文件,你將看到如下目錄:

L01-Dir
主要講解以下一些重要的文件:
* Resource文件夾:資源文件放置處
* Art:以atlas圖冊方式管理素材文件。
* SKTUtiles:采用Extension對一些類進行拓展,添加一些有用的方法或屬性。
* Sounds:游戲聲音素材
* GameScene.swift:Flappy游戲比較簡單,因此一個游戲場景足以,有關于場景內容設置、交互等均在該場景中設置。
* GameViewController.swift:視圖控制器,包含一個視圖*view*,當然這個視圖比較特殊:為*SKView*,用于呈現場景*Scene*。
## 02.呈現視圖
選中*GameViewController.swift*文件,先前提及視圖控制器中的*SKView*,其職責在于呈現游戲場景*Scene*。不過現在空文件中神馬都沒有,我們將重寫`viewWillLayoutSubviews()`方法呈現場景。定位到*GameViewController*類,添加以下代碼:
~~~
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
// 1.對view進行父類向子類的變形,結果是一個可選類型 因此需要解包
if let skView = self.view as? SKView{
// 倘若skView中沒有場景Scene,需要重新創建創建一個
if skView.scene == nil{
/*== 創建場景代碼 ==*/
// 2.獲得高寬比例
let aspectRatio = skView.bounds.size.height / skView.bounds.size.width
// 3.new一個場景實例 這里注意場景的width始終為320 至于高是通過width * aspectRatio獲得
let scene = GameScene(size:CGSizeMake(320, 320 * aspectRatio))
// 4.設置一些調試參數
skView.showsFPS = true // 顯示幀數
skView.showsNodeCount = true // 顯示當前場景下節點個數
skView.showsPhysics = true // 顯示物理體
skView.ignoresSiblingOrder = true // 忽略節點添加順序
// 5.設置場景呈現模式
scene.scaleMode = .AspectFill
// 6.呈現場景
skView.presentScene(scene)
}
}
}
~~~
這里需要注意2、3處,固定了游戲場景的寬度*Width = 320*,高度則通過*Width*乘以高寬比相乘得到,對于*iPhone4s iPhone5/5s*這些寬為320的設備來說自然沒什么影響,但是對于*iPhone6/6Pluse*設備,相當于將設備寬高同時縮小相同倍數,直至寬為320時停止;再通過設置*scaleMode*為`AspectFill`(更多*ScaleMode*,請點擊[這里](http://blog.csdn.net/colouful987/article/details/44855213)了解)呈現視圖。
對于4來說,我們需要了解游戲運行時每秒的幀數、當前場景中節點個數、顯示節點的物理體等,因此通過設置這些參數能幫助我們更好的調試。
OK,點擊運行項目,模擬器運行結果一片漆黑,不過右下角顯示*node=1 60.0fps*,表明當前場景中顯示了一個節點,幀數為60左右。
> Question:什么都還沒添加,視圖中怎么會有一個節點Node了呢?
>
> Answer:場景Scene類為SKScene,繼承自SKNode,因此當skView呈現場景時,自然就將一個節點置于其中了。
## 03場景內容的填充
定位到*GameScene.swift*文件,可以看到文件中已經聲明了一個*GameScene*類,當然類中我們還未實現任何東西,因此這是運行項目呈現出來的場景是漆黑一片。是時候一步步配置游戲場景了!
首先,定位到*GameScene*類中,在類中頂部添加如下三個變量,如下:
~~~
class GameScene:SKScene:{
let worldNode = SKNode()
var playableStart:CGFloat = 0
var playableHeight:CGFloat = 0
//...文件其他內容
}
~~~
如上實例化了一個節點命名為`worldNode`,原因在于之后游戲中所有的節點都將添加至這個節點中,方便管理。此外游戲中場景分為*Background*和*Ground*兩部分,前者是背景,鳥可以在該區域中上下飛行;后者地面,小鳥僅限于跌落至上面。具體劃分請看下圖:

L01-Scene
其中,背景和地面均作為節點添加至`worldNode`節點中。請在`didMoveToView(view:)`方法中添加如下代碼:
~~~
override func didMoveToView(view: SKView) {
addChild(worldNode)
setupBackground()
setupForeground()
}
~~~
首先添加`worldNode`節點到場景中,接著`setupBackground()`和`setupForeground()`兩個方法分別設置背景和地面兩個節點,當然此時方法還未實現。
通常游戲包含多個節點,為了細化節點的圖層關系,節點`Node`中設定了一個`zPosition`屬性用于標識節點相距你的程度,越小越里面,越大越外面。顯然游戲中,背景至于最底部,其次是地面,最后才是`Player`那只鳥。為此我們將使用枚舉來說明層級關系,在`GameScene`類上方添加`Layer`的聲明:
~~~
enum Layer: CGFloat {
case Background
case Foreground
case Player
}
class GameScene:SKScene{}
~~~
干完這些,是時候補充剩下的兩個方法的實現了。首先添加`setupBackground()`方法至*GameScene*類中:
~~~
func setupBackground(){
// 1
let background = SKSpriteNode(imageNamed: "Background")
background.anchorPoint = CGPointMake(0.5, 1)
background.position = CGPointMake(size.width/2.0, size.height)
background.zPosition = Layer.Background.rawValue
worldNode.addChild(background)
// 2
playableStart = size.height - background.size.height
playableHeight = background.size.height
}
~~~
依葫蘆畫瓢實現`setupForeground()`方法:
~~~
func setupForeground() {
let foreground = SKSpriteNode(imageNamed: "Ground")
foreground.anchorPoint = CGPoint(x: 0, y: 1)
foreground.position = CGPoint(x: 0, y: playableStart)
foreground.zPosition = Layer.Foreground.rawValue
worldNode.addChild(foreground)
}
~~~
點擊運行,你將看到如下畫面,*Good Job!*?你已經完成了第一步,之后我們將添加*Player*以及障礙物到場景中。
