10浏览
查看: 10|回复: 3

[项目] 【花雕动手做】基于Kitronik可编程开发板之深色鸭子游戏

[复制链接]
【花雕动手做】基于Kitronik可编程开发板之深色鸭子游戏图1

Kitronik ARCADE 是一款由英国教育科技公司 Kitronik 精心打造的可编程游戏机开发板,专为编程教学与创客实践而设计。该设备原生支持微软的 MakeCode Arcade 平台,用户可通过图形化或 JavaScript 编程方式,轻松创建、下载并运行复古风格的街机游戏。

它集成了彩色 LCD 显示屏、方向控制键、功能按键、蜂鸣器和震动马达等交互组件,提供完整的游戏输入输出体验。无论是初学者进行编程启蒙,还是创客群体开发交互式作品,Kitronik ARCADE 都能作为理想的硬件载体,助力创意实现。

凭借其开源友好、易于上手、兼容性强等特点,该开发板广泛应用于中小学编程课程、创客工作坊、游戏开发教学以及个人项目原型设计,深受教育者与技术爱好者的喜爱。


【花雕动手做】基于Kitronik可编程开发板之深色鸭子游戏图2

驴友花雕  中级技神
 楼主|

发表于 2 小时前

【花雕动手做】基于Kitronik可编程开发板之深色鸭子游戏

作为学习、练习与尝试,这里创建一个深色鸭子的小游戏。
打开网页版:https://arcade.makecode.com/,设置项目名称:深色鸭子

JavaScript 实验代码

  1. namespace projectImages {
  2.     //% fixedInstance
  3.     export const stalagmite_small = image.ofBuffer(hex`e418180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0ee000000000000000000e0eedd0000000000000000eededddd000000000000e0eedddddd1d0000000000e0deddd11ddd1d000000e0eedd11dd11dd111d00e0eede1dd111d111dd111ddddddddd11d111d111d111dd001011d111d111d111dd11d1000000dd11dd11dd11d111d100000000001011dd11dd11dd00000000000000ddd11d111d0000000000000000001d111d00000000000000000000dd1d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000`);
  4.     //% fixedInstance
  5.     export const stalagmite_med = image.ofBuffer(hex`e41824000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eeee00000000000000000000000000000000eeeeeeee0000000000000000000000000000eeeeeeeededd000000000000000000000000e0eeeedddddddddd0000000000000000000000eeeeddddddddddddd1000000000000000000e0eedddddddd11dd1ddd110000000000000000eeddddddd111dd11dd1ddd11000000000000e0eede1dd11dd111d111dd11d1110000000000eedd11dd1dd11dd111d11dd111d11d000000e0dedd1d11d11111ddd111d11dd111d11d0000dd1d11111d11dd1111ddd11dd11dd111d11d0000000010111d111d1111dd111dd11dd11dd11d0000000000001d11dd1111dd111dd11dd11dd1110000000000000010d11111ddd11ddd11d111d11100000000000000000011d11dd111dd11d111d11100000000000000000000d011dd11dd11d111dd1100000000000000000000000010dd1d11d111dd1100000000000000000000000000101111dd11dd11000000000000000000000000000000111dd1dd110000000000000000000000000000000010dd1d11000000000000000000000000000000000000101100000000000000000000000000000000000000000000`);
  6.     //% fixedInstance
  7.     export const stalagmite_large = image.ofBuffer(hex`e4183000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0eeee00000000000000000000000000000000000000eeeeeeeede0000000000000000000000000000000000eeeeeede1dd1dd0000000000000000000000000000eeeeeededddddd1d11dd0000000000000000000000e0eeeeeededd1d1111dddd11dd000000000000000000eeeeeededddddddddd1d11d1dd11d1000000000000e0eeeededddddd1dd1dd1ddd1d11d1dd11d100000000eeeeeeeedddddd11dddd11dd1d11dd1111dd11d100e0eeeeeeddddd1dd1dd11d11dd1dd1dd11d11111dd1111ddeed1d11dd11d11d11d111d11d11d11d111d11111d11111001111111d11dd11d11d111d1111dd11d111d11111d11111000000d11d11d111dd1111dd1111d111d111d11111d11111000000000011dd11dd1111dd1111d111d111d11111d11111000000000000d011dd11d1dd1111dd11d111d11111d11d1100000000000000000011d11111111d11d111d11111d11d1100000000000000000000001111dd1d11dd11dd1111d11111000000000000000000000000001d11d11d11dd1111d11111000000000000000000000000000000d111d1dd1111d111110000000000000000000000000000000000dd1d1111dd1111000000000000000000000000000000000000000011dd11d10000000000000000000000000000000000000000001011dd00000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000`);
  8.     //% fixedInstance
  9.     export const stalagmite_xlarge = image.ofBuffer(hex`e41840000000000000000000000000000000000000000000000000000000000000e0eeee000000000000000000000000000000000000000000000000000000e0eeeedddd00000000000000000000000000000000000000000000000000eeeeeeddd1dddd00000000000000000000000000000000000000000000e0eeeededddddd11dddd0000000000000000000000000000000000000000eeeeeedddd11d1dddd1111dd0000000000000000000000000000000000e0eeeedd1dddddd11111dddd1111dd000000000000000000000000000000eeeeee1dd11d1111dd111d1111dd1d11d1000000000000000000000000eeeeeedddddd1d111d1111d11ddd1111dd1d11d100000000000000000000eeeedddddddd1d11dd11d11111d11ddd1111dd1d11d100000000000000e0eeeeddd1dd1d1d11dd11d111d11111d11ddd1111dd1d11d10000000000eeeede11d11d11dd11dd11d111d11dd11111d11ddd1111dd1d11d10000e0eeee1d11111d11dd11d111d111d111111dd11111111ddd1111d11d1111dddddd1111d11d111d11d111d111d111d11d111dd11d11d111dd1111d11d11110000000010111dd11d11d111dd11d111111d111d111d11d111dd1111d11d1111000000000000dd111111dd111d11dd11111d111d111d11d111dd1111d11d1111000000000000000000d011d111111d11d111111d111d11d111dd1111d11d111100000000000000000000000011d11d11d111d11d111d11d111dd1111d11d111100000000000000000000000000dd1d11dd11d111111d11d111dd1111dd1d1111000000000000000000000000000000000011dd11111d11dd11dd1111dd1d11110000000000000000000000000000000000000010dd1dd11dd11d1111dd1d11d100000000000000000000000000000000000000000000d111d1111111dd1111d1000000000000000000000000000000000000000000000000dd1111d11d1111dd000000000000000000000000000000000000000000000000000000d11111111d000000000000000000000000000000000000000000000000000000000010d11d`);
  10.     //% fixedInstance
  11.     export const stalagtite_small = image.ofBuffer(hex`e4181800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ee0e00000000000000000000ddee0e000000000000000000ddddedee0000000000000000d1ddddddee0e000000000000d1ddd11ddded0e0000000000d111dd11dd11ddee0e000000d111dd111d111dd1edee0e00dd111d111d111d11dddddddd1d11dd111d111d111d1101001d111d11dd11dd11dd000000dd11dd11dd11010000000000d111d11ddd00000000000000d111d1000000000000000000d1dd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000`);
  12.     //% fixedInstance
  13.     export const stalagtite_med = image.ofBuffer(hex`e418240000000000000000000000000000000000000000000000000000000000000000000000000000000000eeee000000000000000000000000000000000000eeeeeeee00000000000000000000000000000000ddedeeeeeeee0000000000000000000000000000ddddddddddeeee0e0000000000000000000000001dddddddddddddeeee000000000000000000000011ddd1dd11ddddddddee0e00000000000000000011ddd1dd11dd111dddddddee0000000000000000111d11dd111d111dd11dd1edee0e000000000000d11d111dd11d111dd11dd1dd11ddee0000000000d11d111dd11d111ddd11111d11d1dded0e000000d11d111dd11dd11ddd1111dd11d11111d1dd0000d11dd11dd11dd111dd1111d111d1110100000000111dd11dd11dd111dd1111dd11d1000000000000111d111d11ddd11ddd11111d0100000000000000111d111d11dd111dd11d1100000000000000000011dd111d11dd11dd110d0000000000000000000011dd111d11d1dd0100000000000000000000000011dd11dd1111010000000000000000000000000011dd1dd11100000000000000000000000000000011d1dd010000000000000000000000000000000011010000000000000000000000000000000000000000000000000000000000000000000000000000`);
  14.     //% fixedInstance
  15.     export const stalagtite_large = image.ofBuffer(hex`e4183000000000000000000000000000000000000000000000000000eeee0e000000000000000000000000000000000000000000edeeeeeeee00000000000000000000000000000000000000dd1dd1edeeeeee0000000000000000000000000000000000dd11d1ddddddedeeeeee0000000000000000000000000000dd11dddd1111d1ddedeeeeee0e00000000000000000000001d11dd1d11d1ddddddddddedeeeeee0000000000000000001d11dd1d11d1ddd1dd1dd1ddddddedeeee0e0000000000001d11dd1111dd11d1dd11dddd11ddddddeeeeeeee000000001111dd11111d11dd1dd1dd11d11dd1dd1dddddeeeeee0e0011111d11111d111d11d11d11d111d11d11d11dd11d1deedd11111d11111d111d11dd1111d111d11d11dd11d11111110011111d11111d111d111d1111dd1111dd111d11d11d00000011111d11111d111d111d1111dd1111dd11dd11000000000011d11d11111d111d11dd1111dd1d11dd110d00000000000011d11d11111d111d11d11111111d1100000000000000000011111d1111dd11dd11d1dd1111000000000000000000000011111d1111dd11d11d11d10000000000000000000000000011111d1111dd1d111d0000000000000000000000000000001111dd1111d1dd00000000000000000000000000000000001d11dd110000000000000000000000000000000000000000dd1101000000000000000000000000000000000000000000d10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000`);
  16.     //% fixedInstance
  17.     export const stalagtite_xlarge = image.ofBuffer(hex`e4184000eeee0e0000000000000000000000000000000000000000000000000000000000ddddeeee0e000000000000000000000000000000000000000000000000000000dddd1dddeeeeee00000000000000000000000000000000000000000000000000dddd11ddddddedeeee0e00000000000000000000000000000000000000000000dd1111dddd1d11ddddeeeeee0000000000000000000000000000000000000000dd1111dddd11111dddddd1ddeeee0e00000000000000000000000000000000001d11d1dd1111d111dd1111d11dd1eeeeee0000000000000000000000000000001d11d1dd1111ddd11d1111d111d1ddddddeeeeee0000000000000000000000001d11d1dd1111ddd11d11111d11dd11d1ddddddddeeee000000000000000000001d11d1dd1111ddd11d11111d111d11dd11d1d1dd1dddeeee0e000000000000001d11d1dd1111ddd11d11111dd11d111d11dd11dd11d11d11edeeee00000000001111d11d1111ddd11111111dd111111d111d111d11dd11d11111d1eeee0e00001111d11d1111dd111d11d11dd111d11d111d111d111d11d111d11d1111dddddd1111d11d1111dd111d11d111d111d111111d11dd111d11d11dd11101000000001111d11d1111dd111d11d111d111d11111dd11d111dd111111dd0000000000001111d11d1111dd111d11d111d111111d11d111111d110d0000000000000000001111d11d1111dd111d11d111d11d111d11d11d110000000000000000000000001111d1dd1111dd111d11d111111d11dd11d1dd000000000000000000000000001111d1dd1111dd11dd11d11111dd1100000000000000000000000000000000001d11d1dd1111d11dd11dd1dd01000000000000000000000000000000000000001d1111dd1111111d111d00000000000000000000000000000000000000000000dd1111d11d1111dd000000000000000000000000000000000000000000000000d11111111d000000000000000000000000000000000000000000000000000000d11d010000000000000000000000000000000000000000000000000000000000`);
  18. }
  19. namespace lighting {
  20.     let bandPalettes: Buffer[];
  21.     // The top row is just the palette, each row gets darker
  22.     const palette_ramps = image.ofBuffer(hex`e4100400ffff0000d1cb0000a2ff0000b3fc0000e4fc000045ce000086fc000067c80000c8ff000069c80000bafc0000cbff0000fcff0000bdfc0000ceff0000ffff0000`);
  23.     export interface LightAnchor {
  24.         x: number;
  25.         y: number;
  26.     }
  27.     export class LightSource {
  28.         anchor: LightAnchor;
  29.         offsetTable: Buffer;
  30.         width: number;
  31.         height: number;
  32.         constructor(public rings: number, public bandWidth: number, public centerRadius: number) {
  33.             const halfh = centerRadius + rings * bandWidth;
  34.             this.offsetTable = control.createBuffer((rings + 1) * halfh);
  35.             // Approach is roughly based on https://hackernoon.com/pico-8-lighting-part-1-thin-dark-line-8ea15d21fed7
  36.             let x: number;
  37.             let band: number;
  38.             let y2: number;
  39.             for (let y = 0; y < halfh; y++) {
  40.                 y2 = Math.pow(y, 2);
  41.                 // Store the offsets where the bands switch light levels for each row. We only need to
  42.                 // do one quadrant which we can mirror in x/y
  43.                 for (band = 0; band < rings; band++) {
  44.                     x = Math.sqrt(Math.pow(centerRadius + bandWidth * (band + 1), 2) - y2) | 0;
  45.                     this.offsetTable[y * rings + band] = x;
  46.                 }
  47.             }
  48.             this.width = halfh;
  49.             this.height = halfh;
  50.         }
  51.         apply() {
  52.             const camera = game.currentScene().camera;
  53.             const halfh = this.width;
  54.             const cx = this.anchor.x | 0;
  55.             const cy = this.anchor.y | 0;
  56.             let prev: number;
  57.             let offset: number;
  58.             let band: number;
  59.             // First, black out the completely dark areas of the screen
  60.             screen.fillRect(0, 0, screen.width, cy - halfh + 1, 15)
  61.             screen.fillRect(0, cy - halfh + 1, cx - halfh, halfh << 1, 15)
  62.             screen.fillRect(cx + halfh, cy - halfh + 1, screen.width - cx - halfh, halfh << 1, 15)
  63.             screen.fillRect(0, cy + halfh, screen.width, screen.height - (cy + halfh), 15)
  64.             // Go over each row and darken the colors
  65.             for (let y = 0; y < halfh; y++) {
  66.                 band = this.rings;
  67.                 prev = 0;
  68.                 offset = this.offsetTable[y * this.rings + band - 1]
  69.                 // Black out the region outside the darkest light band
  70.                 screen.mapRect(cx - halfh, cy + y + 1, halfh - offset, 1, bandPalettes[bandPalettes.length - 1])
  71.                 screen.mapRect(cx - halfh, cy - y, halfh - offset, 1, bandPalettes[bandPalettes.length - 1])
  72.                 screen.mapRect(cx + offset, cy + y + 1, halfh - offset, 1, bandPalettes[bandPalettes.length - 1])
  73.                 screen.mapRect(cx + offset, cy - y, halfh - offset, 1, bandPalettes[bandPalettes.length - 1])
  74.                 // Darken each concentric circle by remapping the colors
  75.                 while (band > 0) {
  76.                     offset = this.offsetTable[y * this.rings + band - 1]
  77.                     if (offset) {
  78.                         offset += (Math.idiv(randint(0, 11), 5))
  79.                     }
  80.                     // We reflect the circle-quadrant horizontally and vertically
  81.                     screen.mapRect(cx + offset, cy + y + 1, prev - offset, 1, bandPalettes[band - 1])
  82.                     screen.mapRect(cx - prev, cy + y + 1, prev - offset, 1, bandPalettes[band - 1])
  83.                     screen.mapRect(cx + offset, cy - y, prev - offset, 1, bandPalettes[band - 1])
  84.                     screen.mapRect(cx - prev, cy - y, prev - offset, 1, bandPalettes[band - 1])
  85.                     prev = offset;
  86.                     band--;
  87.                 }
  88.             }
  89.         }
  90.     }
  91.     export class LanternEffect implements effects.BackgroundEffect {
  92.         protected sources: LightSource[];
  93.         protected static instance: LanternEffect;
  94.         protected anchor: LightAnchor;
  95.         protected init: boolean;
  96.         public static getInstance() {
  97.             if (!LanternEffect.instance) LanternEffect.instance = new LanternEffect();
  98.             return LanternEffect.instance;
  99.         }
  100.         private constructor() {
  101.             bandPalettes = [];
  102.             for (let band = 0; band < 6; band++) {
  103.                 const buffer = control.createBuffer(16);
  104.                 for (let i = 0; i < 16; i++) {
  105.                     buffer[i] = palette_ramps.getPixel(i, band + 1);
  106.                 }
  107.                 bandPalettes.push(buffer);
  108.             }
  109.             this.sources = [];
  110.             this.sources.push(new LightSource(4, 12, 2))
  111.             this.sources.push(new LightSource(4, 13, 1))
  112.             this.sources.push(new LightSource(4, 13, 2))
  113.             this.setAnchor({ x: screen.width >> 1, y: screen.height >> 1 });
  114.         }
  115.         startScreenEffect() {
  116.             if (this.init) return;
  117.             this.init = true;
  118.             let index = 0;
  119.             game.onShade(() => {
  120.                 this.sources[index].apply();
  121.             })
  122.             let up = true;
  123.             game.onUpdateInterval(1000, () => {
  124.                 if (up) index++;
  125.                 else index--;
  126.                 if (index < 0) {
  127.                     index = 1;
  128.                     up = true;
  129.                 }
  130.                 else if (index >= this.sources.length) {
  131.                     index = this.sources.length - 2;
  132.                     up = false;
  133.                 }
  134.             })
  135.         };
  136.         setAnchor(anchor: LightAnchor) {
  137.             this.anchor = anchor;
  138.             this.sources.forEach(function (value: LightSource, index: number) {
  139.                 value.anchor = this.anchor;
  140.             });
  141.         }
  142.     }
  143. }
  144. enum ActionKind {
  145.     Walking,
  146.     Idle,
  147.     Jumping
  148. }
  149. let anim: animation.Animation = null
  150. let bottomImage: Image = null
  151. let projectile: Sprite = null
  152. let topImage: Image = null
  153. let gap = 0
  154. let mySprite: Sprite = null
  155. controller.anyButton.onEvent(ControllerButtonEvent.Pressed, function () {
  156.     mySprite.vy = -100
  157.     animation.setAction(mySprite, ActionKind.Jumping)
  158. })
  159. sprites.onOverlap(SpriteKind.Player, SpriteKind.Projectile, function (sprite, otherSprite) {
  160.     game.over()
  161. })
  162. scene.setBackgroundColor(9)
  163. effects.blizzard.startScreenEffect()
  164. mySprite = sprites.create(img`
  165.     . . . . . . . . . . b 5 b . . .
  166.     . . . . . . . . . b 5 b . . . .
  167.     . . . . . . . . . b c . . . . .
  168.     . . . . . . b b b b b b . . . .
  169.     . . . . . b b 5 5 5 5 5 b . . .
  170.     . . . . b b 5 d 1 f 5 5 d f . .
  171.     . . . . b 5 5 1 f f 5 d 4 c . .
  172.     . . . . b 5 5 d f b d d 4 4 . .
  173.     b d d d b b d 5 5 5 4 4 4 4 4 b
  174.     b b d 5 5 5 b 5 5 4 4 4 4 4 b .
  175.     b d c 5 5 5 5 d 5 5 5 5 5 b . .
  176.     c d d c d 5 5 b 5 5 5 5 5 5 b .
  177.     c b d d c c b 5 5 5 5 5 5 5 b .
  178.     . c d d d d d d 5 5 5 5 5 d b .
  179.     . . c b d d d d d 5 5 5 b b . .
  180.     . . . c c c c c c c c b b . . .
  181. `, SpriteKind.Player)
  182. mySprite.ay = 300
  183. anim = animation.createAnimation(ActionKind.Jumping, 25)
  184. anim.addAnimationFrame(img`
  185.     . . . . . . . . . . . . . . . .
  186.     . . . . . . . . . . . . . . . .
  187.     . . . . . . . . . b 5 5 b . . .
  188.     . . . . . . b b b b b b . . . .
  189.     . . . . . b b 5 5 5 5 5 b . . .
  190.     . b b b b b 5 5 5 5 5 5 5 b . .
  191.     . b d 5 b 5 5 5 5 5 5 5 5 b . .
  192.     . . b 5 5 b 5 d 1 f 5 d 4 f . .
  193.     . . b d 5 5 b 1 f f 5 4 4 c . .
  194.     b b d b 5 5 5 d f b 4 4 4 4 b .
  195.     b d d c d 5 5 b 5 4 4 4 4 4 4 b
  196.     c d d d c c b 5 5 5 5 5 5 5 b .
  197.     c b d d d d d 5 5 5 5 5 5 5 b .
  198.     . c d d d d d d 5 5 5 5 5 d b .
  199.     . . c b d d d d d 5 5 5 b b . .
  200.     . . . c c c c c c c c b b . . .
  201. `)
  202. anim.addAnimationFrame(img`
  203.     . . . . . . . . . . . . . . . .
  204.     . . . . . . . . . . b 5 b . . .
  205.     . . . . . . . . . b 5 b . . . .
  206.     . . . . . . b b b b b b . . . .
  207.     . . . . . b b 5 5 5 5 5 b . . .
  208.     . b b b b b 5 5 5 5 5 5 5 b . .
  209.     . b d 5 b 5 5 5 5 5 5 5 5 b . .
  210.     . . b 5 5 b 5 d 1 f 5 d 4 f . .
  211.     . . b d 5 5 b 1 f f 5 4 4 c . .
  212.     b b d b 5 5 5 d f b 4 4 4 4 4 b
  213.     b d d c d 5 5 b 5 4 4 4 4 4 b .
  214.     c d d d c c b 5 5 5 5 5 5 5 b .
  215.     c b d d d d d 5 5 5 5 5 5 5 b .
  216.     . c d d d d d d 5 5 5 5 5 d b .
  217.     . . c b d d d d d 5 5 5 b b . .
  218.     . . . c c c c c c c c b b . . .
  219. `)
  220. anim.addAnimationFrame(img`
  221.     . . . . . . . . . . b 5 b . . .
  222.     . . . . . . . . . b 5 b . . . .
  223.     . . . . . . . . . b c . . . . .
  224.     . . . . . . b b b b b b . . . .
  225.     . . . . . b b 5 5 5 5 5 b . . .
  226.     . . . . b b 5 d 1 f 5 5 d f . .
  227.     . . . . b 5 5 1 f f 5 d 4 c . .
  228.     . . . . b 5 5 d f b d d 4 4 . .
  229.     b d d d b b d 5 5 5 4 4 4 4 4 b
  230.     b b d 5 5 5 b 5 5 4 4 4 4 4 b .
  231.     b d c 5 5 5 5 d 5 5 5 5 5 b . .
  232.     c d d c d 5 5 b 5 5 5 5 5 5 b .
  233.     c b d d c c b 5 5 5 5 5 5 5 b .
  234.     . c d d d d d d 5 5 5 5 5 d b .
  235.     . . c b d d d d d 5 5 5 b b . .
  236.     . . . c c c c c c c c b b . . .
  237. `)
  238. anim.addAnimationFrame(img`
  239.     . . . . . . . . . . b 5 b . . .
  240.     . . . . . . . . . b 5 b . . . .
  241.     . . . . . . b b b b b b . . . .
  242.     . . . . . b b 5 5 5 5 5 b . . .
  243.     . . . . b b 5 d 1 f 5 d 4 c . .
  244.     . . . . b 5 5 1 f f d d 4 4 4 b
  245.     . . . . b 5 5 d f b 4 4 4 4 b .
  246.     . . . b d 5 5 5 5 4 4 4 4 b . .
  247.     . . b d d 5 5 5 5 5 5 5 5 b . .
  248.     . b d d d d 5 5 5 5 5 5 5 5 b .
  249.     b d d d b b b 5 5 5 5 5 5 5 b .
  250.     c d d b 5 5 d c 5 5 5 5 5 5 b .
  251.     c b b d 5 d c d 5 5 5 5 5 5 b .
  252.     . b 5 5 b c d d 5 5 5 5 5 d b .
  253.     b b c c c d d d d 5 5 5 b b . .
  254.     . . . c c c c c c c c b b . . .
  255. `)
  256. anim.addAnimationFrame(img`
  257.     . . . . . . . . . . b 5 b . . .
  258.     . . . . . . . . . b 5 b . . . .
  259.     . . . . . . b b b b b b . . . .
  260.     . . . . . b b 5 5 5 5 5 b . . .
  261.     . . . . b b 5 d 1 f 5 d 4 c . .
  262.     . . . . b 5 5 1 f f d d 4 4 4 b
  263.     . . . . b 5 5 d f b 4 4 4 4 b .
  264.     . . . b d 5 5 5 5 4 4 4 4 b . .
  265.     . b b d d d 5 5 5 5 5 5 5 b . .
  266.     b d d d b b b 5 5 5 5 5 5 5 b .
  267.     c d d b 5 5 d c 5 5 5 5 5 5 b .
  268.     c b b d 5 d c d 5 5 5 5 5 5 b .
  269.     c b 5 5 b c d d 5 5 5 5 5 5 b .
  270.     b b c c c d d d 5 5 5 5 5 d b .
  271.     . . . . c c d d d 5 5 5 b b . .
  272.     . . . . . . c c c c c b b . . .
  273. `)
  274. anim.addAnimationFrame(img`
  275.     . . . . . . . . . . b 5 b . . .
  276.     . . . . . . . . . b 5 b . . . .
  277.     . . . . . . b b b b b b . . . .
  278.     . . . . . b b 5 5 5 5 5 b . . .
  279.     . . . . b b 5 d 1 f 5 5 d f . .
  280.     . . . . b 5 5 1 f f 5 d 4 c . .
  281.     . . . . b 5 5 d f b d d 4 4 . .
  282.     . b b b d 5 5 5 5 5 4 4 4 4 4 b
  283.     b d d d b b d 5 5 4 4 4 4 4 b .
  284.     b b d 5 5 5 b 5 5 5 5 5 5 b . .
  285.     c d c 5 5 5 5 d 5 5 5 5 5 5 b .
  286.     c b d c d 5 5 b 5 5 5 5 5 5 b .
  287.     . c d d c c b d 5 5 5 5 5 d b .
  288.     . . c b d d d d d 5 5 5 b b . .
  289.     . . . c c c c c c c c b b . . .
  290.     . . . . . . . . . . . . . . . .
  291. `)
  292. animation.attachAnimation(mySprite, anim)
  293. game.onUpdateInterval(1500, function () {
  294.     info.changeScoreBy(1)
  295.     gap = randint(0, 3)
  296.     if (gap == 0) {
  297.         topImage = projectImages.stalagtite_small
  298.         bottomImage = projectImages.stalagmite_xlarge
  299.     } else if (gap == 1) {
  300.         topImage = projectImages.stalagtite_med
  301.         bottomImage = projectImages.stalagmite_large
  302.     } else if (gap == 2) {
  303.         topImage = projectImages.stalagtite_large
  304.         bottomImage = projectImages.stalagmite_med
  305.     } else {
  306.         topImage = projectImages.stalagtite_xlarge
  307.         bottomImage = projectImages.stalagmite_small
  308.     }
  309.     projectile = sprites.createProjectileFromSide(topImage, -45, 0)
  310.     projectile.top = 0
  311.     projectile = sprites.createProjectileFromSide(bottomImage, -45, 0)
  312.     projectile.bottom = scene.screenHeight()
  313. })
  314. game.onUpdate(function () {
  315.     if (mySprite.vy > 0) {
  316.         animation.setAction(mySprite, ActionKind.Idle)
  317.     }
  318.     if (mySprite.bottom > 120 || mySprite.top < 0) {
  319.         game.over()
  320.     }
  321. })
  322. scene.setBackgroundColor(3)
  323. const effect = lighting.LanternEffect.getInstance();
  324. effect.setAnchor(mySprite);
  325. effect.startScreenEffect();
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 2 小时前

【花雕动手做】基于Kitronik可编程开发板之深色鸭子游戏

MakeCode 深色鸭子游戏代码解读
这是一个带有复杂光照效果的平台跳跃游戏,玩家控制一只鸭子在洞穴中飞行,避开钟乳石和石笋障碍物。玩家控制一只鸭子在一个黑暗的洞穴中飞行,洞穴顶部和底部会随机生成不同大小的钟乳石和石笋。游戏具有独特的光照系统,创造出手持灯笼在黑暗中探索的效果。

代码结构分析

1. 图像资源定义 (projectImages命名空间)
游戏定义了8种不同大小的洞穴障碍物图像:

4种石笋(stalagmite):从地面向上生长

4种钟乳石(stalagtite):从顶部向下悬挂

每种障碍物都有小、中、大、超大四种尺寸,使用十六进制编码的图像数据。

2. 光照系统 (lighting命名空间)
这是游戏最复杂和独特的部分:

LightSource类
javascript
  1. export class LightSource {
  2.     constructor(public rings: number, public bandWidth: number, public centerRadius: number)
  3. }
复制代码

创建同心圆形的光照效果

使用数学计算生成光照衰减区域

支持多个光源叠加

光照算法
javascript
  1. // 基于PICO-8光照算法的实现
  2. for (let y = 0; y < halfh; y++) {
  3.     y2 = Math.pow(y, 2);
  4.     for (band = 0; band < rings; band++) {
  5.         x = Math.sqrt(Math.pow(centerRadius + bandWidth * (band + 1), 2) - y2) | 0;
  6.         this.offsetTable[y * rings + band] = x;
  7.     }
  8. }
复制代码

使用勾股定理计算每个光照带的边界

创建平滑的光照衰减效果

LanternEffect类
javascript
  1. export class LanternEffect implements effects.BackgroundEffect
复制代码

实现背景特效接口

管理多个光源并循环切换

提供动态的光照波动效果

3. 游戏核心逻辑
玩家控制
javascript
  1. controller.anyButton.onEvent(ControllerButtonEvent.Pressed, function () {
  2.     mySprite.vy = -100  // 向上跳跃
  3.     animation.setAction(mySprite, ActionKind.Jumping)
  4. })
复制代码

按下任何按钮使鸭子跳跃

设置跳跃动画状态

障碍物生成系统
javascript
  1. game.onUpdateInterval(1500, function () {
  2.     gap = randint(0, 3)  // 随机选择障碍物组合
  3.     // 根据gap值选择不同大小的钟乳石和石笋组合
  4. })
复制代码

每1.5秒生成一对新的障碍物

随机选择4种不同的障碍物大小组合

确保有足够的空间让鸭子通过

动画系统
javascript
  1. enum ActionKind {
  2.     Walking,
  3.     Idle,
  4.     Jumping
  5. }
  6. let anim: animation.Animation = null
  7. anim = animation.createAnimation(ActionKind.Jumping, 25)
复制代码

定义三种动画状态:行走、空闲、跳跃

创建包含6帧的跳跃动画序列

根据物理状态切换动画

4. 游戏机制
碰撞检测
javascript
  1. sprites.onOverlap(SpriteKind.Player, SpriteKind.Projectile, function (sprite, otherSprite) {
  2.     game.over()  // 碰到障碍物游戏结束
  3. })
复制代码

边界检测
javascript
  1. game.onUpdate(function () {
  2.     if (mySprite.bottom > 120 || mySprite.top < 0) {
  3.         game.over()  // 飞出屏幕上下边界游戏结束
  4.     }
  5. })
复制代码

计分系统
javascript
  1. game.onUpdateInterval(1500, function () {
  2.     info.changeScoreBy(1)  // 每1.5秒增加1分
  3. })
复制代码


5. 视觉效果设置
背景效果
javascript
  1. scene.setBackgroundColor(9)  // 设置背景颜色
  2. effects.blizzard.startScreenEffect()  // 启动暴风雪效果(模拟尘埃)
  3. 光照效果初始化
  4. javascript
  5. const effect = lighting.LanternEffect.getInstance();
  6. effect.setAnchor(mySprite);  // 将光源锚定在鸭子位置
  7. effect.startScreenEffect();  // 启动光照效果
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 2 小时前

【花雕动手做】基于Kitronik可编程开发板之深色鸭子游戏

通过模拟器,调试与模拟运行

【花雕动手做】基于Kitronik可编程开发板之深色鸭子游戏图1

【花雕动手做】基于Kitronik可编程开发板之深色鸭子游戏图3

【花雕动手做】基于Kitronik可编程开发板之深色鸭子游戏图2

实验场景记录

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail