> 原文:http://www.jianshu.com/p/f88dce673de9
> 作者:[PMST](http://www.jianshu.com/users/596f2ba91ce9/latest_articles)
## 本文任務
* 游戲運行中,Foreground地面持續滾動。
## 持續移動地面
**任務一需要解決的問題**:
1. 如何移動地面。
2. 如何無縫連接。
**問題一**的解決思路是每次渲染完畢進入`update()`方法中更新*Foreground*的坐標位置,即改變*position*的*x*值。
**問題二**的解決思路是實例化兩個*Foreground*,相鄰緊挨,以約定好的速度向左移動,當第一個節點位置超出屏幕范圍(對玩家來說是不可見)時,改變其坐標位置,添加到第二個節點尾部,如此循環實現無縫連接,參考圖為:



**代碼實現:**
找到*GameScene*類中的`setupForeground()`方法,由于現在需要實例化兩個*Foreground*,顯然早前的已不再使用,替換方法中的所有內容:
~~~
func setupForeground() {
for i in 0..<2{
let foreground = SKSpriteNode(imageNamed: "Ground")
foreground.anchorPoint = CGPoint(x: 0, y: 1)
// 改動1
foreground.position = CGPoint(x: CGFloat(i) * size.width, y: playableStart)
foreground.zPosition = Layer.Foreground.rawValue
// 改動2
foreground.name = "foreground"
worldNode.addChild(foreground)
}
}
~~~
注意我們采用`for-in`進行2次實例化,代碼有兩處改動:1.放置位置與*i*值相關;2.給節點取名為“foreground”,方便之后查找操作。
*Foreground*勻速移動,自然速度值需要固定,姑且這里設為150.0,請在`let kImpulse: CGFloat = 400.0`下方添加一行速度常量定義`let kGroundSpeed: CGFloat = 150.0`。
對于*Foreground*的位置更新自然也是在方法`update()`中進行了,每隔大約33毫秒就跳入該函數更新*position*。就像早前`updatePlayer()`一樣,在其下方聲明一個名為*updateForeground*方法。
~~~
func updateForeground(){
//1
worldNode.enumerateChildNodesWithName("foreground") { (node, stop) -> Void in
//2
if let foreground = node as? SKSpriteNode{
//3
let moveAmt = CGPointMake(-self.kGroundSpeed * CGFloat(self.dt), 0)
foreground.position += moveAmt
//4
if foreground.position.x < -foreground.size.width{
foreground.position += CGPoint(x: foreground.size.width * CGFloat(2), y: 0)
}
}
}
}
~~~
講解:
1. 還記得先前設置了*Foreground*節點的名字為*foreground*嗎?通過`enumerateChildNodesWithName`方法即可遍歷所有名為*foreground*的節點。
2. 注意*node*是`SKNode`類型,而*foreground*精靈是`SKSpriteNode`類型,需要向下變形。
3. 計算dt時間中*foreground*移動的距離,更新*position*坐標位置。
4. 倘若該*foreground*超出了屏幕,則正如前面所說的將其添加到第二個精靈尾部。
> 4中的位置條件判斷,希望讀者理解透徹。首先*SpriteKit*中坐標系與之前不同,原點位于左下角,x軸正方向自左向右,y軸正方向自下向上;其次*wordNode*節點位于原點處,因此它內部的坐標系也是以左下角為原點。請集合上文圖片進行理解。
ok,將`updateForeground`方法添加到`update()`中的最下面即可,點擊運行。