极客小将

您现在的位置是:首页 » scratch编程

资讯内容

浅谈Scratch的舞台刷新机制 Part 2——在常规积木中的应用

极客小将2021-01-13-
“ 简单来说,我们之所以能从各种屏幕上看到画面的动态变化,都是由于屏幕在进行不断地刷新——不断地快速切换静态的画面,由于视觉暂留效应,给人产生画面动态变化的“错觉”。在Scratch中,可以通过舞台观察到角色的运动等动态效果,那么,Scratch的舞台是

 简单来说,我们之所以能从各种屏幕上看到画面的动态变化,都是由于屏幕在进行不断地刷新——不断地快速切换静态的画面,由于视觉暂留效应,给人产生画面动态变化的“错觉”。在Scratch中,可以通过舞台观察到角色的运动等动态效果,那么,Scratch的舞台是否也可以看做是一个小屏幕呢?本文将对于Scratch舞台的刷新机制进行讨论。

在浅谈Scratch的舞台刷新机制 Part 1——自制积木的不刷新屏幕功能一文中,介绍了“运行时不刷新屏幕”功能的原理及其应用。此外,关于舞台的刷新机制,在一般积木中也有涉及,本文将会讨论舞台的刷新机制在一般积木中的应用及其实现原理。


01

案例演示

舞台通过不断刷新,才能让用户看到角色的变化,不论是运动也好,造型也罢,可以说舞台刷新是Scratch重要的底层功能。那么除了“在运行时不刷新屏幕”还有哪些地方可以利用舞台的刷新机制呢?或者说,关于舞台的刷新机制还有哪些tips呢?别急,我们对于舞台的刷新机制还不够了解,先来思考一个问题。

http://caiji.nai.plus/data/images/2021-01-13/7fad044b0e42bae156082e0aa5d80e1c.jpg

为什么【重复执行】配合【移动()步】积木可以实现角色在舞台上移动的效果呢?为什么我们可以看到角色移动的过程呢?为什么角色不是“嗖”一下就从舞台左侧闪到舞台右侧呢?也许初学者会被这样告知,是因为程序的执行有一个延迟时间,每次移动都会延迟一小会儿,这样就能看到移动的过程了。那么这种说法是否正确呢?再来看两段代码吧https://cdn.china-scratch.com/Public/Home/images/grey.gif

http://caiji.nai.plus/data/images/2021-01-13/043b9ea6532c6b1c21f2b22912d0b8ff.jpg

右转90度,循环4次

http://caiji.nai.plus/data/images/2021-01-13/ff75e0cae9f9ecb66a3042e6e2e6f796.jpg

右转90度,顺序执行

两段代码在逻辑上可以说是一样的,他们的运行结果也是一样的,那展示它们到底意义何在?

https://cdn.china-scratch.com/timg/190801/1334252D7-4.gif

循环结构效果

https://cdn.china-scratch.com/timg/190801/1334261502-5.gif

顺序结构效果

尽管两段代码在逻辑上几乎一致,结果也一模一样,但是他们的运行过程有着天壤之别。在循环结构中,可以看到角色旋转的过程,而在顺序结构中,程序像是没有执行。


02

解释

结合上一篇中关于“运行时不刷新屏幕”功能的讲解,对于这个现象应该并不陌生,也很好解释,其实程序是执行了的,只是在执行时没有刷新屏幕罢了,依次右转四次,刚好是一周,又回到了原来的位置,尽管执行完毕后舞台进行了一次刷新,但是“为时已晚”,看起来程序像是未曾运行过一般。

基于这两种不同的现象,我的推论是,顺序结构的代码,在执行过程中,都不会刷新舞台,只有在执行完最后一块积木后,才会进行刷新;而循环结构的代码,每一轮循环都会刷新一次舞台,如循环结构中角色的旋转效果,每执行完一次右转的代码,当轮循环结束,舞台刷新一次,如此我们就会看到角色旋转的过程了。循环结构不能单独存在,循环结构中必然包含顺序结构,所以本质还是顺序结构执行完后对舞台进行刷新。


03

延伸

在顺序结构中,程序必然是只有执行完最后一块积木才会刷新舞台吗?这种说法,可以说对,也可以说不对。

https://cdn.china-scratch.com/timg/190801/13342G055-6.gif

【等待()秒】积木对于顺序结构中舞台刷新的影响

即使是在顺序结构中,代码也不总是只有执行完最后一块积木才刷新舞台的,【等待()秒】积木可以打破这种顺序结构中不刷新屏幕的默契,强行使其刷新,类似地,其他还有【等待()】(条件成立)积木、【说()()秒】积木、【思考()()秒】积木,凡是会使程序进入“阻塞”状态的积木,都会使屏幕刷新。写到这里我忽然恍然大悟,对于舞台刷新的认识,更加证实了我之前对于【等待()】(条件成立)积木的认识,也就是在2.0中我们熟悉的【在()之前一直等待】积木。篇幅有限,亦不是主题,直接上结论:【等待()】(条件成立)积木的本质就是【重复执行直到()】积木的变形。

http://caiji.nai.plus/data/images/2021-01-13/d4f12ca1455ea081b2ead8ca6e5bb9bf.jpg

http://caiji.nai.plus/data/images/2021-01-13/72ce2b785c897c6b69f818351f90f732.jpg

【等待】的本质是循环执行一段空的代码,直到条件成立,跳出循环

如图所示两段代码首先在效果上是完全等价的,其次表现也是完全一样的。在Scratch中,只有正在执行的代码才出现高亮黄色边缘,三种循环如此,各种等待积木亦是如此。因此【等待】积木的本质是循环执行一段空的代码,直到条件成立,跳出循环。现在又多了一条理由:循环结构的代码才会在程序执行过程中不断刷新屏幕,【等待】积木会在顺序结构中强制刷新屏幕,因此【等待】的本质就是循环。还可以推断出如下结论:

http://caiji.nai.plus/data/images/2021-01-13/d32f48008ce39132ab4b26da0897a565.jpg

http://caiji.nai.plus/data/images/2021-01-13/44dacbb4a85481cf87c970f2eac4d3c8.jpg

【等待()秒】的本质也是等待条件成立,只不过在这里条件是时间


http://caiji.nai.plus/data/images/2021-01-13/e9249bf41b375fd75f9fef9eb8e9d607.jpg

【等待()秒】也可以看做是一种循环

回到我们的主题——舞台刷新,为何那些使程序进入阻塞状态的积木,如等待()秒,也可以使舞台刷新,现在看来似乎是理所应当的了,因为他们的本质都是循环。

至于【重复执行】配合【移动()步】积木可以让用户看到角色在舞台上移动的过程,其原因确实是由于循环结构导致的,每移动一次,完成一轮循环,舞台就刷新一次,周而复始,用户就可以观察到角色移动的过程了。


04

辟谣

至于延迟时间的说法,其实是由于在循环时,舞台会被刷新,刷新舞台才能看出移动的过程。而在刷新舞台的过程中,有一个附赠品——时间的消耗,刷新舞台需要消耗一定的计算资源,计算机在执行更底层的舞台重绘时需要花费一定的时间。这仅仅是舞台刷新的一个附赠品,而舞台刷新的真正任务是使用户观测到角色的运动过程,因此那些关于积木内部延迟时间的讨论并无意义,其实测算出来的是舞台刷新所需的时间。就如A直接产生B现象,A又顺带产生了C现象,人们观测到了C现象,就直接下定论说是C导致B。这是一种人们在探索未知领域中常犯的错误,也许本文所讨论的、得出的结论亦是一种类似这样的错误也说不定呢?https://cdn.china-scratch.com/Public/Home/images/grey.gif


05

应用1

总结了这么多看似没有实际用处的推论,总该写一些具有使用价值的东西了吧?

https://cdn.china-scratch.com/timg/190801/1334302260-13.gif

污渍擦除

http://caiji.nai.plus/data/images/2021-01-13/7ea5344fad06bcc0ab6c2f2edf5d573c.jpg

抹布角色带有一个和背景颜色相同的纯色块造型

http://caiji.nai.plus/data/images/2021-01-13/8015a4e06185ced3abbe7a9516f6c2c2.jpg

根据上文得出的结论,顺序结构不刷新舞台,因此切换成纯色块造型时,舞台是没有刷新的,用户也是看不到效果的。在执行完移到鼠标时针和图章的代码后,舞台依旧没有刷新,最后切换回抹布造型,这时候顺序结构执行完毕,刷新舞台,用户只能看到最终的造型——抹布,而看不到之前的造型切换过程。而在执行图章代码时,在舞台中留下的“印记”是“当前”造型,也就是纯色块,因此抹布能将纯色涂抹在舞台中,实现遮盖住污渍的效果,而自身造型看起来不发生改变。


06

应用2

接下来介绍另一个关于舞台刷新的应用技巧——碰撞块

在制作案例时,尤其是一些游戏类的案例,常常会用到碰撞侦测,在角色碰到其他对象时,通过后续代码控制其相应的行为。而角色往往又不是一些常规的几何图形,边缘不光整,所以在碰撞侦测时会产生穿墙BUG,面对这种情况,我们可以使用一种我称之为碰撞块的技巧。以坦克对战为例:

http://caiji.nai.plus/data/images/2021-01-13/1063e528ace671c6e80c86896c99b236.jpg

在控制坦克移动时,一旦碰到墙壁,则后退一定距离,但是由于坦克是个不规则图形,往往在实际操作中会倒退进墙壁内部从而产生穿墙BUG

http://caiji.nai.plus/data/images/2021-01-13/9edd69ce1e4564b856baacb6e2b44c99.jpg

解决方法是给坦克创建一个边缘规则的“碰撞块”造型

http://caiji.nai.plus/data/images/2021-01-13/199ee299d5bbb1dec724de7bf45d69c4.jpg

在执行碰撞侦测等代码之前,先切换成碰撞块造型,在最后将造型切换回坦克造型即可。此时在用户眼前呈现的始终是坦克的造型,而在执行中间的代码时却是以碰撞块造型去进行碰撞侦测的,不会产生穿墙BUG


在了解了舞台刷新机制及其应用技巧后,别忘记额外的小收获:Scratch中所有的“等待”,也许其实都是由循环模拟出来的。

声明:本文章由网友投稿作为教育分享用途,如有侵权原作者可通过邮件及时和我们联系删除

网友点评

共有5条评论来说两句吧...