这篇博客写了什么?
刚开始使用swift编写ios程序,花了两三天的时间看了下《The Swift Programming Language》,看了就忘了o(╯□╰)o,于是干脆从一个项目入手,一边开发一边学习。github上面找了一个挺有名的开源项目swift-2048,经过一天半的”刻苦”学习,终于略有小成。
项目结构
除去xocde7自动生成的一些文件外,austinzheng(2048项目作者),一共就使用7个.swift文件完成了整个项目,让本人第一感觉这个项目挺简单的。接下来就简单的介绍一下每一个文件的大概用处。
GameModel
全工程最庞大的一个文件,在models文件夹下,这个文件主要是算法的实现(移动合并算法),虽然说是model文件后缀,但是本人实在想不到这个文件和MVC中的model有什么关系。
AuxiliaryModels
里面定义着本项目用到的所有的、用户自定义的结构体与枚举
AccessoryViews
本文件里面定义着代表分数的view
GameboardView
和文件名称一样,这个文件是游戏的主要面板也就是下面这个
TileView
文件名也出卖了它,这个让用户看起来就是2048游戏中的那些可以移动的数字。
NumberTileGame
游戏的主要控制器,几乎所有的逻辑均在这里处理
AppearanceProvider
项目辅助功能,它决定着游戏中数字以及TileView的颜色
代码分析
以文件为单位,对2048项目进行一个简单的分析。
TileView.swift
2048项目里面较为简单的一个文件。TileView也就是2048中可以移动的方块
value 属性
这个属性代表着一个tileView上面所显示的分数的数值,并设置了一个属性观察器didSet,这个属性观察器在每一次value属性被设置新值的时候调用。目的是为了在每一次值改变的时候给TileView的背景颜色、文字颜色、以及TileView上显示的Label数值,这给3个属性重新赋值(2048游戏中,TIleVIew数值的不同,颜色是不一样的,2,4,8的颜色都不一样)
delegate 属性
遵守AppearanceProviderProtocol协议的代理,主要用于更改颜色
numberLabel 属性
TileView上每个数字都是一个Label
构造方法
无疑是对TileView本身进行一些初始化,包括本身的大小以及UILabel的创建之类
AccessoryViews.swift
前面项目结构以及分析了,这个文件主要负责获得分数的显示.这个文件也十分的简单,里面主要的类就是 ScoreView它遵守了ScoreViewProtocol协议。因为简单,所以不过多解释.
score 属性
游戏总共的得分,同样也有一个didSet属性观察器,再每次score属性发生改变的时候,更新Label的显示
scoreChanged 方法
在每一次分数改变的时候调用,用于跟新分数显示(个人感觉这个方法和协议写的有点多余)
AppearanceProvider.swift
一个辅助用的,主要用于TileView颜色的控制,简单不多解释.(没有这个文件提供的功能,项目一样可以跑,只是丑点)
GameboardView.swift
一个稍稍复杂的文件,代表游戏面板的view,也就是下面这个黑框框(十分明显的九宫格布局)。当然还实现了一些对TileView的移动、插入等操作。接下来只解释一些主要属性。
tiles 属性
一个Dictionary
NumberTileGame.swift
这个文件就是本项目最主要的一个视图控制器的实现。处理着绝大部分的逻辑。
model 属性
这个属性稍后会在GameModel.swift中进行详细介绍,这里先有个初步了解,它处理游戏中平移与合并算法。2048游戏最重要也是最难的便是它的平移和移动算法的实现。
其他属性
其他的属性几乎都是前面介绍过的。
构造方法
构造方法中对几个属性进行了初始化,并调用setupSwipeControls方法添加了4个手势识别器。
setupGame 方法
由ViewDidLoad调用,用来对游戏界面进行初始化(创建显示分数的ScoreView和游戏面板GameboardView)。值得一提的便是其中的两个用于计算x,y的内嵌方法。xPositionToCenterView与yPositionForViewAtPosition。首先得明白,游戏中”大”的view就只有显示总分数的scoreView和游戏面板GameboardView。而这两个view的位置关系总是scoreView在上GameboardView在下,并且两个view都是居于屏幕最中央(水平且垂直居中)。自己可以换几个不同屏幕大小试一试。而让他们位置有自适应的能力的便就是xPositionToCenterView与yPositionForViewAtPosition两个内嵌方法
func xPositionToCenterView(v: UIView) -> CGFloat { let viewWidth = v.bounds.size.width let tentativeX = 0.5*(vcWidth - viewWidth) return tentativeX >= 0 ? tentativeX : 0 }
这个方法还不算复杂,其目的是:计算出能使传入参数v这个view,在控制器中居中显示的x的值。
func yPositionForViewAtPosition(order: Int, views: [UIView]) -> CGFloat { ... //所有控件高度之和(包括间距),views.map({ $0.bounds.size.height })将所有view的高度取出,然后通过.reduce对所有高度进行求和。 let totalHeight = CGFloat(views.count - 1)*viewPadding + views