【花雕动手做】基于 Kitronik 可编程开发板之粒子效果
Kitronik ARCADE 是一款由英国教育科技公司 Kitronik 精心打造的可编程游戏机开发板,专为编程教学与创客实践而设计。该设备原生支持微软的 MakeCode Arcade 平台,用户可通过图形化或 JavaScript 编程方式,轻松创建、下载并运行复古风格的街机游戏。它集成了彩色 LCD 显示屏、方向控制键、功能按键、蜂鸣器和震动马达等交互组件,提供完整的游戏输入输出体验。无论是初学者进行编程启蒙,还是创客群体开发交互式作品,Kitronik ARCADE 都能作为理想的硬件载体,助力创意实现。
凭借其开源友好、易于上手、兼容性强等特点,该开发板广泛应用于中小学编程课程、创客工作坊、游戏开发教学以及个人项目原型设计,深受教育者与技术爱好者的喜爱。
【花雕动手做】基于 Kitronik 可编程开发板之粒子效果
作为学习、练习与尝试,这里创建一个粒子效果的小游戏。打开网页版:https://arcade.makecode.com/,设置项目名称:粒子效果
JavaScript 实验代码
interface ParticleDemonstration {
start(): particles.ParticleSource[];
}
// show controls
let ctlMessage = image.create(scene.screenWidth(), 10);
ctlMessage.printCenter("Effects: 'A' (+), 'B' (-)", 0, 0);
let msgSprite = sprites.create(ctlMessage);
let msgInterval = 0;
const myDemonstrations: ParticleDemonstration[] = [];
let count = 1;
controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
count = Math.min(count + 1, 6);
});
controller.B.onEvent(ControllerButtonEvent.Pressed, function () {
count = Math.max(count - 1, 1);
});
namespace demonstrations {
export class Fire implements ParticleDemonstration {
start() {
const sources: particles.ParticleSource[] = [];
const factory = new particles.FireFactory(8);
const src = new particles.FireSource(makeSimpleAnchor(), 100, factory);
src.setAcceleration(0, -40);
sources.push(src);
return sources;
}
}
export class Spinner implements ParticleDemonstration {
start() {
class RingFactory extends particles.RadialFactory {
createParticle(anchor: particles.ParticleAnchor) {
const p = super.createParticle(anchor);
p.lifespan = this.galois.randomRange(200, 350);
return p;
}
}
const sources: particles.ParticleSource[] = [];
const colors = ;
const factory = new RingFactory(20, 30, 10, colors);
const src = new particles.ParticleSource(makeSimpleAnchor(), 400, factory);
sources.push(src);
return sources;
}
}
export class BubbleConfetti implements ParticleDemonstration {
start() {
const sources: particles.ParticleSource[] = [];
const min = 1000;
const anchor = makeSimpleAnchor();
anchor.width = screen.width;
const bubbleFactory = new particles.BubbleFactory(anchor, min, min * 2.5);
sources.push(new particles.BubbleSource(anchor, 30, bubbleFactory.stateCount - 1, bubbleFactory));
const confettiFactory = new particles.ConfettiFactory(anchor.width, 16);
confettiFactory.setSpeed(50);
sources.push(new particles.ParticleSource(anchor, 50, confettiFactory));
return sources;
}
}
export class RadialGroup implements ParticleDemonstration {
start() {
const sources: particles.ParticleSource[] = [];
const anchor = makeSimpleAnchor();
const radius = Math.percentChance(50) ? 0 : 20;
const increaseRate = Math.percentChance(50);
control.runInParallel(() => {
for (let i = 0; i < 3; ++i) {
const colors = Math.percentChance(10) ?
:
Math.percentChance(50) ?
:
undefined;
let factory: particles.ParticleFactory = new particles.RadialFactory(radius, 90, 5, colors);
const src = new particles.ParticleSource(anchor, increaseRate ? 50 + (i * 50) : 100, factory);
sources.push(src);
pause(350);
}
});
return sources;
}
}
export class Stars implements ParticleDemonstration {
start() {
class StarFactory extends particles.ParticleFactory {
protected galois: Math.FastRandom;
protected possibleColors: number[];
images: Image[];
constructor(possibleColors?: number[]) {
super();
this.galois = new Math.FastRandom();
this.images = [
img`
1
`, img`
1 . 1
. 1 .
1 . 1
`, img`
. 1 .
1 1 1
. 1 .
`
];
if (possibleColors && possibleColors.length)
this.possibleColors = possibleColors;
else
this.possibleColors = ;
}
createParticle(anchor: particles.ParticleAnchor) {
const p = super.createParticle(anchor);
p._x = Fx8(this.galois.randomRange(0, screen.width));
p._y = Fx8(0);
p.vy = Fx8(this.galois.randomRange(40, 60));
// set lifespan based off velocity and screen height (plus a little to make sure it doesn't disappear early)
p.lifespan = Fx.toInt(Fx.mul(Fx.div(Fx8(screen.height + 20), p.vy), Fx8(1000)));
const length = this.possibleColors.length - 1;
p.color = this.possibleColors;
for (let i = 0; i < length; ++i) {
if (this.galois.percentChance(50)) {
p.color = this.possibleColors;
break;
}
}
// images besides the first one are only used on occasion
p.data = this.galois.percentChance(15) ? this.galois.randomRange(1, this.images.length - 1) : 0;
return p;
}
drawParticle(p: particles.Particle, x: Fx8, y: Fx8) {
// on occasion, twinkle from white to yellow
const twinkleFlag = 0x8000;
const rest = 0x7FFF;
if (twinkleFlag && p.data) {
if (this.galois.percentChance(10)) {
p.color = 1;
p.data &= rest;
}
} else if (p.color === 1 && this.galois.percentChance(1)) {
p.color = 5;
p.data |= twinkleFlag;
}
const selected = this.images.clone();
selected.replace(0x1, p.color);
screen.drawImage(selected, Fx.toInt(x), Fx.toInt(y));
}
}
const sources: particles.ParticleSource[] = [];
const colors = ;
for (let i = 0; i < 4; i++)
colors.push(randint(2, 0xE));
const factory = new StarFactory(colors);
const src = new particles.ParticleSource(makeSimpleAnchor(), 25, factory)
sources.push(src);
return sources;
}
}
}
function makeSimpleAnchor(): particles.ParticleAnchor {
return {
x: screen.width >> 1,
y: screen.height >> 1
};
}
// Radial group as a lot of different possible configurations, so make it twice as likely as others
for (let i = 0; i < 2; i++) {
myDemonstrations.push(new demonstrations.RadialGroup());
}
myDemonstrations.push(new demonstrations.Stars());
myDemonstrations.push(new demonstrations.BubbleConfetti());
myDemonstrations.push(new demonstrations.Spinner());
myDemonstrations.push(new demonstrations.Fire());
forever(() => {
particles.disableAll()
for (let i = 0; i < count; ++i) {
Math.pickRandom(myDemonstrations)
.start();
}
msgSprite.top = scene.screenHeight();
msgSprite.top += msgInterval % 5 == 0 ? -10 : 0;
msgInterval += 1;
pause(3000);
});
【花雕动手做】基于 Kitronik 可编程开发板之粒子效果
这段 JavaScript 代码是基于 MakeCode Arcade 的粒子系统演示框架,展示了如何使用不同的粒子工厂(如火焰、星星、气泡、旋转环等)来创建丰富的视觉效果。它不仅体现了粒子系统的多样性,还通过控制器交互实现了动态切换和组合展示。逐段解读如下:一、核心结构概览
二、控制器逻辑
ts
controller.A.onEvent(...): count++
controller.B.onEvent(...): count--
按下 A 键:增加展示数量(最多 6)
按下 B 键:减少展示数量(最少 1)
三、粒子演示类详解
每个类都实现了 ParticleDemonstration 接口,返回一个或多个 ParticleSource。
1、Fire
使用 FireFactory 创建火焰效果
设置向上的加速度模拟火苗飘动
2、Spinner
使用 RadialFactory 创建旋转粒子环
自定义 lifespan,粒子存活时间随机
3、BubbleConfetti
同时生成气泡和五彩纸屑
使用两个不同的工厂:BubbleFactory 和 ConfettiFactory
4、RadialGroup
并行生成多个 RadialFactory 粒子源
每个源颜色、半径、速率都可能不同
使用 control.runInParallel() 异步创建,增强动态感
5、 Stars
自定义 StarFactory,生成闪烁星星
粒子图像有三种形态,颜色随机
实现 drawParticle() 方法,控制星星闪烁逻辑
四、辅助函数与配置
1、makeSimpleAnchor()
ts
return { x: screen.width >> 1, y: screen.height >> 1 }
返回一个屏幕中心点作为粒子源锚点
2、初始化演示列表
ts
myDemonstrations.push(...)
RadialGroup 被添加两次,增加其出现概率
其余演示类各添加一次
五、主循环逻辑
ts
forever(() => {
particles.disableAll()
for (let i = 0; i < count; ++i) {
Math.pickRandom(myDemonstrations).start();
}
...
pause(3000);
});
每 3 秒:
清除所有粒子
随机选择 count 个演示类并启动
控制提示信息上下浮动,形成动态 UI 效果。
【花雕动手做】基于 Kitronik 可编程开发板之粒子效果
通过模拟器,调试与模拟运行实验场景记录
页:
[1]