中级篇——Pong1

【疑惑篇】

点击绿旗按钮开始游戏,通过“w”和“s”键控制红色球拍,通过“↑”和“↓”键控制蓝色球拍。

视频演示open in new window

亲自操作open in new window

想一想: 如何修改游戏的难度?

【线索篇】

案例分析

它们发生的场景是什么?

每个场景中有哪些角色?

每个场景中的每个角色在做什么?

  1. 点击绿旗,重复播放背景音乐。红球拍、蓝球拍、小球移动到舞台初始位置,隐藏数字倒计时。
  2. 红球拍和蓝球拍通过说话,提示玩家操作方法。
  3. 开始数字倒计时。
  4. 倒计时结束,通过“w”和“s”键控制红球拍上下移动,通过“↑”和“↓”键控制蓝球拍上下移动。
  5. 小球以某个随机方向,开始在舞台左右两侧来回移动,碰到舞台上下边缘和两个球拍就反弹。
  6. 获胜判断。红球拍未接住球(小球超出红球拍左侧位置),蓝色获胜。蓝球拍未接住球(小球超出蓝球拍右侧位置),红色获胜。

积木提示

当绿旗被点击

移动(10)步

移到x:(0) y:(0)

面向(90)方向

将旋转方式设为[左右翻转]

碰到边缘就反弹

将x坐标设为(0)

将y坐标增加(10)

将y坐标设为(0)

x坐标

y坐标

方向

说(你好!)(2)秒

说(你好!)

换成([造型1])造型

下一个造型

显示

隐藏

播放声音([喵])等待播完

播放声音([喵])

当接收到[消息1]

广播[消息1]

等待(1)秒

重复执行

如果<>那么

如果<>那么否则

停止[全部脚本]

碰到([鼠标指针])?

碰到颜色(颜色)?

按下([空格])键?

([舞台])的[背景编号]

加法

减法

乘法

除法

在(1)和(10)之间取随机数

大于

小于

等于

注意事项

  1. 小球碰到球拍如何反弹?
  2. 如何判断是否获胜?

【解决篇】

乒乓球作为中国的国球,相信是许多人童年最早接触的球类运动。在电子游戏历史中,也有一款类似的经典游戏《Pong》,它是历史上第一个大型电玩电子游戏。

游戏模拟了现实的乒乓球运动,玩家需要控制两侧的球拍上下移动来反弹乒乓球,当一个玩家未能反弹,对方就会得一分,最终哪个玩家得分高获得胜利。

在中级篇的第一个案例中,我们就来一起实现一个简易版的《Pong》游戏。

第一步,还是把用到的背景Blue Sky添加进来。

第二步,添加角色。

先从角色库中选中Ball角色。

再利用绘图工具,画出球拍和倒计时。球拍有红蓝两个角色,倒计时有数字321三种造型。

第三步,使用指令积木实现程序。

1. 点击绿旗,重复播放背景音乐。红球拍、蓝球拍、小球移动到舞台初始位置,隐藏数字倒计时

第一个问题,如何播放背景音乐?相信你应该能立马想到播放声音([喵])等待播完积木和播放声音([喵])积木吧。

在播放背景音乐时会有一个问题,因为玩家的游戏时间是不固定的,假如说它玩的时间很长,你却选择了一个时长比较短的背景音乐,可能游戏还没有结束,音乐就先结束了。为了解决这个问题,你是不是就需要想办法让音乐不停的循环播放,如何实现呢?是不是只需要增加一个重复执行积木,让音乐重复不停的播放就可以了。那这时候在重复执行积木里面应该放入哪个播放声音的积木呢?或者两个积木都可以使用?你可以自己尝试一下,再想一想为什么会这样。给你一个小提示,我们的背景音乐需要每次播放完毕以后,再开始下一次播放。

现在还有一个问题,应该由谁来负责播放背景音乐?在这里你可以让任意一个角色来执行它。不过播放背景音乐这件事并不属于某个角色的任务,它更像是游戏导演需要统筹管理的事情,因此在这里我推荐你可以将它放在舞台中,把舞台当做一个导演,统一管理。

其他几个角色就很简单了,使用当绿旗被点击事件积木开始游戏,再使用移到x:(0) y:(0)积木将它们放到各自的初始位置上,倒计时的数字使用隐藏积木先隐藏起来。

2. 红球拍和蓝球拍通过说话,提示玩家操作方法。

这一步也很简单,使用说(你好!)(2)秒积木让它们说出各自的操控规则。

3. 开始数字倒计时。

如何开始数字倒计时?是不是只需要将倒计时角色显示出来,然后利用换成([造型1])造型积木或者下一个造型积木每隔一秒钟将它的造型切换成对应的数字即可。

需要注意的是,倒计时是在球拍说完话以后才开始出现,所以需要先用等待(1)秒积木让倒计时角色等待球拍说完话,再用显示积木让它显示出来。

倒计时结束之后,记得使用隐藏积木再将它隐藏回去。

4. 倒计时结束,通过“w”和“s”键控制红球拍上下移动,通过“↑”和“↓”键控制蓝球拍上下移动。

在这一步中,有两个关键的问题。一是,球拍怎么知道倒计时结束了?二是,如何通过按键控制球拍上下移动?

要解决第一个问题,一个最简单的方法,是不是像上一步一样,只需要计算一下倒计时总共花了多少时间,让球拍使用等待(1)秒积木等待相应的时间即可。

例如,在这个案例中,倒计时3秒,就需要等待3秒钟,3秒过后就可以开始移动球拍。

这样做可以实现该功能,但是会有一个问题。假如说,在倒计时之前,你还想增加其他的游戏功能介绍,这时候需要等待的时间就会发生改变,你就需要去修改每个等待(1)秒积木中的时间参数。

有没有什么方法,可以让球拍角色不用去考虑倒计时角色做了什么,或者做了多长时间,只需要让倒计时角色像发令员一样发出一个通知,球拍收到通知时,就知道游戏已经开始,可以上下移动了。

这种由一个角色发出通知,其他角色接收通知的功能,就是我们中级篇中需要重点学习的内容,消息机制

想一想现实生活中,当你想要别人帮你做一件事情时,你是不是会跟对方说一句话,这句话就是你发送给它的消息。当对方听到你的话,也就是接收到这条消失后,就可以根据你说话内容的不同,去做不同的事情。

在Scratch的事件分类中,也有这样的积木块。当一个角色想要通知其他角色某件事时,就可以使用广播[消息1]积木发送一条消息。

其他的角色使用当接收到[消息1]积木就可以接收到对方发出的消息,在根据不同的消息内容,完成不同的任务。

与刚刚生活中不同的是,生活中你说的话可能只能被一个人听见,而Scratch中角色发出的消息,就像是使用了一个大喇叭进行广播,所有作品中的角色(包括发消息者本人)和舞台都可以听见这条消息。

回到上面的问题,球拍角色需要等待倒计时角色的任务完成后才开始执行,但是球拍并不知道倒计时什么时候才会结束。为了让它们之间进行沟通,当倒计时角色结束自己的任务后,就可以给球拍角色发送一条消息。

点击广播[消息1]积木参数中的新消息,就会出现一个消息对话框,里面输入需要发送的消息内容。例如,游戏中倒计时结束后需要通知球拍可以开始游戏了,因此消息的内容可以写成“开始游戏”。

输入消息内容后,点击确定,这时广播[消息1]积木参数中就会多出一条你刚刚输入的消息。

倒计时角色选中该消息进行使用,就能将它广播出去。

接下来就到了球拍角色这边。之前它是提前计算好倒计时角色花费的时间,再使用等待(1)秒积木等待相应时间后再继续执行后面的任务。

现在换成了消息机制,球拍就不需要再使用等待(1)秒积木。更改为使用当接收到[消息1]积木获取倒计时角色发出的消息。同样,参数需要选中倒计时发出的消息内容,也就是“开始游戏”。

这样一来,每当倒计时发出“开始游戏”消息时,该事件积木就会被启动执行。具体需要执行什么呢?就是我们需要解决的第二个问题,如何通过按键控制球拍上下移动?

或许你脑子里面立马想到的就是小猫抓球里面的方法。使用当按下[空格]键积木配合移动积木让球拍上下移动。

如果这样做的话,会有两个问题。第一个问题,使用这种方法,那怕倒计时还没有结束,玩家按下按键后,球拍也会移动。第二个问题,球拍移动的过程不够流畅,会有卡顿的感觉。

那除了上面这种方法,还有没有别的方法可以通过按键控制球拍移动呢?这时就要用到侦测分类中的按下([空格])键?积木了。

按下([空格])键?积木与当按下[空格]键积木很类似,都可以侦测出键盘中的某个按键是否被按下。

不同的是,当按下[空格]键是事件积木,每当所选按键被按下后就会启动该事件,从而执行它后面的指令。

按下([空格])键?积木类似于小猫抓球中使用的碰到([鼠标指针])?积木,当所选按键被按下时它就会返回true,没有被按下就返回false。

