上周, 我们讲了Microbit最重要的输出装置也就是LED显示屏, 只有25个像素点, 也就是Microbit的显示器. 我们还介绍了让一个像素点从第一行最左边的位置一直往右跑, 跑完第一行就换下一行, 当跑完25个像素点的时候又回到了第一个位置.
我们还可以让这个像素点绕着LED显示屏跑一周. 我们需要2组变量, 分别是像素点的当前位置 (x, y) 和 方向偏移量 (xoffset, yoffset). 比如当方向为右的时候, X偏移量为1, 而Y偏移量为0.
1 2 3 | let x = 0, y = 0; // 初始方向是右 let xoffset = 1, yoffset = 1; |
let x = 0, y = 0; // 初始方向是右 let xoffset = 1, yoffset = 1;
然后, 类似地使像素朝一个方向奔跑, 我们可以绘制和取消绘制像素, 再等待一些时间间隔.
1 2 3 4 5 6 7 | basic.forever(function() { led.plot(x, y); basic.pause(100); led.unplot(x, y); x += xoffset; y += yoffset; }); |
basic.forever(function() { led.plot(x, y); basic.pause(100); led.unplot(x, y); x += xoffset; y += yoffset; });
上面的Javascript代码将使像素点从(0, 0)-左上角向右移动, 当其位置超出了LED屏幕的最右边框, 它很快就会消失. 我们可以加个判断, 当它到达了右上角, 我们就改变方向偏移量-让它接下来往下跑.
1 2 3 4 5 6 7 8 9 10 11 | basic.forever(function() { led.plot(x, y); basic.pause(100); led.unplot(x, y); x += xoffset; y += yoffset; if (x == 4 && y == 0) { // 如果到达了右上角 xoffset = 0; yoffset = 1; // 往下跑 } }); |
basic.forever(function() { led.plot(x, y); basic.pause(100); led.unplot(x, y); x += xoffset; y += yoffset; if (x == 4 && y == 0) { // 如果到达了右上角 xoffset = 0; yoffset = 1; // 往下跑 } });
同样, 我们必须处理其它三个角落情况, 以使像素保持沿边缘奔跑而不会出现问题.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | basic.forever(function() { led.plot(x, y); basic.pause(100); led.unplot(x, y); x += xoffset; y += yoffset; if (x == 4 && y == 0) { // 右上角 xoffset = 0; yoffset = 1; // 方向向下 } else if (x == 4 && y == 4) { // 右下角 xoffset = -1; yoffset = 0; // 方向向左 } else if (x == 0 && y == 4) { // 左下角 xoffset = 0; yoffset = -1; // 上 } else if (x == 0 && y == 0) { // 左上角 xoffset = 1; yoffset = 0; // 右 } }); |
basic.forever(function() { led.plot(x, y); basic.pause(100); led.unplot(x, y); x += xoffset; y += yoffset; if (x == 4 && y == 0) { // 右上角 xoffset = 0; yoffset = 1; // 方向向下 } else if (x == 4 && y == 4) { // 右下角 xoffset = -1; yoffset = 0; // 方向向左 } else if (x == 0 && y == 4) { // 左下角 xoffset = 0; yoffset = -1; // 上 } else if (x == 0 && y == 0) { // 左上角 xoffset = 1; yoffset = 0; // 右 } });
代码和 Microbit 模拟器: https://makecode.microbit.org/_L4X75r3b4FUU
使用精灵对象
上面的代码可以正常工作, 但是有点冗长和复杂, 因为我们必须通过修改坐标和方向偏移来处理更改方向和移动像素. 我们可以使用精灵对象-这是一个面向对象的编程(OOP). 精灵可以被认为是一个像素点, 我们可以针对每个精灵对象调用几种方法, 例如 移动, 向左转, 向右转等. 还有一个 ifOnEdgeBounce() 方法可以让精灵碰到边后就向后转.
我们可以使用game.createSprite()方法来创建一个精灵. 参数 (x, y) 是精灵的初始位置.
1 2 3 4 5 6 7 8 9 | let pixel = game.createSprite(0, 0); basic.forever(function() { pixel.move(1); // 让像素点往它的方向前进一个点. if (pixel.isTouchingEdge()) { // 如果碰到了边 pixel.turnRight(90); // 就向右转90度. } basic.pause(100); }); |
let pixel = game.createSprite(0, 0); basic.forever(function() { pixel.move(1); // 让像素点往它的方向前进一个点. if (pixel.isTouchingEdge()) { // 如果碰到了边 pixel.turnRight(90); // 就向右转90度. } basic.pause(100); });
代码和 Microbit 模拟器: https://makecode.microbit.org/_b6q2d8Cym63P
但是, 它不能按预期工作, 虽然有点酷.
该代码背后的原因是: 当像素位于边缘时, 它将向右转. 拐角是边缘, 但是边缘本质上不是拐角. 我们可以通过添加一个函数来检查像素是否在拐角处来修复代码.
1 2 3 4 5 6 7 8 | function isAtCorner(pixel: game.ledSprite): boolean { const x = pixel.x(); const y = pixel.y(); return ((x == 0) && (y == 0)) || ((x == 0) && (y == 4)) || ((x == 4) && (y == 0)) || ((x == 4) && (y == 4)); } |
function isAtCorner(pixel: game.ledSprite): boolean { const x = pixel.x(); const y = pixel.y(); return ((x == 0) && (y == 0)) || ((x == 0) && (y == 4)) || ((x == 4) && (y == 0)) || ((x == 4) && (y == 4)); }
整个代码和模拟器: https://makecode.microbit.org/_VD17z4exrWED
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | let pixel = game.createSprite(0, 0); function isAtCorner(pixel: game.LedSprite): boolean { const x = pixel.x(); const y = pixel.y(); return ((x == 0) && (y == 0)) || ((x == 0) && (y == 4)) || ((x == 4) && (y == 0)) || ((x == 4) && (y == 4)); } basic.forever(function () { pixel.move(1); if (pixel.isTouchingEdge() && isAtCorner(pixel)) { pixel.turnRight(90); } basic.pause(100); }); |
let pixel = game.createSprite(0, 0); function isAtCorner(pixel: game.LedSprite): boolean { const x = pixel.x(); const y = pixel.y(); return ((x == 0) && (y == 0)) || ((x == 0) && (y == 4)) || ((x == 4) && (y == 0)) || ((x == 4) && (y == 4)); } basic.forever(function () { pixel.move(1); if (pixel.isTouchingEdge() && isAtCorner(pixel)) { pixel.turnRight(90); } basic.pause(100); });
我们使用 game.LedSprite 来指定 isAtCorner 函数的输入参数类型. 该函数的返回类型为布尔值-可以为TRUE或FALSE. 然后, 我们只能在拐角处和边处进行转弯. 请注意, 尽管我们将两个布尔表达式都放在此处以显示逻辑AND运算符(即&&)的用法, 但其实只要检查是否是角就足够了.
游戏的随机性
游戏需要随机性才好玩. 我们使用 Math.randomRange(from, to) 函数生成一个在范围为[from, to]的随机整数. 例如, 以下操作将使像素在LED屏幕中随机跳跃.
1 2 3 4 5 6 7 8 | let pixel = game.createSprite(0, 0); basic.forever(function () { const x = Math.randomRange(0, 4); const y = Math.randomRange(0, 4); pixel.goTo(x, y); basic.pause(100); }); |
let pixel = game.createSprite(0, 0); basic.forever(function () { const x = Math.randomRange(0, 4); const y = Math.randomRange(0, 4); pixel.goTo(x, y); basic.pause(100); });
代码和 Microbit 模拟器: https://makecode.microbit.org/_W64WXLEDX6Xq
使用精灵对象来设计一个吃苹果游戏
我们可以通过到目前为止所学的技能来制作一款好玩的游戏. 我们可以生成一个随机掉落的苹果, 然后我们需要捕捉/吃掉它. (很有意思, 在上课的时候突发奇想就写了这么一个小游戏)
1 2 | // 在第一行随机生成一个苹果对象 let apple = game.createSprite(Math.randomRange(0, 4), 0); |
// 在第一行随机生成一个苹果对象 let apple = game.createSprite(Math.randomRange(0, 4), 0);
然后, 我们可以将盘子最初放在中间的最后一行中:
1 | let pixel = game.createSprite(2, 4); |
let pixel = game.createSprite(2, 4);
然后, 我们可以使用两个按钮(按钮A和按钮B)向左或向右移动(一次移动一个像素)来控制盘子(接苹果的). 代码应如下所示很简单清楚:
1 2 3 4 5 6 7 | input.onButtonPressed(Button.A, function() { pixel.changeXBy(-1); }); input.onButtonPressed(Button.B, function() { pixel.changeXBy(1); }); |
input.onButtonPressed(Button.A, function() { pixel.changeXBy(-1); }); input.onButtonPressed(Button.B, function() { pixel.changeXBy(1); });
请注意, sprite.changeXBy(偏移量)方法用一个整数表示要更改的偏移量, 即位置将移动此偏移量. 同样, 我们有changeYBy()方法. 这两种方法将限制精灵在LED屏幕中的位置, 这意味着当像素的坐标X = 0时, 调用changeByX(-1)不会更改X坐标, 因为它已经在最左侧(第一列)并且限制在LED上 屏幕.
为了使游戏更加人性化, 我们可以通过允许平板像素倒退到另一侧(例如, 当像素位于最左边时, 您可以按A按钮转到最右边, 反之亦然. 这有时会缩短抓苹果的时间, 并且为用户提供了更多选择.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | let px = 2; let py = 4; input.onButtonPressed(Button.A, function () { px--; if (px < 0) px = 4; pixel.setX(px); }) input.onButtonPressed(Button.B, function () { px++; if (px > 4) px = 0; pixel.setX(px); }) |
let px = 2; let py = 4; input.onButtonPressed(Button.A, function () { px--; if (px < 0) px = 4; pixel.setX(px); }) input.onButtonPressed(Button.B, function () { px++; if (px > 4) px = 0; pixel.setX(px); })
我们还可以定义按钮A + B(同时按下)以重置游戏.
1 2 3 4 5 6 7 | input.onButtonPressed(Button.AB, function () { if (apple.y() == 4) { // 避免误操作 game.setScore(0); score = 0; apple.goTo(Math.randomRange(0, 4), -1); } }) |
input.onButtonPressed(Button.AB, function () { if (apple.y() == 4) { // 避免误操作 game.setScore(0); score = 0; apple.goTo(Math.randomRange(0, 4), -1); } })
在这里, 我们只在苹果落到地面上时重置游戏, 因此您在玩游戏时不会意外重置游戏. 然后我们将分数重置为零. 苹果还需要移动到另一个初始随机位置.
game.setScore(分数)设置内部游戏得分, 当您调用game.gameOver() 时会显示游戏最后得分. 该方法类似于以下内容:
1 2 3 | function gameOver() { basic.showString("Game Over, Score: " + score); } |
function gameOver() { basic.showString("Game Over, Score: " + score); }
我们定义了一个全局游戏得分变量-这不是强制性的, 因为我们可以使用game.addScore(score)或game.setScore(score)来更改/更改得分.
为了使游戏更具挑战性, 每当分数增加时(当您抓到一个苹果时), 我们就缩短延迟时间, 让苹果掉得更快一些.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | basic.forever(function () { apple.changeYBy(1); // 苹果下落一格 if (pixel.isTouching(apple)) { // 接到了 score++; apple.goTo(Math.randomRange(0, 4), -1); // 生成另一个随机苹果位置 } else if (4 <= apple.y()) { // 当苹果掉到地上了 basic.showNumber(score); game.setScore(score); game.gameOver(); } let delay = 500 - 10 * score; // 下落得越来越快 delay = Math.max(50, delay); // 最快的速度有限制 basic.pause(delay); }) |
basic.forever(function () { apple.changeYBy(1); // 苹果下落一格 if (pixel.isTouching(apple)) { // 接到了 score++; apple.goTo(Math.randomRange(0, 4), -1); // 生成另一个随机苹果位置 } else if (4 <= apple.y()) { // 当苹果掉到地上了 basic.showNumber(score); game.setScore(score); game.gameOver(); } let delay = 500 - 10 * score; // 下落得越来越快 delay = Math.max(50, delay); // 最快的速度有限制 basic.pause(delay); })
这是主要的游戏逻辑, 在主循环中, 苹果将首先下降1个像素. 然后我们使用sprite.isTouching(anotherSprite)方法(来判断两个精灵是否发生了碰撞检测)借此来检查是否捕获了它. 然后, 我们还检查应用的Y坐标是否大于或等于4-落在了地面上. 然后我们可以延迟一些时间间隔(延迟越来越短, 苹果掉落的速度越来越快).
通过使用Math.max()函数将最大下降速度限制为50, 该函数与以下相同:
1 2 3 | if (delay < 50) { delay = 50; } |
if (delay < 50) { delay = 50; }
这个吃苹果游戏代码和Microbit 模拟器: https://makecode.microbit.org/_DV93uT7i0WuK
游戏的可视化显示了该游戏的几大部件:
剑桥 Chesterton Community College – Coding Club
视频:
下一周, 我们将让 Microbit 拥有最简单的人工智能来玩这个游戏: Microbit 编程: 简易人工智能让电脑玩游戏
英文: Microbit Programming: How to Make a Catching-Apple Game by Using Sprites Objects?
loading...
上一篇: 在英国给孩子换学校的经历: 孩子离开了村里的小学
下一篇: 如果不知道投资啥就投资孩子吧
