Scratch第五十二讲:开心消消乐(CC哥版)
想免费学编程,就请点击上面的蓝字:跟我学Scratch编程,关注CC哥。
最近实在太忙,所以空了一周,关键也是一直在做这个小程序。这个消消乐真的是CC哥自己琢磨着编写的,没有参考任何其他人的材料,完全属于独创。做完之后还是小得意了一下。虽然还有很多地方没有去一一细化,好在为了教学,能讲明白就行。
先看看CC哥版的消消乐
虽然跟手游上的比还是差很多,不过作为教学已经很够用了。做这个游戏还是很费了一些脑子。平常我们去看别人的程序代码,就会觉得不复杂,或者是感觉就应该这样设计的。其实任何一个程序都有无数种方法去实现,哪种好,哪种不好,还真是很难说清楚。甚至做完了你都不知道你选的方法是不是最好的方法。在这个程序里,CC哥就反复了很多次,尝试了各种方法,下面就一一给你道来。
设计框架
第一步是要选择用什么方法来实现这一堆彩球。消消乐的思路就是通过相邻的彩球的交换,形成三个连起来的彩球,然后消除掉。那么用什么来做这一堆彩球呢?思路上有两个大的思路:
1:克隆
克隆就是这些彩球全部通过克隆来做。
2:图章
图章就是用图章的命令在桌面上画出应该的彩球。(CC哥前面有个俄罗斯方块的讲座就是全部用图章来做的。)
用图章做这个程序的工作量将主要放在画图上,和颜色的检测上。用克隆做程序的主要工作量就放在了克隆体的操作上。每个人习惯不同,我就更喜欢用克隆来做,这个强调的主要是逻辑和算法。用图章做是个细致活,实在不是CC哥的风格。大家没事可以自己试试。
我在scratch里选了小球的角色,9个一排,克隆了126个。总共5个造型,随机分布,看着还不错吧。
第二步:实现相邻之间的小球交换
小球交换就有几种情况:
1:选的球不是相邻的,那么就不能交换。
2:选的球是同色的,那么也不能交换。
3:选的球交换后,不能形成三个同色球在一起,那么还要换回原地。
第三步:消除同色的小球,上面的小球降落下来。
这里面难点包括:
1:如何检测上下左右有几个球是同色的。
2:这些小球是克隆体,如何消除这些特定的克隆体。
3:上面的小球如何降落下来,以及如何在空白位置补充新的小球。
有没有觉得不好做了?一开始CC哥觉得挺容易的,谁知道做起来还是挺绕的。这一讲CC哥不像以前那样一步一步给大家过代码,主要讲一下CC哥在编程过程中绕的圈子和最终的解决方式吧。如果大家对代码感兴趣,还是老规矩,帮CC哥分享,免费获取源代码。
126个球的标签
做这么多克隆体的管理,就必须要给克隆体打标签,这个技能CC哥很多讲座里都讲过了,通过克隆体的私有变量来做。但是这126个球的私有特征都有什么呢?
1:位置,我们要管理球动来动去,自然要标记位置。
2:颜色,这个也是必须标记的。
3:状态,球也是有状态的,变动过位置的球跟没变动过位置的球是有区别的,变动过位置的球就需要检测位置变动后有没有同色相邻球,而没有变动过位置的球就不需要检测。
为此,CC哥想到了列表,但是Scratch的列表是一维的,只能有一列,那怎么标记这么多种特征呢?而且位置本身就是个二维的,行和列。
为此,CC哥想到一个方法,用一个5位数字来表示球的信息,第一位是列,第二三位是行,第四位是颜色,第五位是状态。比如10120,就表示第一列第一排的蓝色小球。是不是很完美,一开始CC哥也满得意的,做到最后就有点蒙圈了。
scratch毕竟不是C语言,稍微一些复杂的数据的处理用这种图形命令就会写得非常复杂,不但容易错,而且错了也很难检查出来。
一个计算式屏幕都放不下,写得CC哥都快崩溃了。尤其是做到消除这一块时,我就知道这么做肯定不行了,因为通过列表里的状态信息来控制克隆体,算法实在是太复杂了,所以这条路走不通。
其实一开始我就觉得这么做有些问题,但是一开始也没法想那么细,每做一步都是一个小成功,当开始发现问题的时候,因为前面已经花了那么多时间,就不想放弃,推倒重来前面不是白做了。最后做到了第三步才发现实在是做不动了,逻辑过于复杂,bug多到根本找不完,解了一个bug,又增加几个bug。才不得不放弃。这就是我们经常碰到的沉默成本的问题。最后我还是全部推到重来,用了不到半天就把程序全部做完了。前面因为沉默成本,在错误的路上埋头坚持了两个晚上,想想多么愚蠢呀。
CC哥主要错在哪里了?就是用列表没错,错在信息标签做的太复杂。
其实就这么一列数据就够了,因为方框内就这么126个位置,所以从左到右从上到下个号,只要知道小球的编号,就完全可以算出小球在哪个位置上。所以列表的编号就是位置信息,每个编号就对应了一个克隆体。那么列表的内容只需要放这个克隆体的颜色信息就够了。而状态这个完全不需要再加一位进去,只需要把有过位置移动的小球信息单独再创建个列表就OK了。
对特定小球的控制
这个游戏里面大量的操作都是针对具体的克隆体进行控制,这里面有个特别的技巧,就是消息命令。大家一定要掌握。
针对克隆体的控制一般的做法都是用当作为克隆体启动时来做,里面套个无限循环,然后通过检测私有标签,来针对相应的克隆体做些动作,比如移动呀,碰撞检测呀等等。
但是缺点就是如果克隆体的操作逻辑次序比较复杂时,那么这个方法就不合适了,你会需要用大量的判断命令(控制命令),很容易出错。
而消息命令就是个非常不错的方法。
CC哥把针对小球的每一种控制都用消息来做,逻辑和编程就简单多了。逻辑很简单:
当你发布一条消息的时候,所有的克隆体都会同时收到,那么你只要在当接收到消息的代码中加上一条对私有变量的判断命令就ok了,符合这个判断条件的克隆体就会发生动作,不符合的克隆体就不会有动作。是不是很方便,大家一定要掌握这个技巧。
如何进行相邻球的同色检测
同色检测,以及检测完毕后面的一系列动作,都是基于列表来操作的。
克隆体之间的互动是个难点,你不论是用消息,还是当克隆体启动时来对克隆体进行控制,都是针对当前的克隆体,所以代码就只能操纵当前这个克隆体,而不能在一个克隆体的代码内去操纵其他的克隆体。如果真的需要,就只能在执行代码里重新发布消息,这样其他的克隆体才能接收到消息产生动作。编程就会变得复杂的多。
而通过列表就可以完美的解决问题,每一个克隆体对应列表里的一个数据,我们把希望做的逻辑和控制都在列表上做,对数据的操作,就相当于在克隆体之间进行逻辑和控制操作,当结果出来后,再针对结果通过消息来控制具体的克隆体做相应的动作就好了。
而且列表不是私有变量,完全可以在别的角色里面操作,更加灵活方便:
同色检测的逻辑就是检测具体的小球上下左右四个方向有没有同色连排的球,并把结果反馈回来。(因为有了列表,而且列表跟克隆体的私有信息一一对应,所以我们只要检测列表里面的数据就行了,不需要去检测克隆体)
因为我们不确定到底有几个小球相连,为了编程简单,我们用了递归的技巧,递归之前有专题讲座,如果不是太懂得朋友可以复习一下。
CC哥不像把编程逻辑做的太复杂,所以就用了四个自定义命令来检测上下左右四个方向。虽然代码多,但是逻辑简单哦。
我们编程的时候没必要为了代码的简单去可以去优化逻辑,大家一定记得,逻辑越复杂,bug越多的道理。
看只要知道一个小球的编号,减去9就是它上面小球的编号,加上9就是它下面小球的编号,多简单。
因为互换操作是两个球,每个球都可能发生同色球连排,所以两个球都要做,通过返回的上下左右四个变量来表示同色球的起始位置,只要右减左,上减下,就可以得出同色的球是否有三个以上,来判断是否要做下一步的消除同色球的操作了。
两球交换动作注意
为了表现两个球交换的动态效果,这两个克隆体的移动是真实发生的。当克隆体真实移动的时候,就必须注意克隆体的私有标识信息要跟列表同步好,如果忘掉这一步,那么列表和克隆体的对应就乱掉了。
清除同色球的操作
要说明一点,这个游戏的关键是除了两个球的交换CC哥用了克隆体的移动,其他的所有操作,都没有发生克隆体的移动。那么如何做到消除呢?只是简单的把小球的造型换了个空白的就实现了消除操作。
那消除后的空白,如果实现让上面的球落下来呢?也没有用克隆体位移,只是让上面所有的克隆体一起改变颜色就好了。视觉上看着就像是上面的小球都落下来了。
因为这些小球都是克隆体,而不是一个个具体角色,所以当要操作这些需要消除的角色时,还是要通过消息来操作。因为同色球的数量是不固定的,最简单的操作就是把所有要清除的同色球编号,都单独放在一个列表里。那么只需要一个简单的判断就可以通知对应的球来进行消除动作了。
就这么一条语句,每一个克隆体就知道自己是不是清除的对象了。为了有消除的视觉感,我做了几个对应的破裂的造型,做的有点糙,下次一定好好P一下。
消除并不是真的删除克隆体,而只是换了个空白的造型,屏幕看上去没有了。
如何让上面的球落下来
一样的情况,我们不是真的要让克隆体移动下来,只是要让克隆体的颜色变一下,造成下移的效果。(如果你真要做克隆体移动,估计会做崩溃掉的)那么哪些克隆体需要变颜色呢?
同样,我们不用针对克隆体去做逻辑运算,只要去针对列表就行了。
每一个被清除的球,我们都要去计算这个球以及其上面每一个球,在下落发生后应该是什么颜色。每计算完一个球,就把它从要清除的列表里删掉。(这种处理完就删除的操作的列表操作,为了简便,大家一定要从列表的尾部取,不要从头部取)
这段程序就是检测每一个要清除的小球上面一列所有的球,下落后应该对应的颜色。用的仍然是递归的算法。每一步只需要确认上方一个球的颜色,然后递归操作。
不确定循环次数的循环最好用递归
当列表更新完了,就出现了个问题,就是克隆体跟列表不能对应上了,所有改动过的列表项目跟克隆体的造型私有变量对不上了。那就剩下最后一步操作,把这两项同步就好了。
只要克隆体的颜色与列表不一样的,都以列表为准,同时切换到对应的造型,下移这么复杂的操作就很简单的完成了。
最后一步,就是把上面空出来的位置补上新球。也就是把空白造型切换成1~5的随机造型。
结束语
大家在学习编程的过程中,一定要实践,实践的过程也就是创造的过程,所谓实践,不是指去复现程序的例子,而是要从头到尾试着自己去编一些小程序。通过实践去验证自己的思路,不仅仅可以锻炼你的创造性,更可以锻炼你的逻辑的严谨性,还可以让你活用学过的技巧。
--end--
声明:本文章由网友投稿作为教育分享用途,如有侵权原作者可通过邮件及时和我们联系删除:freemanzk@qq.com