这样一来,利用如果<>那么积木配合它使用,你就可以在按键被按下时,执行相应的操作。

具体到红球拍,就是当“w”键被按下时,它就会向上移动,当“s”键被按下时,它就会向下移动。蓝球拍就是当“↑”键被按下时,它会向上移动,当“↓”键被按下时,它会向下移动。

具体怎样让角色上下移动?是不是在初级篇中你已经学会了很多不同的方法,自己把他们都拿来试试,看看各自有什么优缺点。

现在你就可以点击绿旗按钮,启动程序,看看到目前为止程序能不能按照我们预想的方式来执行。

点击绿旗后,角色先移动到各自的初始位置,接着球拍开始说明操作规则,接着倒计时出现,321倒计时结束,你开始按下相应的操作键,你会发现球拍只能移动很短的距离,接着就停止不动了。想一想这是为什么?

原因其实很简单,当倒计时发送消息后,当接收到[消息1]积木便开始执行,此时如果<>那么积木会去判断之前设置的按键是否被按下,如果被按下,就会让球拍上下移动。还记不记得在初级篇中我们经常说到,指令执行的速度非常快,只需要一瞬间如果<>那么积木就会执行完毕,所以球拍也只会在执行的这瞬间发生移动,之后无论你是否再按下按键,如果<>那么积木也不会重新执行。

现在知道了球拍不能移动的原因,你是不是就可以想出办法,让球拍一直保持移动了?

既然刚刚说到球拍不动是因为如果<>那么积木只执行了一次,如果想要球拍一直运动,只需要让如果<>那么积木一直重复执行就可以了。

重新点击绿旗按钮进行测试,倒计时结束,你可以正常通过按键控制球拍上下移动了。

现在请你暂停一下,自己尝试着通过按键去操控球拍移动,接着再通过按键去操作一下小猫抓球中小猫的移动,感受一下两者有什么不同?

在操作的过程中,你会不会有这样的疑问。假如同时按下“w”和“s”或者“↑”和“↓”,球拍会向哪边移动?

你可以自己动手试一试,你会发现当你同时按下两个按键时,球拍又会停在原地不动,为什么会这样?

原因和之前很类似,我们现在使用了两个如果<>那么积木对按键进行判断,当两个按键被同时按下时,球拍是不是会先向上移动,再向下移动,回到原来的位置。由于程序执行的速度非常快,你根本看不见移动的过程,仿佛球拍一直停在原地。有没有什么方法可以让你同时按下两个按键时,球拍也可以移动?

方法也很简单,停在原地是因为球拍同时满足了两个如果那么判断,现在只要改为同时按下时,让角色只满足一个如何那么判断就可以了。如何做呢?只需要将其中一个如果<>那么积木替换为如果<>那么否则积木就可以了。

这样一来,当角色会先判断有没有满足如果<>那么否则积木中的条件,满足了就移动,不满足再继续执行否则里面的条件判断。

现在球拍可以正常移动了,但是如果你一直按着某个方向键,又会发现一个新问题。当球拍一直向上或者向下移动时,它会跑出舞台外面。有没有什么方法可以让它保持在舞台中?

你是不是会想到小鱼游动中的那条小鱼,每当它游到舞台边缘时就会自动返回来,避免游到舞台外面。

同样的,你也可以对球拍使用碰到边缘就反弹积木,当它碰到舞台边缘时就会自动反弹回来。不过需要注意一个问题,反弹以后球拍的方向会发生改变,所以你还需要设置球拍的旋转方式,避免它发生倾斜。

除了上面这种方法之外,还有没有别的方法避免它移出舞台?

想一想我们在学习运动分类时一直重复的重点,角色的位置由它的坐标值决定。既然现在我们想让球拍保持在舞台中,是不是只需要限制它坐标值(y坐标)的范围就可以了。

你可以把球拍拖动了舞台顶部和底部,看看它此时的y坐标是多少,这两个坐标值就是球拍可以上下移动的y坐标范围。注意,因为你绘制的球拍大小可能和我不同,所以你的范围值也会和我的不同。

现在我们就需要想办法限制球拍的y坐标范围,让它始终保持在最大y坐标值和最小y坐标值之间,应该如何做?

还记不记得我们在小猫的降噪耳机中如何让汽车不停的在舞台中移动?其中一个方法是不是利用x坐标积木,不停的获取汽车x坐标值,接着使用如果<>那么积木和大于积木去判断它的x坐标有没有超出舞台右侧的坐标值,如果超出了,就将它移动到舞台左侧。

同样的,我们现在可以不停的使用y坐标积木获取球拍的y坐标值,接着使用如果<>那么积木和大于积木去判断它的y坐标有没有超出前面测量出来的范围,如果超出了,就将它移回范围内。

现在再点击绿旗按钮进行测试,球拍已经可以正常移动,并且保持在舞台范围内了。

5. 小球以某个随机方向,开始在舞台左右两侧来回移动,碰到舞台上下边缘和两个球拍就反弹。

接下来开始做小球的运动。首先,小球什么时候开始动?是不是跟球拍一样,到它接收到倒计时发出的“开始游戏”的消息时,小球就开始运动了。

接下来,小球是如何运动的呢?假如不考虑球拍的话,小球在舞台中移动的过程是不是和海底世界中的小鱼一样。

只是小鱼初始的方向是固定不变的,在这里为了增加游戏的趣味性,我们可以让小球的初始方向设置为某个范围内的随机值。例如,我将它的范围设置为60~120之间,你也可以根据自己的喜好随意调整。

如何让小球获取到这个范围内随机的方向值呢?你是不是能马上想到使用在(1)和(10)之间取随机数积木。这样一来,小球每次出发时的方向就会随机改变。

好了,现在你运行一下程序,小球已经可以在舞台内不停的移动了,当它碰到球拍时会直接穿拍而过。接下来,我们就需要考虑如何让小球不能穿越球拍,当它碰到球拍时,就像碰到舞台边缘一样反弹回去。

要实现这个功能你需要考虑两个问题。问题一,如何知道小球碰到了球拍?

是不是可以像小猫抓球中一样,使用如果<>那么积木配合碰到([鼠标指针])?积木,就可以知道小球是否碰到了球拍。

除此之外还有别的方法吗?

在侦测分类中还有一个与碰到([鼠标指针])?类似的积木,碰到颜色(颜色)?

使用碰到([鼠标指针])?积木时,当碰到该积木参数所选的角色,就会返回true,通知你,我已经碰到这个角色了。

使用碰到颜色(颜色)?积木时,你需要在参数中选择一个待判断的颜色,这个颜色可以是角色身上的颜色,也可以是舞台背景上的颜色。

在选择颜色时,你尽量使用积木底部的滴管工具从舞台中拾取,以保证拾取到的颜色值、饱和度和亮度,跟舞台上展示的颜色一模一样。如果这三个数值与舞台上的颜色有一点偏差,可能你用眼睛观察不出来它们之间有什么区别,但是程序却能知道它们是不同的颜色,从而做出与你预期不符的判断。

颜色选择完成后,一旦角色碰到了所选的颜色,该积木也会返回true,通知你,我已经碰到这种颜色了。

这样一来,我们就可以用以上两种不同的方式,来判断小球是否碰到了球拍。

问题二,如果小球碰到球拍,应该如何反弹回去?

小球移动的过程,会不停地朝着当前的方向值方向前进,只要当小球碰到球拍时,调整它的方向值,就可以让小球反弹回去。所以问题二就等同于这样一个问题,如果小球碰到球拍,方向值应该如何改变?

在Scratch中,当你使用碰到边缘就反弹积木时,角色碰到舞台边缘反弹的方向,就类似于光线反射的方向,也就是满足入射角度等于反射角度这个规律。

接下来就需要你自己动手试验一下,当小球碰到上下左右四个边缘时,它的方向值是如何变化的。你需要用纸笔像下面一样画出一个表格,然后给小球设置不同的初始方向值,看看当它碰到四周时,方向值会变为多少?

上边缘下边缘左边缘右边缘
碰撞前方向值0000
碰撞后方向值
碰撞前方向值45454545
碰撞后方向值
碰撞前方向值90909090
碰撞后方向值
碰撞前方向值135135135135
碰撞后方向值
碰撞前方向值180180180180
碰撞后方向值
碰撞前方向值-135-135-135-135
碰撞后方向值
碰撞前方向值-90-90-90-90
碰撞后方向值
碰撞前方向值-45-45-45-45
碰撞后方向值

除了我上面列出来的方向值以外,你还可以选择任意的方向值做实验,记录下来,然后观察方向值的改变有没有什么规律。记住,一定要亲自动手试一试,找到规律后再接着往下做。

假如你已经做完了实验,你会发现这样的规律。

当小球碰撞到左右两个边缘时,碰撞后方向值 = -碰撞前方向值,或者碰撞后方向值 = 360 - 碰撞前方向值

