shownb / shownb.github.com

shownb.github.io
shownb.github.io
5 stars 1 forks source link

scratch 3.0 插件开发指南 #36

Open shownb opened 5 years ago

shownb commented 5 years ago

具体的插件定义大家可以前往MIT团队的官方github仓库查看:https://github.com/LLK/scratch-vm/wiki/Scratch-3.0-Extensions-Specification 下面按照自己的理解翻译一下

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
    });
};

环境的搭建

怎么添加扩展

积木的分类

COMMAND ★★★★ 最基础 REPORTER ★★★ 基础 BOOLEAN ★★ 高阶 HAT ★★ 高阶 EVENT ★ 专业 CONDITIONAL ★ 专业 LOOP ★ 专业 BUTTON ★ 专业