为什么标题要叫做“滴答作响的时钟机制”呢?
想必我们大家都玩过俄罗斯方块,那些不同形状的东西,就是哪些不同形状,你懂的,会随着游戏级别的提高而下降的越来越快。是的 ,我们也要模仿那样,做出我们自己的时钟机制。
我们可以看到SKScene里面有一个函数
update(currentTime: CFTimeInterval)。 这个函数被没一帧所调用。帧,frame, 是什么? 你可以理解一帧就是一副静态的图片,如果很多图片在很短的时间内连续播放,就成了动画。当你的眼睛开始去预知每一帧图像的时候,你的游戏会看起来有些慢,我们来看下面的这个GIF图片,你是不是会觉得60fps的时候那个球看起来跑的没有下面的球块一样?
我特意去查了一下什么叫 motion blur , 其实就是摄影里面的慢速快门一样。
ok介绍完帧,我们来修改我们GameScene中的update函数,照着下面这个图修改吧:
好的,让我们继续来分段讲解下这次的更新吧。
#1
首先我们定义了一个常量,TickLengthlevelOne, 这个常量将会用来显示我们最慢的游戏速度,因为每一幅图片之间的间隔越长,它就看起来越慢,对吧?
我们先把它设置成600毫秒,也就是说每隔0.6秒,我们的形状将会往下掉落一行。
#2
我们定义了一些新的变量。
tickLengthMillis和lastTick很简单,我们之前已经遇到过这样的定义方式。第一个被赋予之前我们已经定义过的常量TickLenghtLevelOne;第二个用来表示我们最后一次记录的时间,一个NSDate类型的实例。
但是,但是,你知道tick:(()->())? 是个什么么?它看起来确实非常诡异的。
tick其实是一个在swift被叫做闭包(closure)的东西,如果你熟悉object-c ,那么闭包就是那里面的块(block)。
之前我们已经接触过函数的定义方式,知道了 -> 这个符号的意思,那在tick里面,(()->())? 表示这个闭包不需要参数,也不返回任何东西。因为它是optional的,所以它当然有可能是nil。
刚开始学的时候,我对这个()->()百思不得其解,它不需要任何参数,它又返回了noting,那它是干嘛的?后来没憋住上Stackoverflow上问了有位大神的回复让我总算明白了它的含义。
是的,在这里,到目前为止,我们这个tick,指向函数的你叫它变量也好,叫它指针也罢,我们叫它closure;目前为止,这个closure没有什么意义,它就是一个占位的,告诉你这里是有个东西的,当然,到项目的中期,我们的tick 闭包就会派上用处了。
所以大家不要急,你可以认为这里的closure就是个占位符,好比我先把楼给占了,等我想好说什么了我在说,而且这次觉得说的不好,我还可以换,就这么nb。
我也推荐另外一个中文翻译的
你可以在那里看到更多神奇的特性
#3
让我们接着往下看,我们将会引入一个新的变量。
如果lastTick是nil,那么我们当前处于一个暂停状态,所以我们直接return就好了,不需要做任何动作;但是如果不是,说明目前游戏是在进行中的,我们得做点什么东西。
timePassed这个变量从它的名字上就能看出来是表示过去了多久的一个变量,过去多久,和啥时候作为参照呢?把lastTick和now作为比较,因为lastTick记录的是最后一次记录的时间点,那它相对现在肯定是倒退的,所以,timeIntervalSinceNow这个函数可以返回和当前的时间比相差多少。因为是过去的时间点,所有这个值肯定是负数,而且单位是毫秒,所以我们需要*
-1000 把它变成一个正的而且单位是秒的数,因为我们的tickLengthMillis可是0.6秒。
也就是说 如果现在的时间和最后一次记录的时间间隔超过了0.6秒,我们就执行接下来的动作:
记录下当前的时间,然后tick一下;
在现在这个阶段,因为tick是个真正空的东西,所以不会发生什么,但是你要知道,它是可以发生点什么的,只要我们赋予tick某个函数就行了。
因为我们用到了lastTick.timeIntervalSinceNow, 所以感兴趣的东西学深入学习一下swift的dot语法
呐,我们还注意到其实这个tick写法是有讲究的,?是在()前的,这样的写法是我们首先检查下tick是否存在,如果存在再调用它,如果不存在就没有必要调用了,它等同于下面的代码:
#4
这里的两个函数都比较简单,调用start,因为lastTick不在是nil ,scene将开始刷新屏幕; 调用stop后 update函数将一直返回,所以就不在刷新屏幕