前言
笔者是swift自学新手,希望借助阅读别人开源项目提升自己swift水平。文中尽量使用文字说明来代替代码的堆砌,建议对着源码阅读,以便更好理解项目。文中难免有错误之处,欢迎各路大牛留言指正。
项目信息
swift-2048 github地址
该项目可以说一个带有实验学习性质的项目,其中部分功能没有实现或不完整。但2048游戏的基本功能均完整实现。笔者将分3篇文章,分别按controller、model、view的进行介绍。
本篇是第1篇,将重点展开介绍controller部分。
开始
对于一个完整项目,笔者喜欢从AppDelegate读起:
1.AppDelegate没有添加代码;
2.Main.storyboard中只有一个startGame按钮;
3.开始按钮对应的方法也内也只有2句代码:
@IBAction func startGameButtonTapped(sender : UIButton) {
let game = NumberTileGameViewController(dimension: 4, threshold: 2048)
self.presentViewController(game, animated: true, completion: nil)
}
可见游戏的所有功能业务逻辑应该全部在NumberTileGameViewController中。
补充解释
dimension 表示游戏盘的维度,dimension=4表示4*4大小的游戏盘。
threshold 表示游戏胜利条件,threshold=2048表示当出现2048时游戏结束。
正题
NumberTileGameViewController是整个游戏的的入口。不说大家应该也猜到了,本类里面的内容就是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主动调用:
m.insertTileAtRandomLocation(2) 在游戏盘上一个随机位置插入一枚棋子
m.userHasWon() 判断是否是获胜
m.userHasLost() 判断是否是失败
m.queueMove(MoveDirection.Down, completion: { ... })//移动棋子(向下滑动手势)
上面4个方法,主要是在用户滑动手势之后进行调用,滑动手势对应的方法中主要完成以下3步:
1》queueMove移动格子
2》移动完成后,判断是否获胜userHasWon或失败userHasLost
3》如果游戏可以继续,插入新格子insertTileAtRandomLocation
可见,上面是典型的 view(手势)更新 model 的流程。
model通知view,也使用了典型的做法--委托
model定义了如下协议:
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)
}
本协议定义了游戏model所产生的结果动作:
1》scoreChanged 得分变化
2》moveOneTile 移动一个棋子,到一个新位置
3》moveTwoTiles 移动2个棋子,到一个新位置
4》insertTile 插入新棋子
其中,1、4还是很好理解。2、3 是开发者根据游戏的特点所抽象出的2种棋子移动方式(具体说明将在专门分析model时提到)。这四个方法均在NumberTileGameViewController中实现。实现很简单,即直接调用相应view的方法:1调用的是scoreView的scoreChange;2.3.4调用是board(GameBoardVIew)的moveOneTile、moveTwoTiles、insertTile方法。例如:
func insertTile(location: (Int, Int), value: Int) {//插入新棋子的协议实现
assert(board != nil)
let b = board!
b.insertTile(location, value: value)//调用view对应的方法
}
梳理controller主要方法的流程
init方法:
1.创建GameModel
2.setupSwipeControls 创建滑动手势的动作
viewDidLoad方法:
调用setupGame, 安装Game相关的view (后面有本函数的流程说明)
滑动手势的处理方法:
func downCommand(r: UIGestureRecognizer!) {
assert(model != nil)
let m = model!
m.queueMove(MoveDirection.Down, //调用model,进行业务处理
completion: { (changed: Bool) -> () in //本无名闭包将在model调用委托方法之后,执行
if changed {
self.followUp() //这个是后续方法,执行如判断游戏胜利失败或插入新棋子)
}
})
}
setupGame方法:
1创建内部函数xPositionToCenterView。返回一个view水平居中后的x
2内部函数yPositionForViewAtPosition 给一组view垂直居中后,其中某一个view的y
3创建scoreView
4创建game board view
5通过前面的内部函数,计算出scoreView和gameBoardView的frame中的xy
6将scoreView和game board加入主view,并赋值到viewcontrller的对应属性
7调用model,新增随机游戏棋子,开始游戏
总结
本项目中的viewcontroller的职能很清晰的,主要是下面2点:
1》初始化view、model、手势
2》协助view和model交互(手势处理函数中调用model;model的委托函数中调用view)