Adding palette/colors/storyboard packages (#898)
* modify scene palette * add colors/palette projexts * fix game pxt.json * reomve scenes * hide new color blocks * refactor color buffer * more refactoring * support for ARGB colors * avoid name clashing * fix sig * split files * simplify palette * adding weight * refactor default palette * adding palette test * updated test * add storyboard library * avoid name clash * fix namespace * fix extension name * fix fade * fix colorbuffer * fix build issues * avoid dup color * remove blocks * fix typing issue * added test * more storyboard work * reset palette * scene cleanup, remove dep on palette * add default loader * update blocks * pop/push/replace * fix pop bug * remove microsoft animation * fix test * handle scene push * pr feedback
This commit is contained in:
Родитель
ed37343be4
Коммит
4cb8e86a55
|
@ -1,9 +1,9 @@
|
|||
export interface Secrets {
|
||||
interface Secrets {
|
||||
connString: string;
|
||||
wifi: pxt.StringMap;
|
||||
}
|
||||
// this is to be overridden in a separate file
|
||||
export let secrets: Secrets;
|
||||
let secrets: Secrets;
|
||||
function test() {
|
||||
|
||||
const log = console.log;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Colors
|
||||
|
||||
Color manipulation
|
|
@ -0,0 +1,100 @@
|
|||
namespace color {
|
||||
export enum ColorBufferLayout {
|
||||
/**
|
||||
* 24bit RGB color
|
||||
*/
|
||||
RGB,
|
||||
/**
|
||||
* 32bit RGB color with alpha
|
||||
*/
|
||||
ARGB
|
||||
}
|
||||
|
||||
/**
|
||||
* A buffer of colors
|
||||
*/
|
||||
export class ColorBuffer {
|
||||
layout: ColorBufferLayout;
|
||||
buf: Buffer;
|
||||
|
||||
constructor(buf: Buffer, layout?: ColorBufferLayout) {
|
||||
this.buf = buf;
|
||||
this.layout = layout || ColorBufferLayout.RGB;
|
||||
}
|
||||
|
||||
get stride() {
|
||||
return this.layout == ColorBufferLayout.RGB ? 3 : 4;
|
||||
}
|
||||
|
||||
get length() {
|
||||
return Math.idiv(this.buf.length, this.stride);
|
||||
}
|
||||
|
||||
color(index: number): number {
|
||||
index = index | 0;
|
||||
if (index < 0 || index >= this.length) return -1;
|
||||
|
||||
const s = this.stride;
|
||||
const start = index * s;
|
||||
let c = 0;
|
||||
for (let i = 0; i < s; ++i)
|
||||
c = (c << 8) | (this.buf[start + i] & 0xff);
|
||||
return c;
|
||||
}
|
||||
|
||||
setColor(index: number, color: number) {
|
||||
index = index | 0;
|
||||
if (index < 0 || index >= this.length) return;
|
||||
|
||||
const s = this.stride;
|
||||
const start = index * s;
|
||||
for (let i = s - 1; i >= 0; --i) {
|
||||
this.buf[start + i] = color & 0xff;
|
||||
color = color >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
slice(start?: number, length?: number): ColorBuffer {
|
||||
const s = this.stride;
|
||||
return new ColorBuffer(this.buf.slice(start ? start * s : start, length ? length * s : length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of the src color buffer starting at the start dstOffset in the current buffer
|
||||
* @param dstOffset
|
||||
* @param src
|
||||
*/
|
||||
write(dstOffset: number, src: ColorBuffer): void {
|
||||
if (this.layout == src.layout) {
|
||||
const d = (dstOffset | 0) * this.stride;
|
||||
this.buf.write(d, src.buf);
|
||||
} else {
|
||||
// different color layout
|
||||
const n = Math.min(src.length, this.length - dstOffset);
|
||||
for (let i = 0; i < n; ++i)
|
||||
this.setColor(dstOffset + i, src.color(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of colors into a color buffer
|
||||
*/
|
||||
export function createBuffer(colors: number[], layout?: ColorBufferLayout): color.ColorBuffer {
|
||||
const n = colors.length;
|
||||
layout = layout || ColorBufferLayout.RGB;
|
||||
const stride = layout == ColorBufferLayout.RGB ? 3 : 4;
|
||||
const buf = control.createBuffer(n * stride);
|
||||
const p = new ColorBuffer(buf);
|
||||
let k = 0;
|
||||
for (let i = 0; i < n; i++) {
|
||||
let color = colors[i];
|
||||
for (let j = stride - 1; j >= 0; --j) {
|
||||
p.buf[k + j] = color & 0xff;
|
||||
color = color >> 8;
|
||||
}
|
||||
k += stride;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,213 @@
|
|||
/**
|
||||
* Well known colors
|
||||
*/
|
||||
const enum Colors {
|
||||
//% block=red
|
||||
Red = 0xFF0000,
|
||||
//% block=orange
|
||||
Orange = 0xFF7F00,
|
||||
//% block=yellow
|
||||
Yellow = 0xFFFF00,
|
||||
//% block=green
|
||||
Green = 0x00FF00,
|
||||
//% block=blue
|
||||
Blue = 0x0000FF,
|
||||
//% block=indigo
|
||||
Indigo = 0x4b0082,
|
||||
//% block=violet
|
||||
Violet = 0x8a2be2,
|
||||
//% block=purple
|
||||
Purple = 0xA033E5,
|
||||
//% block=pink
|
||||
Pink = 0xFF007F,
|
||||
//% block=white
|
||||
White = 0xFFFFFF,
|
||||
//% block=black
|
||||
Black = 0x000000
|
||||
}
|
||||
|
||||
/**
|
||||
* Well known color hues
|
||||
*/
|
||||
const enum ColorHues {
|
||||
//% block=red
|
||||
Red = 0,
|
||||
//% block=orange
|
||||
Orange = 29,
|
||||
//% block=yellow
|
||||
Yellow = 43,
|
||||
//% block=green
|
||||
Green = 86,
|
||||
//% block=aqua
|
||||
Aqua = 125,
|
||||
//% block=blue
|
||||
Blue = 170,
|
||||
//% block=purple
|
||||
Purple = 191,
|
||||
//% block=magenta
|
||||
Magenta = 213,
|
||||
//% block=pink
|
||||
Pink = 234
|
||||
}
|
||||
|
||||
/**
|
||||
* Color manipulation
|
||||
*/
|
||||
//% advanced=1
|
||||
namespace color {
|
||||
/**
|
||||
* Converts red, green, blue channels into a RGB color
|
||||
* @param red value of the red channel between 0 and 255. eg: 255
|
||||
* @param green value of the green channel between 0 and 255. eg: 255
|
||||
* @param blue value of the blue channel between 0 and 255. eg: 255
|
||||
*/
|
||||
//% blockId="colorsrgb" block="red %red|green %green|blue %blue"
|
||||
//% red.min=0 red.max=255 green.min=0 green.max=255 blue.min=0 blue.max=255
|
||||
//% help="colors/rgb"
|
||||
//% weight=19 blockGap=8
|
||||
//% blockHidden=true
|
||||
export function rgb(red: number, green: number, blue: number): number {
|
||||
return ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);
|
||||
}
|
||||
|
||||
export function argb(alpha: number, red: number, green: number, blue: number): number {
|
||||
return ((alpha & 0xFF) << 24) | ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the RGB value of a known color
|
||||
*/
|
||||
//% blockId=colorscolors block="%color"
|
||||
//% help="colors/well-known"
|
||||
//% shim=TD_ID
|
||||
//% weight=20 blockGap=8
|
||||
//% blockHidden=true
|
||||
export function wellKnown(color: Colors): number {
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an HSV (hue, saturation, value) color to RGB
|
||||
* @param hue value of the hue channel between 0 and 255. eg: 255
|
||||
* @param sat value of the saturation channel between 0 and 255. eg: 255
|
||||
* @param val value of the value channel between 0 and 255. eg: 255
|
||||
*/
|
||||
|
||||
//% blockId="colorshsv" block="hue %hue|sat %sat|val %val"
|
||||
//% hue.min=0 hue.max=255 sat.min=0 sat.max=255 val.min=0 val.max=255
|
||||
//% help="colors/hsv"
|
||||
//% weight=17
|
||||
//% blockHidden=true
|
||||
export function hsv(hue: number, sat: number = 255, val: number = 255): number {
|
||||
let h = (hue % 255) >> 0;
|
||||
if (h < 0) h += 255;
|
||||
// scale down to 0..192
|
||||
h = (h * 192 / 255) >> 0;
|
||||
|
||||
//reference: based on FastLED's hsv2rgb rainbow algorithm [https://github.com/FastLED/FastLED](MIT)
|
||||
let invsat = 255 - sat;
|
||||
let brightness_floor = ((val * invsat) / 255) >> 0;
|
||||
let color_amplitude = val - brightness_floor;
|
||||
let section = (h / 0x40) >> 0; // [0..2]
|
||||
let offset = (h % 0x40) >> 0; // [0..63]
|
||||
|
||||
let rampup = offset;
|
||||
let rampdown = (0x40 - 1) - offset;
|
||||
|
||||
let rampup_amp_adj = ((rampup * color_amplitude) / (255 / 4)) >> 0;
|
||||
let rampdown_amp_adj = ((rampdown * color_amplitude) / (255 / 4)) >> 0;
|
||||
|
||||
let rampup_adj_with_floor = (rampup_amp_adj + brightness_floor);
|
||||
let rampdown_adj_with_floor = (rampdown_amp_adj + brightness_floor);
|
||||
|
||||
let r: number;
|
||||
let g: number;
|
||||
let b: number;
|
||||
if (section) {
|
||||
if (section == 1) {
|
||||
// section 1: 0x40..0x7F
|
||||
r = brightness_floor;
|
||||
g = rampdown_adj_with_floor;
|
||||
b = rampup_adj_with_floor;
|
||||
} else {
|
||||
// section 2; 0x80..0xBF
|
||||
r = rampup_adj_with_floor;
|
||||
g = brightness_floor;
|
||||
b = rampdown_adj_with_floor;
|
||||
}
|
||||
} else {
|
||||
// section 0: 0x00..0x3F
|
||||
r = rampdown_adj_with_floor;
|
||||
g = rampup_adj_with_floor;
|
||||
b = brightness_floor;
|
||||
}
|
||||
return rgb(r, g, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade the color by the brightness
|
||||
* @param color color to fade
|
||||
* @param brightness the amount of brightness to apply to the color, eg: 128
|
||||
*/
|
||||
//% blockId="colorsfade" block="fade %color=neopixel_colors|by %brightness"
|
||||
//% brightness.min=0 brightness.max=255
|
||||
//% help="light/fade"
|
||||
//% group="Color" weight=18 blockGap=8
|
||||
//% blockHidden=true
|
||||
export function fade(color: number, brightness: number): number {
|
||||
brightness = Math.max(0, Math.min(255, brightness >> 0));
|
||||
if (brightness < 255) {
|
||||
let red = unpackR(color);
|
||||
let green = unpackG(color);
|
||||
let blue = unpackB(color);
|
||||
|
||||
red = (red * brightness) >> 8;
|
||||
green = (green * brightness) >> 8;
|
||||
blue = (blue * brightness) >> 8;
|
||||
|
||||
color = rgb(red, green, blue);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
export function unpackR(rgb: number): number {
|
||||
return (rgb >> 16) & 0xFF;
|
||||
}
|
||||
export function unpackG(rgb: number): number {
|
||||
return (rgb >> 8) & 0xFF;
|
||||
}
|
||||
export function unpackB(rgb: number): number {
|
||||
return (rgb >> 0) & 0xFF;
|
||||
}
|
||||
|
||||
export function parseColor(color: string): number {
|
||||
switch (color) {
|
||||
case "RED":
|
||||
case "red":
|
||||
return Colors.Red;
|
||||
case "GREEN":
|
||||
case "green":
|
||||
return Colors.Green;
|
||||
case "BLUE":
|
||||
case "blue":
|
||||
return Colors.Blue;
|
||||
case "WHITE":
|
||||
case "white":
|
||||
return Colors.White;
|
||||
case "ORANGE":
|
||||
case "orange":
|
||||
return Colors.Orange;
|
||||
case "PURPLE":
|
||||
case "purple":
|
||||
return Colors.Purple;
|
||||
case "YELLOW":
|
||||
case "yellow":
|
||||
return Colors.Yellow;
|
||||
case "PINK":
|
||||
case "pink":
|
||||
return Colors.Pink;
|
||||
default:
|
||||
return parseInt(color) || 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "color",
|
||||
"description": "Color manipulation",
|
||||
"files": [
|
||||
"colors.ts",
|
||||
"colorbuffer.ts",
|
||||
"README.md"
|
||||
],
|
||||
"public": true,
|
||||
"weight": 1,
|
||||
"dependencies": {
|
||||
"core": "file:../core"
|
||||
}
|
||||
}
|
|
@ -328,7 +328,8 @@ namespace game {
|
|||
*/
|
||||
export function addScenePushHandler(handler: (oldScene: scene.Scene) => void) {
|
||||
if (!_scenePushHandlers) _scenePushHandlers = [];
|
||||
_scenePushHandlers.push(handler);
|
||||
if (_scenePushHandlers.indexOf(handler) < 0)
|
||||
_scenePushHandlers.push(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -351,7 +352,8 @@ namespace game {
|
|||
*/
|
||||
export function addScenePopHandler(handler: (oldScene: scene.Scene) => void) {
|
||||
if (!_scenePopHandlers) _scenePopHandlers = [];
|
||||
_scenePopHandlers.push(handler);
|
||||
if (_scenePopHandlers.indexOf(handler) < 0)
|
||||
_scenePopHandlers.push(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,55 +1,3 @@
|
|||
/**
|
||||
* Well known colors
|
||||
*/
|
||||
const enum Colors {
|
||||
//% block=red
|
||||
Red = 0xFF0000,
|
||||
//% block=orange
|
||||
Orange = 0xFF7F00,
|
||||
//% block=yellow
|
||||
Yellow = 0xFFFF00,
|
||||
//% block=green
|
||||
Green = 0x00FF00,
|
||||
//% block=blue
|
||||
Blue = 0x0000FF,
|
||||
//% block=indigo
|
||||
Indigo = 0x4b0082,
|
||||
//% block=violet
|
||||
Violet = 0x8a2be2,
|
||||
//% block=purple
|
||||
Purple = 0xA033E5,
|
||||
//% block=pink
|
||||
Pink = 0xFF007F,
|
||||
//% block=white
|
||||
White = 0xFFFFFF,
|
||||
//% block=black
|
||||
Black = 0x000000
|
||||
}
|
||||
|
||||
/**
|
||||
* Well known color hues
|
||||
*/
|
||||
const enum ColorHues {
|
||||
//% block=red
|
||||
Red = 0,
|
||||
//% block=orange
|
||||
Orange = 29,
|
||||
//% block=yellow
|
||||
Yellow = 43,
|
||||
//% block=green
|
||||
Green = 86,
|
||||
//% block=aqua
|
||||
Aqua = 125,
|
||||
//% block=blue
|
||||
Blue = 170,
|
||||
//% block=purple
|
||||
Purple = 191,
|
||||
//% block=magenta
|
||||
Magenta = 213,
|
||||
//% block=pink
|
||||
Pink = 234
|
||||
}
|
||||
|
||||
/**
|
||||
* Different modes for RGB or RGB+W NeoPixel strips
|
||||
*/
|
||||
|
@ -195,9 +143,9 @@ namespace light {
|
|||
//% advanced=true
|
||||
setAll(rgb: number) {
|
||||
rgb = rgb | 0;
|
||||
const red = unpackR(rgb);
|
||||
const green = unpackG(rgb);
|
||||
const blue = unpackB(rgb);
|
||||
const red = color.unpackR(rgb);
|
||||
const green = color.unpackG(rgb);
|
||||
const blue = color.unpackB(rgb);
|
||||
|
||||
const end = this._start + this._length;
|
||||
const stride = this.stride();
|
||||
|
@ -216,12 +164,12 @@ namespace light {
|
|||
//% weight=79 blockGap=8
|
||||
//% group="More" advanced=true blockHidden=true
|
||||
setGradient(startColor: number, endColor: number, easing?: (t: number) => number) {
|
||||
const sr = unpackR(startColor);
|
||||
const sg = unpackG(startColor);
|
||||
const sb = unpackB(startColor);
|
||||
const er = unpackR(endColor);
|
||||
const eg = unpackG(endColor);
|
||||
const eb = unpackB(endColor);
|
||||
const sr = color.unpackR(startColor);
|
||||
const sg = color.unpackG(startColor);
|
||||
const sb = color.unpackB(startColor);
|
||||
const er = color.unpackR(endColor);
|
||||
const eg = color.unpackG(endColor);
|
||||
const eb = color.unpackB(endColor);
|
||||
|
||||
const end = this._start + this._length;
|
||||
const n1 = this._length - 1;
|
||||
|
@ -299,9 +247,9 @@ namespace light {
|
|||
//% help="light/neopixelstrip/set-pixel-color"
|
||||
//% weight=79 blockGap=8
|
||||
//% group="More" advanced=true
|
||||
setPixelColor(pixeloffset: number, color: number): void {
|
||||
setPixelColor(pixeloffset: number, c: number): void {
|
||||
pixeloffset = pixeloffset | 0;
|
||||
color = color | 0;
|
||||
c = c | 0;
|
||||
|
||||
if (pixeloffset < 0
|
||||
|| pixeloffset >= this._length)
|
||||
|
@ -309,9 +257,9 @@ namespace light {
|
|||
|
||||
const stride = this.stride();
|
||||
pixeloffset = (pixeloffset + this._start) * stride;
|
||||
const red = unpackR(color);
|
||||
const green = unpackG(color);
|
||||
const blue = unpackB(color);
|
||||
const red = color.unpackR(c);
|
||||
const green = color.unpackG(c);
|
||||
const blue = color.unpackB(c);
|
||||
this.setBufferRGB(pixeloffset, red, green, blue)
|
||||
this.autoShow();
|
||||
}
|
||||
|
@ -353,7 +301,7 @@ namespace light {
|
|||
break;
|
||||
}
|
||||
|
||||
return rgb(red, green, blue);
|
||||
return color.rgb(red, green, blue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -663,7 +611,7 @@ namespace light {
|
|||
//% group="Photon" advanced=true
|
||||
setPhotonPenHue(hue: number) {
|
||||
hue = hue | 0;
|
||||
this.setPhotonPenColor(hsv(hue, 0xff, 0xff));
|
||||
this.setPhotonPenColor(color.hsv(hue, 0xff, 0xff));
|
||||
}
|
||||
|
||||
//% deprecated=1 blockHidden=1
|
||||
|
@ -821,7 +769,7 @@ namespace light {
|
|||
tempColor += currChar;
|
||||
|
||||
if ((isSpace || i == leds.length) && tempColor) {
|
||||
this.setPixelColor(pi++, parseColor(tempColor))
|
||||
this.setPixelColor(pi++, color.parseColor(tempColor))
|
||||
tempColor = "";
|
||||
if (pi == n) {
|
||||
this.show();
|
||||
|
@ -1238,7 +1186,7 @@ namespace light {
|
|||
//% help="light/rgb"
|
||||
//% group="Color" weight=19 blockGap=8
|
||||
export function rgb(red: number, green: number, blue: number): number {
|
||||
return ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);
|
||||
return color.rgb(red, green, blue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1252,19 +1200,6 @@ namespace light {
|
|||
return color;
|
||||
}
|
||||
|
||||
function unpackR(rgb: number): number {
|
||||
let r = (rgb >> 16) & 0xFF;
|
||||
return r;
|
||||
}
|
||||
function unpackG(rgb: number): number {
|
||||
let g = (rgb >> 8) & 0xFF;
|
||||
return g;
|
||||
}
|
||||
function unpackB(rgb: number): number {
|
||||
let b = (rgb >> 0) & 0xFF;
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an HSV (hue, saturation, value) color to RGB
|
||||
* @param hue value of the hue channel between 0 and 255. eg: 255
|
||||
|
@ -1277,53 +1212,11 @@ namespace light {
|
|||
//% help="light/hsv"
|
||||
//% group="Color" weight=17
|
||||
export function hsv(hue: number, sat: number = 255, val: number = 255): number {
|
||||
let h = (hue % 255) >> 0;
|
||||
if (h < 0) h += 255;
|
||||
// scale down to 0..192
|
||||
h = (h * 192 / 255) >> 0;
|
||||
|
||||
//reference: based on FastLED's hsv2rgb rainbow algorithm [https://github.com/FastLED/FastLED](MIT)
|
||||
let invsat = 255 - sat;
|
||||
let brightness_floor = ((val * invsat) / 255) >> 0;
|
||||
let color_amplitude = val - brightness_floor;
|
||||
let section = (h / 0x40) >> 0; // [0..2]
|
||||
let offset = (h % 0x40) >> 0; // [0..63]
|
||||
|
||||
let rampup = offset;
|
||||
let rampdown = (0x40 - 1) - offset;
|
||||
|
||||
let rampup_amp_adj = ((rampup * color_amplitude) / (255 / 4)) >> 0;
|
||||
let rampdown_amp_adj = ((rampdown * color_amplitude) / (255 / 4)) >> 0;
|
||||
|
||||
let rampup_adj_with_floor = (rampup_amp_adj + brightness_floor);
|
||||
let rampdown_adj_with_floor = (rampdown_amp_adj + brightness_floor);
|
||||
|
||||
let r: number;
|
||||
let g: number;
|
||||
let b: number;
|
||||
if (section) {
|
||||
if (section == 1) {
|
||||
// section 1: 0x40..0x7F
|
||||
r = brightness_floor;
|
||||
g = rampdown_adj_with_floor;
|
||||
b = rampup_adj_with_floor;
|
||||
} else {
|
||||
// section 2; 0x80..0xBF
|
||||
r = rampup_adj_with_floor;
|
||||
g = brightness_floor;
|
||||
b = rampdown_adj_with_floor;
|
||||
}
|
||||
} else {
|
||||
// section 0: 0x00..0x3F
|
||||
r = rampdown_adj_with_floor;
|
||||
g = rampup_adj_with_floor;
|
||||
b = brightness_floor;
|
||||
}
|
||||
return rgb(r, g, b);
|
||||
return color.hsv(hue, sat, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade the color by the brightness
|
||||
* Use color.fade instead
|
||||
* @param color color to fade
|
||||
* @param brightness the amount of brightness to apply to the color, eg: 128
|
||||
*/
|
||||
|
@ -1331,52 +1224,9 @@ namespace light {
|
|||
//% brightness.min=0 brightness.max=255
|
||||
//% help="light/fade"
|
||||
//% group="Color" weight=18 blockGap=8
|
||||
//% blockHidden=true
|
||||
export function fade(color: number, brightness: number): number {
|
||||
brightness = Math.max(0, Math.min(255, brightness >> 0));
|
||||
if (brightness < 255) {
|
||||
let red = unpackR(color);
|
||||
let green = unpackG(color);
|
||||
let blue = unpackB(color);
|
||||
|
||||
red = (red * brightness) >> 8;
|
||||
green = (green * brightness) >> 8;
|
||||
blue = (blue * brightness) >> 8;
|
||||
|
||||
color = rgb(red, green, blue);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
function parseColor(color: string) {
|
||||
switch (color) {
|
||||
case "RED":
|
||||
case "red":
|
||||
return Colors.Red;
|
||||
case "GREEN":
|
||||
case "green":
|
||||
return Colors.Green;
|
||||
case "BLUE":
|
||||
case "blue":
|
||||
return Colors.Blue;
|
||||
case "WHITE":
|
||||
case "white":
|
||||
return Colors.White;
|
||||
case "ORANGE":
|
||||
case "orange":
|
||||
return Colors.Orange;
|
||||
case "PURPLE":
|
||||
case "purple":
|
||||
return Colors.Purple;
|
||||
case "YELLOW":
|
||||
case "yellow":
|
||||
return Colors.Yellow;
|
||||
case "PINK":
|
||||
case "pink":
|
||||
return Colors.Pink;
|
||||
default:
|
||||
return parseInt(color) || 0;
|
||||
}
|
||||
//% blockHidden=true deprecated
|
||||
export function fade(c: number, brightness: number): number {
|
||||
return color.fade(c, brightness);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1407,7 +1257,7 @@ namespace light {
|
|||
let hueOffset = 0;
|
||||
return () => {
|
||||
for (let i = 0; i < n; i++) {
|
||||
strip.setPixelColor(i, hsv(((i * 256) / (n - 1) + hueOffset) % 0xff, 0xff, 0xff));
|
||||
strip.setPixelColor(i, color.hsv(((i * 256) / (n - 1) + hueOffset) % 0xff, 0xff, 0xff));
|
||||
}
|
||||
hueOffset += Math.ceil(128 / n);
|
||||
if (hueOffset >= 0xff) {
|
||||
|
@ -1447,7 +1297,7 @@ namespace light {
|
|||
step++;
|
||||
for (let i = 0; i < l; i++) {
|
||||
const level = (Math.isin(i + step) * 127) + 128;
|
||||
strip.setPixelColor(i, rgb(level * this.red / 255, level * this.green / 255, level * this.blue / 255));
|
||||
strip.setPixelColor(i, color.rgb(level * this.red / 255, level * this.green / 255, level * this.blue / 255));
|
||||
}
|
||||
iteration++;
|
||||
return true;
|
||||
|
@ -1489,7 +1339,7 @@ namespace light {
|
|||
return () => {
|
||||
for (let i = 0; i < l; i++) {
|
||||
offsets[i] = (offsets[i] + (step * 2)) % 255
|
||||
strip.setPixelColor(i, rgb(255 - offsets[i], this.green, this.blue));
|
||||
strip.setPixelColor(i, color.rgb(255 - offsets[i], this.green, this.blue));
|
||||
}
|
||||
step++;
|
||||
if (step * 2 > 0xff) {
|
||||
|
@ -1510,7 +1360,7 @@ namespace light {
|
|||
|
||||
constructor(red: number, green: number, blue: number, delay: number) {
|
||||
super();
|
||||
this.rgb = rgb(red, green, blue);
|
||||
this.rgb = color.rgb(red, green, blue);
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
|
@ -1587,7 +1437,7 @@ namespace light {
|
|||
|
||||
constructor(red: number, green: number, blue: number, delay: number) {
|
||||
super();
|
||||
this.rgb = rgb(red, green, blue);
|
||||
this.rgb = color.rgb(red, green, blue);
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"public": true,
|
||||
"dependencies": {
|
||||
"core": "file:../core",
|
||||
"color": "file:../color",
|
||||
"jacdac": "file:../jacdac"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Palette
|
||||
|
||||
Helpers to manipulate palette in games.
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* Update the current scene palette
|
||||
*/
|
||||
namespace palette {
|
||||
/**
|
||||
* The default palette buffer for the project
|
||||
*/
|
||||
//% whenUsed
|
||||
const defaultPaletteBuffer = hex`__palette`
|
||||
|
||||
/**
|
||||
* Returns a clone of the default palette
|
||||
*/
|
||||
export function defaultPalette(): color.ColorBuffer {
|
||||
return new color.ColorBuffer(defaultPaletteBuffer.slice());
|
||||
}
|
||||
|
||||
const FIELD = "__palette";
|
||||
/**
|
||||
* Dynamically set all or part of the game's current palette
|
||||
*
|
||||
* @param palette The colors to set
|
||||
* @param pOffset The offset to start copying from the palette
|
||||
*/
|
||||
export function setColors(palette: color.ColorBuffer, pOffset = 0) {
|
||||
const scene = game.currentScene();
|
||||
let userPalette = scene.data[FIELD] as color.ColorBuffer;
|
||||
if (!userPalette)
|
||||
userPalette = scene.data[FIELD] = defaultPalette();
|
||||
userPalette.write(pOffset, palette);
|
||||
image.setPalette(userPalette.buf);
|
||||
|
||||
// make sure to clean up
|
||||
game.addScenePushHandler(scenePush);
|
||||
game.addScenePopHandler(scenePop);
|
||||
}
|
||||
|
||||
function scenePush(scene: scene.Scene) {
|
||||
if (scene.data[FIELD]) {
|
||||
const userPalette = scene.data[FIELD] as color.ColorBuffer;
|
||||
image.setPalette(userPalette.buf);
|
||||
}
|
||||
}
|
||||
|
||||
function scenePop(scene: scene.Scene) {
|
||||
if (scene.data[FIELD]) {
|
||||
scene.data[FIELD] = undefined;
|
||||
image.setPalette(defaultPaletteBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset to default palette
|
||||
*/
|
||||
export function reset() {
|
||||
const scene = game.currentScene();
|
||||
scene.data[FIELD] = undefined;
|
||||
image.setPalette(defaultPaletteBuffer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "palette",
|
||||
"description": "Palette manipulations",
|
||||
"files": [
|
||||
"palette.ts",
|
||||
"README.md"
|
||||
],
|
||||
"testFiles": [
|
||||
"test.ts"
|
||||
],
|
||||
"public": true,
|
||||
"weight": 10,
|
||||
"dependencies": {
|
||||
"color": "file:../color",
|
||||
"game": "file:../game"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
let mySprite = sprites.create(img`
|
||||
0 1 2 3
|
||||
4 5 6 7
|
||||
8 9 a b
|
||||
c d e f
|
||||
`.doubled().doubled().doubled().doubled(), SpriteKind.Player)
|
||||
|
||||
controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
|
||||
const p = palette.defaultPalette();
|
||||
for (let i = 0; i < p.length; ++i) {
|
||||
p.setColor(i, color.rgb(i * 16, 0, 255 - i * 16));
|
||||
}
|
||||
p.setColor(0, 0)
|
||||
palette.setColors(p)
|
||||
})
|
||||
|
||||
controller.B.onEvent(ControllerButtonEvent.Pressed, function () {
|
||||
palette.reset()
|
||||
})
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Storyboard
|
||||
|
||||
Orchestrate scenes
|
|
@ -0,0 +1,24 @@
|
|||
namespace storyboard {
|
||||
function loader(done: () => void) {
|
||||
const font = image.font8;
|
||||
let m = 40;
|
||||
let w = screen.width - 2 * m;
|
||||
let c = 2;
|
||||
let y = screen.height / 2 - c;
|
||||
let x = 0;
|
||||
game.onPaint(function() {
|
||||
screen.printCenter("MakeCode Arcade", y - font.charHeight - c, 1, font);
|
||||
screen.drawRect(m, y, w, 2 * c, 1)
|
||||
screen.fillRect(m, y + 1, x, 2 * c - 2, 3);
|
||||
|
||||
x++;
|
||||
if (x == w) done();
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Default boot sequence
|
||||
*/
|
||||
//% block="loader" fixedInstance whenUsed
|
||||
export const loaderBootSequence = new BootSequence(loader, 0);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "storyboard",
|
||||
"description": "Scene manager",
|
||||
"files": [
|
||||
"storyboard.ts",
|
||||
"loader.ts",
|
||||
"README.md"
|
||||
],
|
||||
"testFiles": [
|
||||
"test.ts"
|
||||
],
|
||||
"public": true,
|
||||
"weight": 10,
|
||||
"dependencies": {
|
||||
"game": "file:../game"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/**
|
||||
* A manager of scenes
|
||||
*/
|
||||
//% icon="\uf009"
|
||||
//% weight=87 color="#401255"
|
||||
namespace storyboard {
|
||||
export interface FrameOptions {
|
||||
background?: number;
|
||||
}
|
||||
|
||||
export class Frame {
|
||||
start: () => void;
|
||||
options: FrameOptions;
|
||||
|
||||
constructor(start: () => void, options: FrameOptions) {
|
||||
this.start = start;
|
||||
this.options = options || {};
|
||||
}
|
||||
}
|
||||
|
||||
//% fixedInstances
|
||||
export class BootSequence {
|
||||
start: (done: () => void) => void;
|
||||
background: number;
|
||||
constructor(start: (done: () => void) => void, background: number) {
|
||||
this.start = start;
|
||||
this.background = background;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the boot sequence
|
||||
*/
|
||||
//% block="storyboard register %boot| boot sequence" blockId=storyboardregister
|
||||
register() {
|
||||
registerBootSequence(this);
|
||||
}
|
||||
}
|
||||
|
||||
let _boots: BootSequence[];
|
||||
let _scenes: {
|
||||
[index: string]: Frame
|
||||
};
|
||||
let _nav: Frame[];
|
||||
|
||||
function registerBootSequence(boot: BootSequence) {
|
||||
if (!_boots)
|
||||
_boots = [];
|
||||
if (_boots.indexOf(boot) < 0)
|
||||
_boots.push(boot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a scene
|
||||
* @param name
|
||||
* @param scene
|
||||
*/
|
||||
export function registerScene(name: string, start: () => void, options?: FrameOptions) {
|
||||
if (!name) return;
|
||||
if (!_scenes) {
|
||||
_scenes = {};
|
||||
}
|
||||
_scenes[name] = new Frame(start, options);
|
||||
}
|
||||
|
||||
function consumeBootSequence() {
|
||||
// run boot sequences if any
|
||||
let boot: BootSequence;
|
||||
while (boot = _boots && _boots.shift()) {
|
||||
game.pushScene();
|
||||
let isDone = false;
|
||||
boot.start(() => isDone = true);
|
||||
pauseUntil(() => isDone);
|
||||
game.popScene();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the story board by running boot sequences then entering a scene
|
||||
* @param name
|
||||
*/
|
||||
//% block="storyboard start at $name" blockId=storyboardstart
|
||||
export function start(name?: string) {
|
||||
consumeBootSequence();
|
||||
// grab the first frame
|
||||
push(name || (_scenes && Object.keys(_scenes)[0]));
|
||||
}
|
||||
|
||||
function isActive(name: string): boolean {
|
||||
const scene = name && _scenes && _scenes[name];
|
||||
return scene && (_nav && _nav.length && _nav[_nav.length - 1] == scene);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the current scene with the given scene
|
||||
* @param name
|
||||
*/
|
||||
//% block="storyboard replace scene $name" blockId=storyboardreplace
|
||||
export function replace(name: string) {
|
||||
if (isActive(name)) return;
|
||||
|
||||
const scene = name && _scenes && _scenes[name];
|
||||
if (!scene) return; // not found
|
||||
|
||||
if (!_nav) _nav = [];
|
||||
if (_nav.length) {
|
||||
console.log('drop current scene')
|
||||
_nav.pop();
|
||||
game.popScene();
|
||||
}
|
||||
console.log('replace scene')
|
||||
_nav.push(scene);
|
||||
game.pushScene();
|
||||
scene.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transition to a registered scene
|
||||
* @param name
|
||||
*/
|
||||
//% block="storyboard push scene $name" blockId=storyboardpush
|
||||
export function push(name: string) {
|
||||
if (isActive(name)) return;
|
||||
|
||||
const scene = name && _scenes && _scenes[name];
|
||||
if (!scene) return; // not found
|
||||
|
||||
if (!_nav) _nav = [];
|
||||
if (_nav.length) {
|
||||
console.log('drop scene')
|
||||
game.popScene();
|
||||
}
|
||||
console.log(`push ${name}`)
|
||||
_nav.push(scene);
|
||||
game.pushScene();
|
||||
scene.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the current scene and restart the previous scene
|
||||
*/
|
||||
//% block="storyboard pop frame" blockId=storyboardpop
|
||||
export function pop() {
|
||||
const n = _nav && _nav.pop();
|
||||
if (n) {
|
||||
console.log('pop scene')
|
||||
game.popScene();
|
||||
}
|
||||
// restart previous
|
||||
if (_nav && _nav.length) {
|
||||
console.log('restart scene')
|
||||
const sc = _nav[_nav.length - 1];
|
||||
game.pushScene();
|
||||
sc.start();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
let mySprite = sprites.create(img`
|
||||
. . . . . . b b b b a a . . . .
|
||||
. . . . b b d d d 3 3 3 a a . .
|
||||
. . . b d d d 3 3 3 3 3 3 a a .
|
||||
. . b d d 3 3 3 3 3 3 3 3 3 a .
|
||||
. b 3 d 3 3 3 3 3 b 3 3 3 3 a b
|
||||
. b 3 3 3 3 3 a a 3 3 3 3 3 a b
|
||||
b 3 3 3 3 3 a a 3 3 3 3 d a 4 b
|
||||
b 3 3 3 3 b a 3 3 3 3 3 d a 4 b
|
||||
b 3 3 3 3 3 3 3 3 3 3 d a 4 4 e
|
||||
a 3 3 3 3 3 3 3 3 3 d a 4 4 4 e
|
||||
a 3 3 3 3 3 3 3 d d a 4 4 4 e .
|
||||
a a 3 3 3 d d d a a 4 4 4 e e .
|
||||
. e a a a a a a 4 4 4 4 e e . .
|
||||
. . e e b b 4 4 4 4 b e e . . .
|
||||
. . . e e e e e e e e . . . . .
|
||||
. . . . . . . . . . . . . . . .
|
||||
`, SpriteKind.Player)
|
||||
mySprite.x = 10
|
||||
controller.moveSprite(mySprite)
|
||||
storyboard.loaderBootSequence.register()
|
||||
storyboard.registerScene("lemon", function () {
|
||||
let mySprite2 = sprites.create(img`
|
||||
4 4 4 . . 4 4 4 4 4 . . . . . .
|
||||
4 5 5 4 4 5 5 5 5 5 4 4 . . . .
|
||||
b 4 5 5 1 5 1 1 1 5 5 5 4 . . .
|
||||
. b 5 5 5 5 1 1 5 5 1 1 5 4 . .
|
||||
. b d 5 5 5 5 5 5 5 5 1 1 5 4 .
|
||||
b 4 5 5 5 5 5 5 5 5 5 5 1 5 4 .
|
||||
c d 5 5 5 5 5 5 5 5 5 5 5 5 5 4
|
||||
c d 4 5 5 5 5 5 5 5 5 5 5 1 5 4
|
||||
c 4 5 5 5 d 5 5 5 5 5 5 5 5 5 4
|
||||
c 4 d 5 4 5 d 5 5 5 5 5 5 5 5 4
|
||||
. c 4 5 5 5 5 d d d 5 5 5 5 5 b
|
||||
. c 4 d 5 4 5 d 4 4 d 5 5 5 4 c
|
||||
. . c 4 4 d 4 4 4 4 4 d d 5 d c
|
||||
. . . c 4 4 4 4 4 4 4 4 5 5 5 4
|
||||
. . . . c c b 4 4 4 b b 4 5 4 4
|
||||
. . . . . . c c c c c c b b 4 .
|
||||
`, SpriteKind.Player)
|
||||
mySprite2.y = 20
|
||||
controller.moveSprite(mySprite2)
|
||||
controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
|
||||
storyboard.push("burger");
|
||||
})
|
||||
controller.B.onEvent(ControllerButtonEvent.Pressed, function () {
|
||||
storyboard.pop();
|
||||
})
|
||||
})
|
||||
storyboard.registerScene("burger", function () {
|
||||
let mySprite3 = sprites.create(img`
|
||||
. . . . c c c b b b b b . . . .
|
||||
. . c c b 4 4 4 4 4 4 b b b . .
|
||||
. c c 4 4 4 4 4 5 4 4 4 4 b c .
|
||||
. e 4 4 4 4 4 4 4 4 4 5 4 4 e .
|
||||
e b 4 5 4 4 5 4 4 4 4 4 4 4 b c
|
||||
e b 4 4 4 4 4 4 4 4 4 4 5 4 4 e
|
||||
e b b 4 4 4 4 4 4 4 4 4 4 4 b e
|
||||
. e b 4 4 4 4 4 5 4 4 4 4 b e .
|
||||
8 7 e e b 4 4 4 4 4 4 b e e 6 8
|
||||
8 7 2 e e e e e e e e e e 2 7 8
|
||||
e 6 6 2 2 2 2 2 2 2 2 2 2 6 c e
|
||||
e c 6 7 6 6 7 7 7 6 6 7 6 c c e
|
||||
e b e 8 8 c c 8 8 c c c 8 e b e
|
||||
e e b e c c e e e e e c e b e e
|
||||
. e e b b 4 4 4 4 4 4 4 4 e e .
|
||||
. . . c c c c c e e e e e . . .
|
||||
`, SpriteKind.Player)
|
||||
mySprite3.y = 80
|
||||
controller.moveSprite(mySprite3)
|
||||
controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
|
||||
storyboard.replace("lemon");
|
||||
})
|
||||
controller.B.onEvent(ControllerButtonEvent.Pressed, function () {
|
||||
storyboard.pop()
|
||||
})
|
||||
})
|
||||
controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
|
||||
storyboard.start("lemon")
|
||||
})
|
||||
controller.B.onEvent(ControllerButtonEvent.Pressed, function () {
|
||||
storyboard.start("burger")
|
||||
})
|
||||
|
|
@ -45,6 +45,9 @@
|
|||
"libs/esp32spi",
|
||||
"libs/net",
|
||||
"libs/mqtt",
|
||||
"libs/azureiot"
|
||||
"libs/azureiot",
|
||||
"libs/color",
|
||||
"libs/game",
|
||||
"libs/storyboard"
|
||||
]
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче