var SomeBlocks = function (runtimeProxy) {
/**
* A proxy to communicate with the Scratch 3.0 runtime across a worker boundary.
* @type {Runtime}
*/
this.runtime = runtimeProxy;
};
/**
* @return {object} 这个扩展的元数据
*/
SomeBlocks.prototype.getInfo = function () {
return {
//必须: 扩展的名字.会用作扩展命名空间
id: 'someBlocks',
// 可选: 给人看的,formatMessage是react的函数
name: formatMessage({
id: 'extensionName',
defaultMessage: 'Some Blocks',
description: 'Extension name'
}),
// 可选: 一个会被显示在积木块上的图标URI.
blockIconURI: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAFCAAAAACyOJm3AAAAFklEQVQYV2P4DwMMEMgAI/+DEUIMBgAEWB7i7uidhAAAAABJRU5ErkJggg==',
// 可选:一个会被显示在积木分类菜单的图标URI.
menuIconURI: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAFCAAAAACyOJm3AAAAFklEQVQYV2P4DwMMEMgAI/+DEUIMBgAEWB7i7uidhAAAAABJRU5ErkJggg==',
// 必须: 这个扩展有什么积木的列表,
blocks: [
{
// 必须: 操作的名字 例如会按照这个来操作 someBlocks.myReporter
opcode: 'myReporter',
/* 必须: 积木的类型 有下面这些类型:
'command' - 一个正常的命令积木, 如 "move {} steps"
'reporter' - 返回一个值 如 "direction"
'Boolean' - 返回一个布朗型的值
'hat' - (事件风格) starts a stack if its value is truthy
'conditional' - 控制流 如 "if {}" 或 "if {} else {}" A 'conditional' block may return the one-based index of a branch to run, or it may return zero/falsy to run no branch.
'loop' - 控制流, 如 "repeat {} {}" 或 "forever {}"
// A 'loop' block is like a conditional block with two differences:
// - the block is assumed to have exactly one child branch, and
*/ - each time a child branch finishes, the loop block is called again.
blockType: 'reporter',
// 对于条件语句(conditional)积木 这个选项是必须的, 其他可以忽略: the number of
// child branches this block controls. An "if" or "repeat" block would
// specify a branch count of 1; an "if-else" block would specify a
// branch count of 2.
// TODO: should we support dynamic branch count for "switch"-likes?
branchCount: 0,
// 可选, default false: whether or not this block ends a stack.
// The "forever" and "stop all" blocks would specify true here.
terminal: true,
// 可选, default false: whether or not to block all threads while
// this block is busy. This is for things like the "touching color"
// block in compatibility mode, and is only needed if the VM runs in a
// worker. We might even consider omitting it from extension docs...
blockAllThreads: false,
// 必须: 展示给用户看的积木形式, 包含参数占位符. 参数占位符号必须大写和中括号包含.
text: formatMessage({
id: 'myReporter',
defaultMessage: 'letter [LETTER_NUM] of [TEXT]',
description: '描述 "myReporter" 积木'
}),
// 必须: 对每个参数的描述.因为在翻译的时候,可能参数的顺序会改变,所以必须用占位符的形式来表示
// 例如 英文是 letter [LETTER_NUM] of [TEXT] 中文是 [TEXT]的第[LETTER_NUM]个字
arguments: {
// 必须: the ID of the argument, which will be the name in the
// args object passed to the implementation function.
LETTER_NUM: {
// 必须: 参数的类型 / 要放的积木的外形
type: 'number',
// 可选: 默认值
default: 1
},
// 必须: the ID of the argument, which will be the name in the
// args object passed to the implementation function.
TEXT: {
// 必须: type of the argument / shape of the block input
type: 'string',
// 可选: the default value of the argument
default: formatMessage({
id: 'myReporter.TEXT_default',
defaultMessage: 'text',
description: 'Default for "TEXT" argument of "myReporter"'
})
}
},
// 必须: 这块积木要执行的函数.
func: 'myReporter',
// 可选: list of target types for which this block should appear.
// If absent, assume it applies to all builtin targets -- that is:
// ['sprite', 'stage']
filter: ['someBlocks.wedo2', 'sprite', 'stage']
},
{
// Another block...
}
],
// 可选: 定义积木里面参数的下选项?
menus: {
// 必须: an identifier for this menu, unique within this extension.
menuA: [
// Static menu: list items which should appear in the menu.
{
// 必须: the value of the menu item when it is chosen.
value: 'itemId1',
// 可选: the human-readable label for this item.
// Use `value` as the text if this is absent.
text: formatMessage({
id: 'menuA_item1',
defaultMessage: 'Item One',
description: 'Label for item 1 of menu A'
})
},
// The simplest form of a list item is a string which will be used as
// both value and text.
'itemId2'
],
// Dynamic menu: returns an array as above.
// Called each time the menu is opened.
menuB: 'getItemsForMenuB'
},
// 可选: translations
translation_map: {
de: {
'extensionName': 'Einige Blöcke',
'myReporter': 'Buchstabe [LETTER_NUM] von [TEXT]',
'myReporter.TEXT_default': 'Text',
'menuA_item1': 'Artikel eins',
// Dynamic menus can be translated too
'menuB_example': 'Beispiel',
// This message contains ICU placeholders (see `myReporter()` below)
'myReporter.result': 'Buchstabe {LETTER_NUM} von {TEXT} ist {LETTER}.'
},
it: {
// ...
}
},
// 可选: list new target type(s) provided by this extension.
targetTypes: [
'wedo2', // automatically transformed to 'someBlocks.wedo2'
'speech' // automatically transformed to 'someBlocks.speech'
]
};
};
/**
* Implement myReporter.
* @param {object} args - the block's arguments.
* @property {string} MY_ARG - the string value of the argument.
* @returns {string} a string which includes the block argument value.
*/
SomeBlocks.prototype.myReporter = function (args) {
// This message contains ICU placeholders, not Scratch placeholders
const message = formatMessage({
id: 'myReporter.result',
defaultMessage: 'Letter {LETTER_NUM} of {TEXT} is {LETTER}.',
description: 'The text template for the "myReporter" block result'
});
// Note: this implementation is not Unicode-clean; it's just here as an example.
const result = args.TEXT.charAt(args.LETTER_NUM);
return message.format({
LETTER_NUM: args.LETTER_NUM,
TEXT: args.TEXT,
LETTER: result
});
};
环境的搭建
安装nodejs
apt-get install nodejs
apt-get install npm
把scrath3下载回来
mkdir scratch3
cd scratch3
git clone https://github.com/llk/scratch-gui
git clone https://github.com/llk/scratch-vm
cd scratch-vm
npm install
npm link
npm run watch
另外起一个shell
cd scratch3
cd scratch-gui
npm install
npm link scratch-vm
npm start
坑
具体的插件定义大家可以前往MIT团队的官方github仓库查看:https://github.com/LLK/scratch-vm/wiki/Scratch-3.0-Extensions-Specification 下面按照自己的理解翻译一下
环境的搭建
安装nodejs
把scrath3下载回来
另外起一个shell
怎么添加扩展
例如你的扩展名字叫websockets 在 scratch3\scratch-vm\src\extensions 建立scratch3_websockets目录 把扩展index.js放进去
然后修改scratch-vm\src\extension-support\extension-manager.js builtinExtensions = { 里面添加 websockets:() => require('../extensions/scratch3_websockets')
修改 scratch-gui/src/lib/libraries/extensions/index.jsx 里面 { name: 'websocket Test', extensionId: 'websockets', iconURL: 自己定义一个, description: 'Build with motors and sensors.', featured: true, disabled: true }
积木的分类
COMMAND ★★★★ 最基础 REPORTER ★★★ 基础 BOOLEAN ★★ 高阶 HAT ★★ 高阶 EVENT ★ 专业 CONDITIONAL ★ 专业 LOOP ★ 专业 BUTTON ★ 专业
COMMAND 类型积木 这时最容易理解的积木,
)
一个COMMAND可以通过在其他积木上面或者底下来连接. 这类积木是自上而下的被执行的. 所以这个积木会在上一个积木执行之后被执行。
定义一个COMMAND类型积木是这样的:
blockType 是 BlockType.COMMAND.
text就是在这块积木上面要现实的字符串.如果 text 有 [] , 里面字段会被处理为变量字段, 一个用户可以编辑的值.
opcode 就是函数名 用来实现这块积木的操作。
功能的实现是这样的。
COMMAND
把一个函数作为命令来执行。COMMAND
无需返回值. 下面这个就是转换字符并记录REPORTER 类型积木
REPORTER除了blockType不一样外,定义基本和COMMAND一样
但是函数的实现,一定要有返回值。return
![](https://miro.medium.com/max/1316/1*iXCKD4n1LUxScGbbmQPWTg.png)
REPORTER
也是一个基本函数,它产生一个值 例如 String或者Int.REPORTER
可以放进去任何有变量的字段.REPORTER
可以被放进去COMMAND.也可以放进去其他REPORTER.BOOLEAN 类型积木 BOOLEAN 类型积木其实是一种特殊类型的 REPORTER. 你以为这样才能插得进去?
其实这样也能插得进去,不信你插插看?
这类积木的定义除了blockType=BlockType.BOOLEAN外,其他基本和COMMAND一样
函数的现实一定要返回布朗类型。
HAT 类型积木 When () Is True 这个积木是用来处理事件的。实现的过程有点微妙
如图所演示,send event会执行一个函数,然后这个函数产生一个事件变化,然后绿帽HAT侦测到这个事件的变化,就会执行下面的转15度.