Skip to content
This repository was archived by the owner on May 18, 2026. It is now read-only.

Commit ef78fbc

Browse files
authored
Merge pull request #93 from smalruby/fix/issue-20-align-microbit-more-blocks
feat: Align MicrobitMore with standard Scratch micro:bit extension
2 parents cc73cc0 + 7e207bd commit ef78fbc

2 files changed

Lines changed: 152 additions & 48 deletions

File tree

src/extensions/microbitMore/index.js

Lines changed: 148 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,8 @@ const MbitMoreGestureName =
263263
G3: 'G3',
264264
G6: 'G6',
265265
G8: 'G8',
266-
SHAKE: 'SHAKE'
266+
SHAKE: 'SHAKE',
267+
JUMPED: 'JUMPED'
267268
};
268269

269270
/**
@@ -1614,6 +1615,22 @@ class MbitMoreBlocks {
16141615
}),
16151616
value: 'MOVED'
16161617
},
1618+
{
1619+
text: formatMessage({
1620+
id: 'mbitMore.gesturesMenu.shake',
1621+
default: 'shaken',
1622+
description: 'label for shaken gesture in gesture picker for microbit more extension'
1623+
}),
1624+
value: MbitMoreGestureName.SHAKE
1625+
},
1626+
{
1627+
text: formatMessage({
1628+
id: 'mbitMore.gesturesMenu.jumped',
1629+
default: 'jumped',
1630+
description: 'label for jumped gesture in gesture picker for microbit more extension'
1631+
}),
1632+
value: MbitMoreGestureName.JUMPED
1633+
},
16171634
{
16181635
text: formatMessage({
16191636
id: 'mbitMore.gesturesMenu.tilted',
@@ -1698,17 +1715,9 @@ class MbitMoreBlocks {
16981715
text: formatMessage({
16991716
id: 'mbitMore.gesturesMenu.g8',
17001717
default: '8G',
1701-
description: 'label for 3G gesture in gesture picker for microbit more extension'
1718+
description: 'label for 8G gesture in gesture picker for microbit more extension'
17021719
}),
17031720
value: MbitMoreGestureName.G8
1704-
},
1705-
{
1706-
text: formatMessage({
1707-
id: 'mbitMore.gesturesMenu.shake',
1708-
default: 'shake',
1709-
description: 'label for shaken gesture in gesture picker for microbit more extension'
1710-
}),
1711-
value: MbitMoreGestureName.SHAKE
17121721
}
17131722
];
17141723
}
@@ -1718,14 +1727,6 @@ class MbitMoreBlocks {
17181727
*/
17191728
get TILT_DIRECTION_MENU () {
17201729
return [
1721-
{
1722-
text: formatMessage({
1723-
id: 'mbitMore.tiltDirectionMenu.any',
1724-
default: 'any',
1725-
description: 'label for any direction element in tilt direction picker for Microbit More extension'
1726-
}),
1727-
value: 'ANY'
1728-
},
17291730
{
17301731
text: formatMessage({
17311732
id: 'mbitMore.tiltDirectionMenu.up',
@@ -1757,6 +1758,14 @@ class MbitMoreBlocks {
17571758
description: 'label for right element in tilt direction picker for Microbit More extension'
17581759
}),
17591760
value: MbitMoreGestureName.TILT_RIGHT
1761+
},
1762+
{
1763+
text: formatMessage({
1764+
id: 'mbitMore.tiltDirectionMenu.any',
1765+
default: 'any',
1766+
description: 'label for any direction element in tilt direction picker for Microbit More extension'
1767+
}),
1768+
value: 'ANY'
17601769
}
17611770
];
17621771
}
@@ -2299,6 +2308,18 @@ class MbitMoreBlocks {
22992308
* @type {Object.<number, Object>}
23002309
*/
23012310
this.prevReceivedData = {};
2311+
2312+
/**
2313+
* The timestamp of the last G3 gesture.
2314+
* @type {number}
2315+
*/
2316+
this.lastG3Timestamp = 0;
2317+
2318+
/**
2319+
* The timestamp of the simulated JUMPED gesture.
2320+
* @type {number}
2321+
*/
2322+
this.jumpedTimestamp = 0;
23022323
}
23032324

23042325
/**
@@ -2408,6 +2429,22 @@ class MbitMoreBlocks {
24082429
blockType: BlockType.COMMAND
24092430
},
24102431
'---',
2432+
{
2433+
opcode: 'whenTilted',
2434+
text: formatMessage({
2435+
id: 'mbitMore.whenTilted',
2436+
default: 'when tilted [DIRECTION]',
2437+
description: 'when the micro:bit is tilted to the selected direction'
2438+
}),
2439+
blockType: BlockType.HAT,
2440+
arguments: {
2441+
DIRECTION: {
2442+
type: ArgumentType.STRING,
2443+
menu: 'tiltDirectionMenu',
2444+
defaultValue: 'ANY'
2445+
}
2446+
}
2447+
},
24112448
{
24122449
opcode: 'isTilted',
24132450
text: formatMessage({
@@ -3073,6 +3110,8 @@ class MbitMoreBlocks {
30733110
Object.entries(this._peripheral.gestureEvents).forEach(([gestureName, timestamp]) => {
30743111
this.prevGestureEvents[gestureName] = timestamp;
30753112
});
3113+
// Add simulated JUMPED event
3114+
this.prevGestureEvents[MbitMoreGestureName.JUMPED] = this.jumpedTimestamp;
30763115
}
30773116

30783117
/**
@@ -3154,6 +3193,39 @@ class MbitMoreBlocks {
31543193
return lastTimestamp !== this.prevGestureEvents[name];
31553194
});
31563195
}
3196+
if (gestureName === 'TILTED') {
3197+
const tiltGestures = [
3198+
MbitMoreGestureName.TILT_UP,
3199+
MbitMoreGestureName.TILT_DOWN,
3200+
MbitMoreGestureName.TILT_LEFT,
3201+
MbitMoreGestureName.TILT_RIGHT
3202+
];
3203+
return tiltGestures.some(name => {
3204+
const timestamp = this._peripheral.getGestureEventTimestamp(name);
3205+
if (timestamp === null) return false;
3206+
if (!this.prevGestureEvents[name]) return true;
3207+
return timestamp !== this.prevGestureEvents[name];
3208+
});
3209+
}
3210+
if (gestureName === MbitMoreGestureName.JUMPED) {
3211+
const g3Timestamp = this._peripheral.getGestureEventTimestamp(MbitMoreGestureName.G3);
3212+
const freefallTimestamp = this._peripheral.getGestureEventTimestamp(MbitMoreGestureName.FREEFALL);
3213+
3214+
if (g3Timestamp !== null && g3Timestamp !== this.lastG3Timestamp) {
3215+
this.lastG3Timestamp = g3Timestamp;
3216+
}
3217+
3218+
if (freefallTimestamp !== null && this.lastG3Timestamp !== 0) {
3219+
// Check if FREEFALL happened after G3 and within 1000ms
3220+
if (freefallTimestamp > this.lastG3Timestamp && (freefallTimestamp - this.lastG3Timestamp) < 1000) {
3221+
this.jumpedTimestamp = freefallTimestamp;
3222+
}
3223+
}
3224+
3225+
if (this.jumpedTimestamp === 0) return false;
3226+
if (!this.prevGestureEvents[MbitMoreGestureName.JUMPED]) return true;
3227+
return this.jumpedTimestamp !== this.prevGestureEvents[MbitMoreGestureName.JUMPED];
3228+
}
31573229
const lastTimestamp =
31583230
this._peripheral.getGestureEventTimestamp(gestureName);
31593231
if (lastTimestamp === null) return false;
@@ -3162,50 +3234,78 @@ class MbitMoreBlocks {
31623234
}
31633235

31643236
/**
3165-
* Test whether the micro:bit is tilted in a direction.
3237+
* Test whether the micro:bit is tilted to the selected direction.
3238+
* @param {object} args - the block's arguments.
3239+
* @param {string} args.DIRECTION - direction of tilt.
3240+
* @return {boolean} - true if the condition is met.
3241+
*/
3242+
whenTilted (args) {
3243+
if (!this.updateLastGestureEventTimer) {
3244+
this.updateLastGestureEventTimer = setTimeout(() => {
3245+
this.updatePrevGestureEvents();
3246+
this.updateLastGestureEventTimer = null;
3247+
}, this.runtime.currentStepTime);
3248+
}
3249+
const direction = args.DIRECTION;
3250+
if (direction === 'ANY') {
3251+
const tiltGestures = [
3252+
MbitMoreGestureName.TILT_UP,
3253+
MbitMoreGestureName.TILT_DOWN,
3254+
MbitMoreGestureName.TILT_LEFT,
3255+
MbitMoreGestureName.TILT_RIGHT
3256+
];
3257+
return tiltGestures.some(name => {
3258+
const lastTimestamp = this._peripheral.getGestureEventTimestamp(name);
3259+
if (lastTimestamp === null) return false;
3260+
if (!this.prevGestureEvents[name]) return true;
3261+
return lastTimestamp !== this.prevGestureEvents[name];
3262+
});
3263+
}
3264+
const lastTimestamp = this._peripheral.getGestureEventTimestamp(direction);
3265+
if (lastTimestamp === null) return false;
3266+
if (!this.prevGestureEvents[direction]) return true;
3267+
return lastTimestamp !== this.prevGestureEvents[direction];
3268+
}
3269+
3270+
/**
3271+
* Test whether the micro:bit is tilted to the selected direction.
31663272
* @param {object} args - the block's arguments.
3167-
* @param {string} args.DIRECTION - the direction to check.
3168-
* @return {boolean} - true if tilted within the time window.
3273+
* @param {string} args.DIRECTION - direction of tilt.
3274+
* @return {boolean} - true if the micro:bit is tilted.
31693275
*/
31703276
isTilted (args) {
3171-
if (args.DIRECTION === 'ANY') {
3172-
return (
3173-
this.getTiltAngle({DIRECTION: 'FRONT'}) >= 15 ||
3174-
this.getTiltAngle({DIRECTION: 'BACK'}) >= 15 ||
3175-
this.getTiltAngle({DIRECTION: 'LEFT'}) >= 15 ||
3176-
this.getTiltAngle({DIRECTION: 'RIGHT'}) >= 15
3177-
);
3277+
switch (args.DIRECTION) {
3278+
case 'ANY':
3279+
return Math.abs(this._peripheral.pitch) > 15 || Math.abs(this._peripheral.roll) > 15;
3280+
case MbitMoreGestureName.TILT_UP:
3281+
return this._peripheral.pitch < -15;
3282+
case MbitMoreGestureName.TILT_DOWN:
3283+
return this._peripheral.pitch > 15;
3284+
case MbitMoreGestureName.TILT_LEFT:
3285+
return this._peripheral.roll < -15;
3286+
case MbitMoreGestureName.TILT_RIGHT:
3287+
return this._peripheral.roll > 15;
3288+
default:
3289+
return false;
31783290
}
3179-
const directionMap = {
3180-
[MbitMoreGestureName.TILT_UP]: 'FRONT',
3181-
[MbitMoreGestureName.TILT_DOWN]: 'BACK',
3182-
[MbitMoreGestureName.TILT_LEFT]: 'LEFT',
3183-
[MbitMoreGestureName.TILT_RIGHT]: 'RIGHT'
3184-
};
3185-
const direction = directionMap[args.DIRECTION];
3186-
return this.getTiltAngle({DIRECTION: direction}) >= 15;
31873291
}
31883292

31893293
/**
3190-
* Get the tilt angle in a direction.
3294+
* Get the tilt angle of the selected direction.
31913295
* @param {object} args - the block's arguments.
3192-
* @param {string} args.DIRECTION - the direction to check (FRONT, BACK, LEFT, RIGHT).
3193-
* @return {number} - the tilt angle in degrees.
3296+
* @param {string} args.DIRECTION - direction of tilt.
3297+
* @return {number} - the tilt angle.
31943298
*/
31953299
getTiltAngle (args) {
3196-
const direction = args.DIRECTION;
3197-
const pitch = this._peripheral.readPitch();
3198-
const roll = this._peripheral.readRoll();
3199-
3200-
switch (direction) {
3300+
switch (args.DIRECTION) {
32013301
case 'FRONT':
3202-
return -pitch;
3302+
return -this._peripheral.pitch;
32033303
case 'BACK':
3204-
return pitch;
3304+
return this._peripheral.pitch;
32053305
case 'LEFT':
3206-
return -roll;
3306+
return -this._peripheral.roll;
32073307
case 'RIGHT':
3208-
return roll;
3308+
return this._peripheral.roll;
32093309
default:
32103310
return 0;
32113311
}

src/extensions/microbitMore/translations.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,10 @@
122122
"mbitMore.gesturesMenu.g6": "6Gかかった",
123123
"mbitMore.gesturesMenu.g8": "8Gかかった",
124124
"mbitMore.gesturesMenu.shake": "ゆさぶられた",
125+
"mbitMore.gesturesMenu.jumped": "ジャンプした",
125126
"mbitMore.gesturesMenu.moved": "動いた",
126127
"mbitMore.gesturesMenu.tilted": "どれかの向きに傾いた",
128+
"mbitMore.whenTilted": "[DIRECTION] に傾いたとき",
127129
"mbitMore.isTilted": "[DIRECTION] に傾いた",
128130
"mbitMore.tiltDirectionMenu.any": "どれかの向き",
129131
"mbitMore.tiltDirectionMenu.up": "",
@@ -225,8 +227,10 @@
225227
"mbitMore.gesturesMenu.g6": "6Gかかった",
226228
"mbitMore.gesturesMenu.g8": "8Gかかった",
227229
"mbitMore.gesturesMenu.shake": "ゆさぶられた",
230+
"mbitMore.gesturesMenu.jumped": "ジャンプした",
228231
"mbitMore.gesturesMenu.moved": "うごいた",
229232
"mbitMore.gesturesMenu.tilted": "どれかのむきにかたむいた",
233+
"mbitMore.whenTilted": "[DIRECTION] にかたむいたとき",
230234
"mbitMore.isTilted": "[DIRECTION] にかたむいた",
231235
"mbitMore.tiltDirectionMenu.any": "どれかのむき",
232236
"mbitMore.tiltDirectionMenu.up": "まえ",

0 commit comments

Comments
 (0)