博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[swift实战入门]手把手教你编写2048(二)
阅读量:4078 次
发布时间:2019-05-25

本文共 7789 字,大约阅读时间需要 25 分钟。

上篇地址:

github地址:。

上篇文章已经中已经把2048的游戏区块画好了,这篇来加入计分板以及往游戏面板中插入数字块

计分板同样作为一个view,我们新建一个ScoreView.swift文件,代码如下:

import UIKit//这里协议的作用是方便别的类中调用计分板的scoreChanged方法protocol ScoreProtocol{    func scoreChanged(newScore s : Int)}class ScoreView : UIView , ScoreProtocol{    //计分板本身是个lable,作用是显示分数    var lable : UILabel    //分数    var score : Int = 0{        didSet{            lable.text = "SCORE:\(score)"        }    }    let defaultFrame = CGRectMake(0, 0, 140, 40)    init(backgroundColor bgColor : UIColor, textColor tColor : UIColor , font : UIFont){        lable = UILabel(frame : defaultFrame)        lable.textAlignment = NSTextAlignment.Center        super.init(frame : defaultFrame)        backgroundColor = bgColor        lable.textColor = tColor        lable.font = font        lable.layer.cornerRadius = 6        self.addSubview(lable)    }    required init?(coder aDecoder: NSCoder) {        fatalError("init(coder:) has not been implemented")    }    func scoreChanged(newScore s : Int){        score = s    }}

其中引入了swift中的Protocol这个概念,即协议,其作用类似于Java中的接口,就是方便别的地方调用其中的对外暴露的方法。

加入了ScoreView之后,我们再在主控制器NumbertailGameController中初始化一个计分板即可,代码如下:

func setupGame(){    //...此处省略之前代码    //初始化一个ScoreView    let scoreView = ScoreView(        backgroundColor:  UIColor(red : 0xA2/255, green : 0x94/255, blue : 0x5E/255, alpha : 1),        textColor: UIColor(red : 0xF3/255, green : 0xF1/255, blue : 0x1A/255, alpha : 0.5),        font: UIFont(name: "HelveticaNeue-Bold", size: 16.0) ?? UIFont.systemFontOfSize(16.0)    )    let views = [scoreView , gamebord]    //定位其在主面板中左上角的绝对位置    var f = scoreView.frame    f.origin.x = xposition2Center(view: scoreView)    f.origin.y = yposition2Center(0, views: views)    scoreView.frame = f    //调用其自身方法来初始化一个分数    scoreView.scoreChanged(newScore: 13631488)}

运行结果如下:

可以看到计分板已经出现在游戏中了,接下来我们往游戏中加入数字块,一个数字块其实也就是一个view,所以同样我们新建一个TileView.swift文件,代码如下:

import UIKitclass TileView : UIView{    //数字块中的值    var value : Int = 0 {        didSet{            backgroundColor = delegate.tileColor(value)            lable.textColor = delegate.numberColor(value)            lable.text = "\(value)"        }    }    //提供颜色选择    unowned let delegate : AppearanceProviderProtocol    //一个数字块也就是一个lable    var lable : UILabel    init(position : CGPoint, width : CGFloat, value : Int, delegate d: AppearanceProviderProtocol){        delegate = d        lable = UILabel(frame : CGRectMake(0 , 0 , width , width))        lable.textAlignment = NSTextAlignment.Center        lable.minimumScaleFactor = 0.5        lable.font = UIFont(name: "HelveticaNeue-Bold", size: 15) ?? UIFont.systemFontOfSize(15)        super.init(frame: CGRectMake(position.x, position.y, width, width))        addSubview(lable)        lable.layer.cornerRadius = 6        self.value = value        backgroundColor = delegate.tileColor(value)        lable.textColor = delegate.numberColor(value)        lable.text = "\(value)"    }    required init?(coder aDecoder: NSCoder) {        fatalError("init(coder:) has not been implemented")    }}

这里的AppearanceProviderProtocol其实就是里面定义了一些颜色,可以根据当前的数字值来取不同的颜色,内容很简单,为了不占篇幅,此处就省略了,大家可以在github上下载源码来看下。

同样的,加了视图后,我们需要将其初始化出来,这里由于数字块是在游戏面板中的,所以我们将初始化方法放入GamebordView类中,在GamebordView.swift中新增如下方法:

func insertTile(pos : (Int , Int) , value : Int) {    assert(positionIsValied(pos))    let (row , col) = pos    //取出当前数字块的左上角坐标(相对于游戏区块)    let x = tilePadding + CGFloat(row)*(tilePadding + tileWidth)    let y = tilePadding + CGFloat(col)*(tilePadding + tileWidth)    let tileView = TileView(position : CGPointMake(x, y), width: tileWidth, value: value, delegate: provider)    addSubview(tileView)    bringSubviewToFront(tileView)    tiles[NSIndexPath(forRow : row , inSection:  col)] = tileView    //这里就是一些动画效果,如果有兴趣可以研究下,不影响功能    UIView.animateWithDuration(tileExpandTime, delay: tilePopDelay, options: UIViewAnimationOptions.TransitionNone,        animations: {            tileView.layer.setAffineTransform(CGAffineTransformMakeScale(self.tilePopMaxScale, self.tilePopMaxScale))        },        completion: { finished in            UIView.animateWithDuration(self.tileContractTime, animations: { () -> Void in            tileView.layer.setAffineTransform(CGAffineTransformIdentity)        })    })}func positionIsValied(position : (Int , Int)) -> Bool{    let (x , y) = position    return x >= 0 && x < dimension && y >= 0 && y < dimension}

上面代码很简单,就是取出数字块相对于游戏区块的坐标,然后初始化出数字块,添加到游戏面板中,且将其置于上层。

接下来我们在主控制器NumbertailGameController中调用此方法,就可以看到效果了,代码如下:

var bord : GamebordView?func setupGame(){    //...此处省略之前代码    gamebord.insertTile((3,1) , value : 2)    gamebord.insertTile((1,3) , value : 2)}func insertTile(pos : (Int , Int) , value : Int){    assert(bord != nil)    let b = bord!    b.insertTile(pos, value: value)}

运行看效果如下:

可以看到游戏区块中已经有数字块了,接下来会面临一个问题,就是我们的2048游戏,是在每次滑动之后,随机向空余的地方插入一个数字块,那么,这里我们需要提供一个随机向空余地方插入数字块的方法,这里选用一个我们选用一个数组结构来存储已经添加进游戏的数字块,数组中存储当前块的值,我们通过当前值是否为空来判断这个位置是否空闲,首先我们新建一个BaseModle.swift文件,代码如下:

import Foundation//数组中存放的枚举,要么空要么一个带值的Tileenum TileEnum {    case Empty    case Tile(Int)}struct SequenceGamebord
{ var demision : Int //存放实际值的数组 var tileArray : [T] init(demision d : Int , initValue : T ){ self.demision = d tileArray = [T](count : d*d , repeatedValue : initValue) } //通过当前的x,y坐标来计算存储和取出的位置 subscript(row : Int , col : Int) -> T { get{ assert(row >= 0 && row < demision && col >= 0 && col < demision) return tileArray[demision*row + col] } set{ assert(row >= 0 && row < demision && col >= 0 && col < demision) tileArray[demision*row + col] = newValue } } //初始化时使用 mutating func setAll(value : T){ for i in 0..

上段代码涉及到两个关键字,其中subscript就是给结构体定义下标访问方式,mutating是结构体在修改自身属性时必须要加的。

结构体定义好了,我们知道现在要存放整个数字块状态的结构体就是一个SequenceGamebord<TileEnum>,接下来,我们需要新建一个GameModle.swift充当我们的游戏区域的modle层,来记录当前游戏的状态以及提供一些游戏自身的操作等(这里大家可以注意下,这个项目中命名规则我都是视图层以View结尾,控制层以Controller结尾,模型层以Modle结尾,不太理解这些层意义的建议去Google下MVC,此处就不多讲了)。代码如下:

import UIKitclass GameModle : NSObject {    let dimension : Int    let threshold : Int    //存放数字块状态信息    var gamebord : SequenceGamebord
unowned let delegate : GameModelProtocol //当前分数,改变后回调用分数视图渲染分数 var score : Int = 0{ didSet{ delegate.changeScore(score) } } //初始化一个都存的Empty的SequenceGamebord
init(dimension : Int , threshold : Int , delegate : GameModelProtocol) { self.dimension = dimension self.threshold = threshold self.delegate = delegate gamebord = SequenceGamebord(demision: dimension , initValue: TileEnum.Empty) super.init() }}

上面代码很简单,下面我们来新加方法取出游戏区中空置的块:

func getEmptyPosition() -> [(Int , Int)]  {    var emptyArrys : [(Int , Int)] = []    for i in 0..

代码很简单,就是通过遍历SequenceGamebord<TileEnum>,将不为空的位置组成一个(Int , Int)的字典数组返回。

接下来写随机插入的方法:

func insertRandomPositoinTile(value : Int)  {    let emptyArrays = getEmptyPosition()    if emptyArrays.isEmpty {        return    }    let randomPos = Int(arc4random_uniform(UInt32(emptyArrays.count - 1)))    let (x , y) = emptyArrays[randomPos]    gamebord[(x , y)] = TileEnum.Tile(value)    delegate.insertTile((x , y), value: value)}

这个方法也很简单,就是取出当前所有的空的位置数组,在随机一个数组中的位置,之后赋值给gamebord以及调用游戏视图层渲染出新的游戏区块

接下来我们在主控制器NumbertailGameController中加入如下代码看下效果:

var gameModle : GameModle?init(dimension d : Int , threshold t : Int) {    //...此处省略之前代码    gameModle = GameModle(dimension: dimension , threshold: threshold , delegate: self )}func setupGame(){    //...此处省略之前代码    assert(gameModle != nil)    let modle = gameModle!    modle.insertRandomPositoinTile(2)    modle.insertRandomPositoinTile(2)    modle.insertRandomPositoinTile(2)}

运行看下效果:

可以看到,在随机位置插入了三个数字为2的数字块。

今天就先介绍到这里,下期来将数字块的移动。


我的博客:blog.scarlettbai.com

欢迎关注个人微信公众号:读书健身编程

你可能感兴趣的文章
移植Vim配色方案到Eclipse
查看>>
从超链接调用ActionScript
查看>>
谈谈加密和混淆吧[转]
查看>>
TCP的几个状态对于我们分析所起的作用SYN, FIN, ACK, PSH,
查看>>
网络游戏客户端的日志输出
查看>>
关于按钮的mouseOver和rollOver
查看>>
《多线程服务器的适用场合》例释与答疑
查看>>
Netty框架
查看>>
Socket经验记录
查看>>
对RTMP视频流进行BitmapData.draw()出错的解决办法
查看>>
FMS 客户端带宽计算、带宽限制
查看>>
在线视频聊天(客服)系统开发那点事儿
查看>>
SecurityError Error 2148 SWF 不能访问本地资源
查看>>
Flex4的可视化显示对象
查看>>
Flex:自定义滚动条样式/隐藏上下箭头
查看>>
烈焰SWF解密
查看>>
Qt 静态编译后的exe太大, 可以这样压缩.
查看>>
3D游戏常用技巧Normal Mapping (法线贴图)原理解析——基础篇
查看>>
乘法逆元
查看>>
STL源码分析----神奇的 list 的 sort 算法实现
查看>>