Google Blockly Reimplementation with Unity/C#(2)

5min read

Contents

  1. Introduction
  2. Blockly Model
  3. Code Generator, Interpreter and Runner
  4. UGUI Design

For English:

  1. Introduction
  2. Blockly Model
  3. Code Interpreter and Runner
  4. UGUI Design


Google Blockly Model

核心Model模块完全参考Google Blockly。正如前文框架图所示,Blockly主要包括模型:Workspace,Variable, Block, Connection, Input, Field

  • Workspace相当于一个容器,包含Blocks, Variables。

    • 一个Workspace可以存储为一个Xml文件,保留Blocks之间的连接关系,以及属性信息。反过来也可以从一个格式正确的Xml文件重建一个Workspace。
    • Code Generator&Interpreter从遍历一个Workspace的顶层Block开始,根据Blocks之间的连接关系依次深度优先向下执行。
    • 一个Workspace在UI上显示为可供编辑Block的区域,其中还包含一个Toolbox,提供Block原型的容器。
  • Variable是作用在一个Workspace中的全局变量。

  • Block代表一段可执行程序。

    • 类比于一个方法,可以有输出(作为另一个Block的输入使用),也可以是没有输出(作为一个命令接在另一个Block下面执行)。
    • Blocks之间的关系有两种:输入/输出,前/后。Blocks在一个Workspace中的结构如下:
    - Block(Topmost in workspace)
      - ConnectionOutput
      - ConnectionPrev
      - ConnectionNext
        - Block(Next)
      - Input
        - Field 
        - Field 
          ...
        - ConnectionInput
          - Block(Input)
      - Input
        ...
    - Block
      ...
    - Block
      ...
  • Connection是实现Blocks之间的连接的关键,方式如下:

  Block.ConnectionOutput <-> Block.Input.ConnectionInput
  Block.ConnectionPrev <-> Block.ConnectionNext
  • Input是Block的基本单元。

    • 一个Input包含若干Field,以及一个Connection用来连接输入Block。

    • 依照json语义,按顺序创建Input。每个input之前的field都包含在该input里,如果剩下的field后没有定义input,则创建一个dummy input来包含剩下的fields。

    一个例子:

    "message0": "%{BKY_COROUTINE_WAIT_TITLE} %1 %2",
    "args0": [
      {
        "type": "input_value",
        "name": "TIME",
        "check": "Number"
      },
      {
        "type": "field_dropdown",
        "name": "UNIT",
        "options": [
          ["%{BKY_TIME_UNIT_MILLISECOND}", "MILLISECOND"],
          ["%{BKY_TIME_UNIT_SECONDS}", "SECONDS"],
          ["%{BKY_TIME_UNIT_MINUTES}", "MINUTES"],
          ["%{BKY_TIME_UNIT_TOO_HIGH}", "TOOHIGH"]
        ]
      }
    ],

    Block结果显示为:

    message0定义了block的形态:

    • %{BKY_COROUTINE_WAIT_TITLE}: 多语言的key
    • %1: input_value
    • %2: field_dropdown

    该Block有两个Input:

    1. input_value,Input Connection;
    2. dummy input。因为field_dropdown后没有input,因此创建一个dummy input来包含该field_dropdown。
  • Field描述Block的属性、状态,拿上例解释:

    field_dropdown:提供menu选择,不同选项代表了该Block执行不同的功能,比如算术运算的+, -, *, /

    除此之外,还有field_variable, field_number, field_textinput等,开发者也可自己定义。

Json语义定义

一个Block是由json语义来定义的,主要有如下属性:

  • type,用来识别Block的类型标识符;
  • Input/Field,如上例,以及对每个field, input属性、输入类型的描述;
  • Block Output Connection,或者Previous/Next Connection;
  • UI背景色;
  • 特殊属性

开发者可通过自定义Json描述,来定义一个新的Block。

Mutation特性

上文Json定义中提到了特殊属性,其中Mutation就是一个,它提供了动态修改Block结构的功能。

IF/ELSE就是一个典型的需要Mutation的例子:

初始结构 => Mutate后结构

用户在编辑时,只需要指定else if的个数,以及是否有else,Mutation根据这些变量重构Block结构。

函数

Mutation特性给函数Block的实现提供了便利。

下图定义了一个Swap(x, y)的函数,调用结果为将传入的x, y的值互换。

函数实现

函数Block(Google Blockly称“Procedure”)分为两大类:

  • 函数声明Procedure Definition: 利用Mutation功能可以允许用户定义函数名、参数,供所在的Workspace全局调用。见上图右。
  • 函数调用Procedure Call: 对应每个声明的函数,都会自动定义一个函数调用Block供用户选择。Block中只包含函数名、参数Input,见上图左;

自定义Mutation

开发者可以定义更多的Mutation,而具体Mutation的功能需自己实现。

以上简单介绍了Blockly的模型结构,下一篇博文会介绍Code Generator, Interpreter 以及 Runner的实现方法。


MORE FROM THE BLOG

The UGUI Design of uBlockly...

For Chinese:...

5min read

The Interpreter and Runner of...

For Chinese:...

6min read

The Blockly Model of uBlockly...

For Chinese:...

4min read

Introduction of uBlockly - Reimplementation...

For Chinese:...

1min read