1.0.1 • Published 9 months ago
longto-block v1.0.1
SCRATCH-BLOCK
前置知识
在blockly里面,一个基本的block的构成,包括下面三个部分:
block
定义// 如下定义了一个motion_stop的block Blockly.defineBlocksWithJsonArray([{ type: 'motion_stop', lastDummyAlign0: 'RIGHT', message0: '停止', previousStatement: null, colour: COLOR.MOTION, tooltip: '停止一切动作', helpUrl: '', }])
注册到
toolbox
Blockly.inject('blockHTML', { toolbox: { "type": "block", "type": "motion_stop" }, })
编写对应的代码生成规则
// jsonGenerator为我们自定义的json代码生成器 jsonGenerator['motion_stop'] = function () { const code = { cmd: 'stop', token: 'token' } return JSON.stringify(code) }
Block组件文件结构
📦Blockly
┣ 📂blocks 所有的block定义
┃ ┣ 📜condition.ts 情况类型的block的定义
┃ ┣ 📜controls.ts 控制类型的block定义
┃ ┣ 📜index.ts 所有类型的block,都会通过这个文件导出
┃ ┣ 📜input.ts 输入类型的block定义
┃ ┗ 📜motion.ts 运动类型的blcok定义
┣ 📜constants.ts 该组件内部用到的所有的常量
┣ 📜extensions.ts 所有的block拓展(主要用于自定义验证规则)
┣ 📜index.vue 组件入口
┣ 📜jsonGenerator.ts 所有block对应的代码生成规则
┣ 📜toolbox.json 侧边栏(toolbox)
┣ 📜typing.d.ts 数据类型
┗ 📜utils.ts 工具函数
如何自定义一个block(以前往目标点(motion_goto_goal)为例)
constants.ts定义block名称
export const BLOCKKIND: { [property: string]: Opcode } = { MOTION_GOTO_GOAL: 'motion_goto_goal', }
在blocks文件夹里面,定义相关的block
// motion.ts import { COLOR } from '../constants'; import { BLOCKKIND } from '../constants'; export default [ { type: BLOCKKIND.MOTION_GOTO_GOAL, message0: '前往目标点: %1', args0: [ { type: 'field_input', name: 'target', text: '' } ], previousStatement: null, nextStatement: null, colour: COLOR.MOTION, tooltip: '前往某一个目标点', helpUrl: '' }, ]
在jsonGenerator文件里面,定义相关的代码生成规则
jsonGenerator[BLOCKKIND.MOTION_GOTO_GOAL] = function (block: Blockly.Block) { const code: BlockOutput = { kind: 'motion', opcode: BLOCKKIND.MOTION_GOTO_GOAL, id: block.id, nextId: block.getNextBlock()?.id || null, previousId: block.getPreviousBlock()?.id || null, parentId: block.getParent()?.id || null, inputs: {}, mqttTopic: '/robot/action' output: { cmd: 'goto', target: 'goal', goal: valueToCode(block, 'target') || '' }, topLevel: !block.getPreviousBlock() && !block.getParent() ? true : false } return JSON.stringify(code) }
输出JSON数据类型
/**
* * 拖拽block生成的单个JSON。生成的完整的json为:JsonBlockForList[]
* kind: block分类。所有的block都归属于某一个分类下。
* opcode: 对应生成当前json的block类型(如motion_stop对应【停止】block)
* id: 当前对象的唯一标识符
* nextId: 当前块相邻的下一个块的id
* previousId: 当前块的前一个块的id
* parentId: 当前块的父块的id(如,如果当前块为if类型的块,里面包含判断和执行两个块,那么if块就是判断和执行这两个块的父块)。该属性已移除。
* inputs?.condition:if块的判断块的id。可选。
* inputs?.doStack: if块的判断为真,需要执行的块的集合。数组形式,每一项为一个id
* inputs?.elseStack: if块的判断为假,执行的块。数组形式,每一个项都为一个id
* output: 发送给mqtt的数据
* mqttTopic: mqtt 发送消息的时候的topic
* isTopLevel: 当前块是否为最顶层的块。当前版本只有一个根节点,对应isTopLevel只有一个为true,其他的都为false
*/
export type JsonBlockForList = {
kind: 'motion' | 'controls' | 'condition' | 'status' | 'message'
opcode: OpcodeForEmbed
id: string
nextId: string
previousId: string
mqttTopic: string
// parentId: string | null
inputs: {
type?: 'if' | 'repeat' | 'if_else'
times?: number
condition?: string
doStack?: string[]
elseStack?: string[]
}
output: OutputForEmbed | null
isTopLevel: boolean
}
新增块
一、typing.d.ts
- 添加相关的块的输出,如:type xxxOutput
- 给OutputForEmbed 添加相关xxxOutput
- 给OpcodeForEmbed添加相关的类型,通常为新增的xxxOutput中刨去Output的小写下横线连接的单词。如MotionGotoGoalOutput,对应这个地方的值为motion_goto_goal。
- 如果这个值为一个新增的大类,JsonBlockForList添加相关的kind
二、constants.ts
根据实际添加的block,修改COLOR和BLOCKKIND
三、/blocks文件夹下添加需要的block
如:
{
type: BLOCKKIND.CONTROLS_MAP_BUILD_ON,
message0: locale.controls_map_build_on.message0,
previousStatement: null,
nextStatement: null,
colour: COLOR.CONTROLS,
tooltip: locale.controls_map_build_on.tooltip,
helpUrl: ''
},
- type 的BLOCKKIND为第二步增加的constants
- message0为/locale下增加的中英文翻译
- colour 的BLOCKKIND为第二步增加的constants
- tooltip为/locale下增加的中英文翻译