当小球碰撞到上下两个边缘时, |碰撞后方向值| = 180 - |碰撞前方向值|,符号保持不变。或者你也可以不考虑符号,直接使用碰撞后方向值 = 180 - 碰撞前方向值进行计算。

有了上面这两个方向值的变化规律,接下来我们就可以把球拍想象成舞台左右两侧边缘,如果小球碰到了球拍就要改变方向,反弹回去。根据上面的规律,当小球碰撞到左右两个边缘时,碰撞后方向值 = -碰撞前方向值,或者碰撞后方向值 = 360 - 碰撞前方向值。

点击绿旗按钮进行测试,小球碰到球拍后已经可以正常的反弹回去,同时你也会发现两个问题。

第一个问题是,当小球的碰撞前的方向刚好为90或者-90时,小球就会像海底世界中的鲨鱼一样,来回在一条直线上左右移动。这样两个球拍只要保持位置不变,游戏就永远不能分出胜负。

应该如何解决它?

一种简单的方式,你在计算碰撞后方向值时,除了按照上面的规律之外,还可以在增加一个随机值,这样就能让它反弹后不会一直在90和-90之间改变。

或者你还可以根据小球接触到球拍的不同位置,增加不同的方向值。

除此之外,你还可以发挥你的想象力,使用别的方法来调整小球反弹的方向值,让游戏变得更有趣。

第二个问题,当小球碰到球拍上下两侧的边缘时,会在球拍中间不停的来回打转。

这是因为小球改变方向移动后,依然还会触碰到球拍,这时就会再次调整方向值,造成不停的在球拍中间来回打转,直到小球离开球拍。如何解决这个问题呢?

一个简单的方式,如果小球碰到球拍时,除了调整方向,再修改一下小球的x坐标值,让它直接离开球拍。这样一来,小球就会从新的坐标位置反弹回去。

最后,为了增加游戏效果,还可以当小球碰到球拍时,播放一个音效,让游戏变得更生动有趣。

6. 获胜判断。红球拍未接住球(小球超出红球拍左侧位置),蓝色获胜。蓝球拍未接住球(小球超出蓝球拍右侧位置),红色获胜。

终于到了最后一步,现在我们需要来判断什么时候玩家才会获胜?是不是当小球移动到了球拍后面,已经无法接住球时,游戏就结束了。你可以想想舞台上有两条获胜的坐标线,具体这条线的x坐标值需要由你自己测试来决定,你只要保证这条线在球拍后面就行。当小球的x坐标超过这两条线的x坐标时,其中一方就获胜。

这时又要不停使用x坐标积木获取小球的x坐标进行判断,当它大于或小于获胜坐标线的x坐标值时,就使用说(你好!)积木说出哪方获胜。

除此之外,游戏已经结束,我们可以把正在运行的程序都停止掉。这时就要用到控制分类中的停止[全部脚本]积木。

它有三个选项,选择全部脚本时,相当于点击了舞台上方的停止按钮,舞台上显示的对话或者克隆体等都会消失。

选择这个脚本时,将会停止角色中该积木所在的指令串。例如,通常使用重复执行积木时,该指令串会一直不停的执行下去。如果你想要停止它,就需要在重复执行积木中放入停止[这个脚本]积木,程序一旦执行到它,重复执行积木就会停止运行。

选择该角色的其他脚本时,与选择这个脚本类似。不过此时将会停止运行的指令串是,角色所拥有的没有该积木的其他指令串。

例如,回到刚刚的问题。现在游戏已经结束,我们想要让其他角色的程序都停止运行。这里会有一个问题,现在只有小球知道游戏是否结束,所以它需要发送一条消息通知其他角色,消息的内容可以写成“游戏结束”。

这样一来,球拍收到这条消息时,就可以使用停止[该角色的其他脚本]积木结束其他指令串的运行,玩家就无法在控制球拍的移动。

舞台收到这条消息时,也可以使用停止[该角色的其他脚本]积木停止背景音乐,接着在播放一个结束音效。

小球自己也可以收到这条消息时,使用停止[该角色的其他脚本]积木结束其他指令串,这样小球就能停止移动。

好了,一个简易版的Pong游戏就完成了。接下来,你就可以自己思考一下,可以用哪些方式来调整游戏的难度,让游戏变的更加有趣。

想看更多学习案例,欢迎点击查看《Scratch 3学习手册》open in new window

想要获取所有案例源码和素材,以及获得我对你在学习中所遇问题的一对一解答,欢迎加入石头解忧杂货店

Last Updated:
Contributors: lanheixingkong