前言
筆者是swift自學(xué)新手胳施,希望借助閱讀別人開源項目提升自己swift水平。文中盡量使用文字說明來代替代碼的堆砌谦秧,建議對著源碼閱讀鼠次,以便更好理解項目。文中難免有錯誤之處邢笙,歡迎各路大牛留言指正啸如。
項目信息
swift-2048 github地址
該項目可以說一個帶有實驗學(xué)習性質(zhì)的項目,其中部分功能沒有實現(xiàn)或不完整氮惯。但2048游戲的基本功能均完整實現(xiàn)叮雳。筆者將分3篇文章,分別按controller妇汗、model帘不、view的進行介紹。
本篇是第1篇杨箭,將重點展開介紹controller部分寞焙。
開始
對于一個完整項目,筆者喜歡從AppDelegate讀起:
1.AppDelegate沒有添加代碼互婿;
2.Main.storyboard中只有一個startGame按鈕捣郊;
3.開始按鈕對應(yīng)的方法也內(nèi)也只有2句代碼:
@IBAction func startGameButtonTapped(sender : UIButton) {
? ? let game = NumberTileGameViewController(dimension: 4, threshold: 2048)
? ? self.presentViewController(game, animated: true, completion: nil)
}
可見游戲的所有功能業(yè)務(wù)邏輯應(yīng)該全部在NumberTileGameViewController中慈参。
補充解釋
dimension 表示游戲盤的維度,dimension=4表示4*4大小的游戲盤驮配。
threshold 表示游戲勝利條件着茸,threshold=2048表示當出現(xiàn)2048時游戲結(jié)束。
正題
NumberTileGameViewController是整個游戲的的入口琐旁。不說大家應(yīng)該也猜到了涮阔,本類里面的內(nèi)容就是model+view旋膳。
//model:
var model: GameModel? //整個游戲的model
//view:
var board: GameboardView? //游戲盤的view
var scoreView: ScoreViewProtocol? //顯示等分的view
contoller如何使用model?
model在init中初始化:
model = GameModel(dimension: dimension, threshold: threshold, delegate: self)
model有主要4個方法被controller主動調(diào)用:
m.insertTileAtRandomLocation(2) 在游戲盤上一個隨機位置插入一枚棋子
m.userHasWon() 判斷是否是獲勝
m.userHasLost() 判斷是否是失敗
m.queueMove(MoveDirection.Down, completion: { ... })//移動棋子(向下滑動手勢)
上面4個方法途事,主要是在用戶滑動手勢之后進行調(diào)用验懊,滑動手勢對應(yīng)的方法中主要完成以下3步:
1》queueMove移動格子
2》移動完成后,判斷是否獲勝userHasWon或失敗userHasLost
3》如果游戲可以繼續(xù)尸变,插入新格子insertTileAtRandomLocation
可見义图,上面是典型的 view(手勢)更新 model 的流程召烂。
model通知view,也使用了典型的做法--委托
model定義了如下協(xié)議:
protocol GameModelProtocol : class {
? ? func scoreChanged(score: Int)
? ? func moveOneTile(from: (Int, Int), to: (Int, Int), value: Int)
? ? func moveTwoTiles(from: ((Int, Int), (Int, Int)), to: (Int, Int), value: Int)
? ? func insertTile(location: (Int, Int), value: Int)
}
本協(xié)議定義了游戲model所產(chǎn)生的結(jié)果動作:
1》scoreChanged 得分變化
2》moveOneTile 移動一個棋子怕篷,到一個新位置
3》moveTwoTiles 移動2個棋子酗昼,到一個新位置
4》insertTile 插入新棋子
其中,1麻削、4還是很好理解。2呛哟、3 是開發(fā)者根據(jù)游戲的特點所抽象出的2種棋子移動方式(具體說明將在專門分析model時提到)。這四個方法均在NumberTileGameViewController中實現(xiàn)榛鼎。實現(xiàn)很簡單鳖孤,即直接調(diào)用相應(yīng)view的方法:1調(diào)用的是scoreView的scoreChange;2.3.4調(diào)用是board(GameBoardVIew)的moveOneTile淌铐、moveTwoTiles、insertTile方法际起。例如:
func insertTile(location: (Int, Int), value: Int) {//插入新棋子的協(xié)議實現(xiàn)
? ? assert(board != nil)
? ? let b = board!
? ? b.insertTile(location, value: value)//調(diào)用view對應(yīng)的方法
}
梳理controller主要方法的流程
init方法:
1.創(chuàng)建GameModel
2.setupSwipeControls 創(chuàng)建滑動手勢的動作
viewDidLoad方法:
調(diào)用setupGame, 安裝Game相關(guān)的view (后面有本函數(shù)的流程說明)
滑動手勢的處理方法:
func downCommand(r: UIGestureRecognizer!) {
? ? assert(model != nil)
? ? let m = model!
? ? m.queueMove(MoveDirection.Down, //調(diào)用model街望,進行業(yè)務(wù)處理
? ? completion: { (changed: Bool) -> () in //本無名閉包將在model調(diào)用委托方法之后,執(zhí)行
? ? ? ? if changed {
? ? ? ? ? ? self.followUp() //這個是后續(xù)方法防症,執(zhí)行如判斷游戲勝利失敗或插入新棋子)
? ? ? ? }
? ?})
}
setupGame方法:
1創(chuàng)建內(nèi)部函數(shù)xPositionToCenterView。返回一個view水平居中后的x
2內(nèi)部函數(shù)yPositionForViewAtPosition 給一組view垂直居中后蔫敲,其中某一個view的y
3創(chuàng)建scoreView
4創(chuàng)建game board view
5通過前面的內(nèi)部函數(shù)炭玫,計算出scoreView和gameBoardView的frame中的xy
6將scoreView和game board加入主view,并賦值到viewcontrller的對應(yīng)屬性
7調(diào)用model吞加,新增隨機游戲棋子,開始游戲
總結(jié)
本項目中的viewcontroller的職能很清晰的叶圃,主要是下面2點:
1》初始化view践图、model、手勢
2》協(xié)助view和model交互(手勢處理函數(shù)中調(diào)用model平项;model的委托函數(shù)中調(diào)用view)