> 原文:http://www.jianshu.com/p/91de69a4fb2d
> 作者:[PMST](http://www.jianshu.com/users/596f2ba91ce9/latest_articles)
**本節任務:**
* 隨機生成障礙物,且一對障礙物上下相距距離固定,但位置隨機。
**幾種情況:**
`y position = 0`的情況:

`y position = playableStart`的情況:

`y position = playableStart - 障礙物.size.height/2`的情況:

推導一般情況下的公式:`y position = playableStart - 障礙物.size.height/2 + (10%~60%)playgroundHeight`:

上下兩個障礙物之間距離固定為3.5倍的*Player*尺寸的高度:

注意推導公式:`y position = playableStart - 障礙物.size.height/2`此時障礙物的頂部剛好與地面齊平,而`(10%~60%)playgroundHeight`是一個浮動范圍,表明障礙物超出地面的高度。顯然我們的障礙物的層級關系是在背景上面但是在*Foreground*的下面,因此修改早前的*Layer*:
~~~
enum Layer: CGFloat {
case Background
case Obstacle //添加障礙物層級關系
case Foreground
case Player
}
~~~
## 01.產生障礙物的構造方法
我們需要增添一個方法用于實例化一個紋理(圖片)為仙人掌的精靈(*SpriteNode*),設置其*zPosition*為*Obstacle*,請在`flapPlayer()`方法上方新增如下方法:
~~~
func createObstacle()->SKSpriteNode{
let sprite = SKSpriteNode(imageNamed: "Cactus")
sprite.zPosition = Layer.Obstacle.rawValue
return sprite
}
~~~
注意到實例方法生成一個紋理為*Cactus*的精靈并返回,這是之后源源不斷生成障礙物的基礎。
緊接著我們要有一個實例方法,作用是隨機產生成對的障礙物到場景中,步驟如下:
1. 使用`createObstacle()`得到下方障礙物的實例,并將其放置緊貼右側屏幕邊線。
2. 障礙物y軸上的放置位置范圍為10%~60%,分別計算最小與最大的y軸點位,通過隨機函數得到兩者之間的一個數作為y值,設置障礙物的*position*,最后添加到*worldNode*節點中。
3. 同理實例化上方障礙物,將其旋轉180°后放置距離下方障礙物3.5倍*Player*尺寸的地方,添加到*worldNode*節點中。
4. 給上下障礙物增添一個移動Action,已一定速度自右向左移動,倘若超出屏幕,則從父節點中移除。
~~~
//新增三個常量
let kBottomObstacleMinFraction: CGFloat = 0.1
let kBottomObstacleMaxFraction: CGFloat = 0.6
let kGapMultiplier: CGFloat = 3.5
// 在createObstacle()實例方法下方增添新方法
func spawnObstacle(){
//1
let bottomObstacle = createObstacle() //實例化一個精靈
let startX = size.width + bottomObstacle.size.width/2//x軸位置為屏幕最右側
//2
let bottomObstacleMin = (playableStart - bottomObstacle.size.height/2) + playableHeight * kBottomObstacleMinFraction //計算障礙物超出地表的最小距離
let bottomObstacleMax = (playableStart - bottomObstacle.size.height/2) + playableHeight * kBottomObstacleMaxFraction //計算障礙物超出地表的最大距離
bottomObstacle.position = CGPointMake(startX, CGFloat.random(min: bottomObstacleMin, max: bottomObstacleMax)) // 隨機生成10%~60%的一個距離賦值給position
worldNode.addChild(bottomObstacle) //添加到世界節點中
//3
let topObstacle = createObstacle() //實例化一個精靈
topObstacle.zRotation = CGFloat(180).degreesToRadians()//翻轉180°
topObstacle.position = CGPoint(x: startX, y: bottomObstacle.position.y + bottomObstacle.size.height/2 + topObstacle.size.height/2 + player.size.height * kGapMultiplier)//設置y位置 相距3.5倍的Player尺寸距離
worldNode.addChild(topObstacle)//添加至世界節點中
//4 給障礙物添加動作
let moveX = size.width + topObstacle.size.width
let moveDuration = moveX / kGroundSpeed
let sequence = SKAction.sequence([
SKAction.moveByX(-moveX, y: 0, duration: NSTimeInterval(moveDuration)),
SKAction.removeFromParent()
])
topObstacle.runAction(sequence)
bottomObstacle.runAction(sequence)
}
~~~
倘若你迫不及待想看看成果,將`spawnObstacle`方法添加至`didMoveToView()`最下方,點擊運行。一對障礙物“呼嘯而過”,然后就沒有然后了...確實目前這個方法僅僅只是產生一對罷了,為此我們還需要新增一個方法用于源源不斷的產生障礙物。請添加如下內容到`spawnObstacle()`方法下方
~~~
func startSpawning(){
//1
let firstDelay = SKAction.waitForDuration(1.75)
//2
let spawn = SKAction.runBlock(spawnObstacle)
//3
let everyDelay = SKAction.waitForDuration(1.5)
//4
let spawnSequence = SKAction.sequence([
spawn,everyDelay
])
//5
let foreverSpawn = SKAction.repeatActionForever(spawnSequence)
//6
let overallSequence = SKAction.sequence([firstDelay,foreverSpawn])
runAction(overallSequence)
}
~~~
1. 第一個障礙物生成延遲1.75秒
2. 生成障礙物的動作,用到了先前的實例方法`spawnObstacle`.
3. 之后生成障礙物的間隔時間為1.5秒
4. 之后障礙物的生成順序是:產生障礙物,延遲1.5秒;產生障礙物,延遲1.5秒;產生障礙物,延遲1.5秒...可以看出**[產生障礙物,延遲1.5秒]**為一組重復動作。
5. 使用`SKAction.repeatActionForever`重復4中的動作。
6. 將延遲1.75秒和重復動作整合成一個SKAction的數組,然后讓場景來執行該動作組。
請將`didMoveToView()`方法中的`spawnObstacle`替換成`startSpawning()`,點擊運行。