文档
官网 打开编辑器
文档/更快地写积木

积木文本语法

积木页文本、命令行(gandi)、本机 MCP 和积木注释里的 gandi-dsl 片段,都用同一种文本来描述积木。 控制、运算、变量和列表写成 JavaScript 的样子,其余积木写成 分类.积木名(...)。文本从不执行, 只是积木的另一种写法:积木打印成文本、文本编回积木,结构完全一致。

const score = stage.variable("score", 0);
const items = sprite.list("items", []);

when.flagclicked(() => {
    score = 0;
    for (let i = 1; i <= 10; i++) {
        items.push(i * 2);
        if (i % 3 == 0 && !sensing.mousedown()) {
            score += 1;
        } else if (i > 8) {
            looks.say(`第 ${i} 个`);
        }
    }
    repeat(3, () => { motion.movesteps(10); });
});

旧的块式写法(control.if(operator.gt(a, 1), () => { ... })、data.set(x, 1))一直可用, 编出的积木相同。读回积木时,能写成 JavaScript 的地方都写成 JavaScript;写不成的保持块式(见细节)。

声明#

要新建变量、列表或广播,在文件开头声明,const 和 let 等价:

写法 含义
const x = stage.variable("x", 0); 全局变量,初始值可省
const x = sprite.variable("x", 0); 当前角色的变量
const L = sprite.list("L", []); / stage.list(...) 列表
const msg = broadcast("消息"); 广播消息

项目里已有的变量和列表不用声明,直接按名字写(x = 1;、L.push(v);)。只有三种情况要声明:新建一个; 角色变量和全局变量同名(不声明会报 E_AMBIGUOUS_VAR,声明时选 sprite.variable 还是 stage.variable); 同名的变量和列表要用列表写法(L.push(...))。引用从不新建变量,名字不存在报 E_UNKNOWN_VAR。 for 的循环变量也一样:要么项目里已有,要么先声明,例如 const i = sprite.variable("i", 0);。

读回积木时只声明这一页用到的变量,声明里的字符串是变量的真名,标识符可以不同:名字写不成标识符 (my score、☁ x、_)叫 _variable;和积木分类同名(data、motion……)、和这一页任何自制积木的形参同名的, 标识符加数字后缀(p → p2),重名的往后编号。例如变量 p 和自制积木形参 p 同名时:

const p2 = sprite.variable("p", 0);          // 真名还是 "p"
define("f %n", (p) => { p2 = p; });          // 形参 p 和变量 p2 不会混

控制#

积木 写法
如果 if (条件) { ... }
如果…否则 if (条件) { ... } else { ... },else if 链是嵌套的「如果…否则」
重复执行 while (true) { ... }
当…重复执行 while (条件) { ... }
对于每个 for (let i = 1; i <= n; i++) { ... },i 必须是项目里已有或已声明的变量,起点只能是 1,语义见for 的语义
重复执行…次 repeat(n, () => { ... });
重复执行直到 repeatUntil(条件, () => { ... });
等待 wait(秒);、waitUntil(条件);
停止 stop("all");
跳出循环 / 跳到下一轮 break;、continue;(Gandi 专有积木,见Gandi 专有积木)
返回 return 值;,只能写在自制积木的定义里;顶层或 hat 里写 return 语句报 E_RETURN_OUTSIDE

while (true) 的循环体里有 break; 时,它是「当 真 重复执行」而不是「重复执行」: 「重复执行」是终结积木,后面不能再接积木,会结束的循环可以。break; 和 continue; 只能写在 while、for 语句里;repeat、repeatUntil 的回调里写 control.break()、 control.continue()。

定义之外孤立的「返回」积木在运行时合法(相当于停止这个脚本,TurboWarp 作品里有),读回时写成块式 procedures.return(值),编译只给 W_RETURN_OUTSIDE 警告;要停止脚本写 stop("this script")。

for 的语义#

for (let i = 1; i <= n; i++) 编成「对于每个 i(1 到 n)」积木,和 JavaScript 的 for 不一样(VM 实测,解释器和编译执行一致):

情形 实际行为 JavaScript 里
n 每一轮重新求值 和 JavaScript 一致,循环里改 n 会影响轮数 一致
n = 2.5 跑 3 轮(i 取 1、2、3) 跑 2 轮
循环体里改 i 不影响迭代,仍然跑满 会影响
循环结束后的 i 等于 n 等于 n + 1
n < 1 一轮都不跑,i 不会被置成 1,保持原来的值 i 被置成起点

起点只能写 1,步长只能是 ++ 或 += 1,条件只能是 i <= n,别的写法报 E_UNSUPPORTED_FOR。

运算#

运算符的优先级与 JavaScript 相同,a + b * 2 是 a + (b * 2),积木是嵌套的两个运算积木。

积木 写法
加、减、乘、除、取余、乘方 a + b、a - b、a * b、a / b、a % b、a ** b(乘方是 Gandi 专有积木)
取负 -a(等于 0 - a)
大于、小于、等于 a > b、a < b、a == b
不等于、小于等于、大于等于 a != b、a <= b、a >= b,是对应比较外面套一个「不成立」
区分大小写的等于 a === b、a !== b(Gandi 专有积木,不是严格类型相等,见下)
与、或、不成立 a && b、a || b、!a
三元 条件 ? a : b(Gandi 专有积木)
连接 模板字符串 `你好 ${名字}`
四舍五入、绝对值、向下取整、向上取整、平方根 Math.round(x)、Math.abs(x)、Math.floor(x)、Math.ceil(x)、Math.sqrt(x)
乘方 Math.pow(a, b)(和 a ** b 是同一块,Gandi 专有)
ln、log、e ^ Math.log(x)、Math.log10(x)、Math.exp(x)
三角函数 sin(x)、cos(x)、tan(x)、asin(x)、acos(x)、atan(x),参数和结果都是角度
随机数 random(a, b)
字符串 s.length、s[i]、s.includes(t)

&&、||、! 和 if、while 的条件必须是布尔积木:比较、true / false、侦测里的判断等。 变量不是布尔值,要写成 x != 0。

变量与列表#

积木 写法
将变量设为 x = 值;
将变量增加 x += 值;、x -= 值;、x++;、x--;
乘、除、取余、乘方后设回 x *= 值;、x /= 值;、x %= 值;、x **= 值;,编成「设为」加运算积木
加入列表 L.push(值);
插入列表 L.insert(位置, 值);
删除列表的第几项 L.remove(位置);
删除列表的全部项目 L.clear();
替换列表的第几项 L[位置] = 值;
列表的第几项 L[位置]
列表的项目数 L.length
列表包含 L.includes(值)
列表中第一个…的编号 L.indexOf(值),找不到是 0

显示、隐藏变量仍写 data.showvariable(x)、data.hidevariable(x)。运动、外观、声音、事件、侦测等 其余积木都写成 分类.积木名(...),需要的积木名用 gandi blocks 关键词 查。

和 JavaScript 不同的地方#

写法 实际含义
s[i]、L[i]、L.insert、L.remove、L.indexOf 位置从 1 数起。作品装了「高级数据结构」后,变量、成员、调用结果上的 x[i] 是属性访问(对象的键 / 对象列表的第 i 项),只有字符串字面量和模板后面的 [i] 才是取字符;变量里取字符写 operator.letter_of(i, x),见高级数据结构的文本写法
a + b 任一边是字符串字面量、模板字符串或连接积木时是连接,否则是数字加法
a == b 不区分大小写,数字形式的文字按数值比较;a === b 区分大小写
a % b 结果的符号跟除数一致,-7 % 3 是 2
sin(x) 等 参数是角度。没有 Math.sin
x = x + 1 与 x += 1 前者是「将变量设为」加一个加法积木,后者是「将变量增加」,两种写法各自保留,不互相转换
a < b < c 报错,写成 a < b && b < c
for 计数循环只支持 for (let i = 1; i <= n; i++),语义和 JavaScript 不同,见for 的语义;for...of 只在作品装了集市版「高级数据结构」时有,是它的「遍历」积木,见高级数据结构
函数形参 不能赋值,要先放进已声明的变量
s.includes(t)、L.includes(v)、L.indexOf(v) 不区分大小写
a < b、a > b 两边有一边是文字(不能当数字读)就按字符串比较,"10" < "9" 成立
NaN 的比较 退化成字符串比较:NaN > 1、NaN >= 1 得 true,NaN <= 1 得 false,NaN == NaN 得 true;不要依赖 NaN 参与比较
(12345).length 数字当文字取长度,是 5
"" == 0 false(空串不当 0)
s2 + s3(两个变量,值都是文字) 变量不是字符串字面量,按数字加,"a" 和 "b" 得 0,不是 "ab";连接要写模板字符串 `${s2}${s3}`
s + 4,s 的值是 "3" 得 7(数字形式的文字按数值加)
1 === "1" true:=== 只是区分大小写的等于,不比较类型
s[0]、s[越界] 得空串(序号从 1 起);字面量 0 会给 W_INDEX_FROM_ONE 警告,L[0] 同理
random(a, b) a、b 都是整数才取整数,有小数就取小数;a > b 时自动交换
x / 0、x % 0 x / 0 是 Infinity(0 / 0 是 NaN),x % 0 是 NaN

不支持函数表达式、new、typeof、??、switch、do...while、async。对象和数组只能写在其他写法 列出的位置(可增减的参数组、命名参数),不能当值用。作品装了「高级数据结构」时,对象和数组字面量、typeof、new Set(...) 是它的积木,见高级数据结构的文本写法。

Gandi 专有积木#

===、!==、**(Math.pow)、条件 ? a : b、break、continue 编成 Gandi 才有的积木 (operator_strictequals、operator_power、operator_ternary、control_break、control_continue)。 原版 Scratch 没有这些操作码,含有它们的作品导出到原版 Scratch 后打不开。check 和写入时编译会给 W_GANDI_ONLY 警告,列出用到的积木,不阻断写入;作品要在原版 Scratch 里打开就别用: === 换 ==,break / continue 换条件变量加 while / repeatUntil,**、三元换乘法和 if。

其他写法#

  • 命名参数:looks.say({MESSAGE: "hi"}),键是积木的输入名或字段名,写了不存在的键报 E_UNKNOWN_ARG, 新积木缺必填字段报 E_MISSING_ARG。命名参数和位置参数不能混用;有回调时回调是第二个参数。
  • 可增减的参数组(扩展积木的 ➕➖ 参数):固定参数照常写,后面每个组写成数组或对象: gandiScene.switchToWithParams("main", {关卡: 1, 难度: 2})(键 = 值 两格一组写成对象)、 ext.block(a, [x, y, z])(一格一组写成数组)、[[键, 值], ...](键写不成属性名时)。数字样的键、 typed / reference / opcode 等保留名不能当对象键,会退回 [[键, 值], ...]。核心积木的多操作数写成 operator.add(a, b, c)、混合运算符写成 operator.arithmetic(a, "+", b, "-", c)。 扩展声明了「逐槽选类型」(types)的组,每个槽放什么由槽里的值定:布尔积木是布尔槽(槽里没有文字框),数字是数字槽, 文字是文字槽;类型存在积木的 argtypes 里,带底写回原样保留,纯文本重编会按槽里的值重新写出。 超过个数上限报一条 E_VARIADIC_LIMIT(不是每个多出来的槽一条未知输入),积木上带着 items="2" 这类和槽数一致的旧属性,写回时原样保留。
  • 阈值型 hat:when.greaterthan("LOUDNESS", 10, () => { ... }) 的阈值是数字框,可以换成报告器 (when.greaterthan("TIMER", sensing.answer(), ...));它没有参数椭圆,写回调形参报 E_HAT_PARAMS。
  • hat 回调的形参:带参数椭圆的 hat 把椭圆名写成回调形参,体内直接用: gandiScene.whenSceneStartsWithParams((level, 难度) => { looks.say(level); })。形参只在这个回调里有效, 不能赋值;椭圆名写不成标识符或和变量重名时退回 ["名字", ...] 加 ccw.hat_parameter("名字")。 hat 没有参数椭圆却写了形参报 E_HAT_PARAMS。回调形参 _ 表示「不要这个参数」,参数名真叫 _ 时退回字符串位置写法。
  • 自制积木:define("go %n", (steps) => { ... }); 和 call["go %n"](10);,形参 %n 数字、%s 文字、 %b 布尔、%c 积木堆(体内 body() 调用)。变量和形参同名时形参优先,读回时变量会改名(见声明)。
  • 积木注释:积木前写 /** 文字 */,多行用每行 * 开头的 JSDoc 样式;文字有首尾空白、*/、\r 时写成精确 写法 /** @text "..." */。空注释写 /** */。挂在 reporter 上的注释写成 (/** 文字 */ 表达式),括号让 注释挂在这一整块上。普通注释(//、/* */)不会存进积木,会给 W_COMMENT_DROPPED 警告; else /** 注释 */ if 这种不在语句或表达式前面的注释同样被丢并警告。
  • 装饰器:@at(x, y)、@warp、@global、@reporter、@boolean、@collapsed、@id("...")、@size、@color、 @locked、@note(...) 只能写在顶层语句或 frame() 前面(中间只隔空白和注释);写在回调里、或后面没有语句, 报 E_DECORATOR。
  • 深度上限:语句和表达式嵌套超过 400 层报 E_TOO_DEEP(带上限数),长链(几百项的 +、&&、模板) 拆成几条语句。读回积木时嵌套超过 180 层也会拒绝打印并报同一个错,不会截断。

回调形参#

积木上有「参数槽」时,参数槽写成回调的形参。参数槽是积木上一个只能放自己那块参数积木的输入:遍历积木的「键」「值」、 map 积木的「项」「序号」、reduce 的「累积值」……(hat 积木的参数椭圆是同一类,见上面的 hat 回调)。

ext.each(list, (key, value) => { looks.say(value); });   // C 形积木:回调体是积木堆
r = ext.map(list, (item, index) => item * 2);             // 回调体是一个表达式(lambda 积木)
  • 回调永远是最后一个参数,前面是积木上其余的固定参数(按积木上的顺序)。具名写法把回调放在回调体输入的键里 ({LIST: list, SUBSTACK: (key, value) => {...}})或者作第二个参数。没有形参的 () => { ... } 也认。
  • 形参依次绑定参数槽,个数不能超过槽数(E_HAT_PARAMS),少写的槽照样在积木上;形参名只是文字里的写法。体里用形参就是 引用槽里那块参数积木,所以形参只在这个回调体里有效,不能赋值(E_ASSIGN_PARAM),回调外面再用报 E_UNKNOWN_VAR。
  • 回调体的种类要对:C 形口写 { ... },lambda 写表达式,写反了报 E_SLOT_TYPE。lambda 体里的 true / false、字面量照常编。
  • 参数槽的名字:槽里是自己的可再生积木的(item、key……),打印时取槽名的小写(IDX 写 index);槽里是默认名的参数椭圆的,取椭圆名。 重名或和变量冲突就加数字(item2)。
  • 里层回调盖住外层的同一块参数积木:两个回调积木用的是同一块参数积木(例如都有 item)时,运行时读最近一层的值。 在里层体里写外层的形参报 E_PARAM_SHADOWED,要用就先放进变量;这包括里层没写形参的槽。
  • 参数槽被别的积木盖住、缺输入、体不是标准形状的积木,读回时保持位置参数写法(参数槽里的标准影子写成它自己的调用, ext.forEachKey()),编译回去是同一块积木。
  • 老的「每个槽都写出来」的位置写法(ext.each(list, "ITEM", "POS", () => {...})、参数槽里写参数积木的调用)照常可用。

带点和特殊字符的扩展 id#

积木写成 扩展id.积木名(...)。扩展 id 不一定是单个标识符,写法按 id 的样子定,打印和解析互逆(积木 → 文本 → 积木结构一致):

扩展 id 积木写法
music、my_ext(下划线属于 id) music.playNote(...)、my_ext.go(...)
test.moreDataTypes(带点,每一段都是标识符) 成员链 test.moreDataTypes.getNewSet(...);去掉最后一段方法名,其余用点连起来就是 id
my-ext、中文、a b(有一段写不成标识符) ext["my-ext"].go(...)
if、null、class、when、call、Math、JSON、Object、store、ads、stage……(第一段是 JavaScript 保留字或 DSL 自己占用的名字) ext["if"].go(...):写成 if.go(...)、null.go(...) 读不回
积木名写不成标识符(do-it、two words) ext["my-ext"]["do-it"](...),普通 id 也一样
  • 积木的操作码是 扩展id_积木名;解析成积木后和普通扩展没有区别,E_UNKNOWN_BLOCK 的报错里是完整的操作码, 没装的扩展(test.moreDataTypes.getNewSet(...))报「积木不存在」并带上完整 id,宿主据此去装扩展。
  • 分类名、带点 id 的第一段(test)和 ext 在文本里是前缀:变量、形参不能叫这些名字(读回积木时同名的变量会改名, 如 test2,声明里的字符串真名不变)。文件里声明了同名变量时,那个名字就是变量,不再当扩展前缀。
  • 装了「高级数据结构」时,没对上已装扩展 id 的成员链(o.a.b.push(v))是对象属性路径,不是积木调用。

细节#

下列积木打印时保持块式,因为写成 JavaScript 读回来会变样:

  • 在比较下拉里选了 ≠、≥、≤、≡ 的紧凑比较积木,以及带可增减参数的算术、逻辑、连接、三元积木: operator.compare(...)、operator.arithmetic(...)、operator.logic(...)、operator.join(...)、 operator.ternary({...})。
  • 带 else if 分支的「如果」积木(多条件的紧凑形态)。
  • 「否则」槽里的内层「如果」带注释、或下面还有别的积木时,写成 else { ... },不写成 else if。
  • 嵌套在左边的连接积木 连接(连接(a, b), c);只有嵌套在右边的链才写成模板字符串。
  • 条件恰好是 true 而循环体里没有 break 的「当…重复执行」:写成 control.while(true, ...)。
  • 循环体里有 break 的「重复执行」:写成 control.forever(...)。
  • repeat、repeatUntil 回调里的「跳出循环」:写成 control.break()。
  • 名字和积木分类同名的变量(data、motion……)、和自制积木形参同名的变量、写不成标识符的名字(含 _): 打印时改标识符(加后缀,如 data2、p2;写不成标识符的叫 _variable),声明里的字符串真名不变。
  • 定义之外的「返回」积木:写成 procedures.return(值),不写成 return。
  • 带注释的 reporter:写成 (/** 注释 */ 表达式)。

没装扩展的积木页是只读的#

作品用了还没装的扩展时,读这一页会先自动装上它(和写入同一套:协作中要有 edit.project、要用户同意,已授权的设备不再逐次确认; 装第三方代码,所以这是读取会改动环境的一处,结果里带 installedExtensions)。装不上的页(扩展库里没有、没权限、不同意、超时) 退回只读预览:扩展积木写成 扩展.积木({ 输入名: 值 }),结果带 degraded: true 和 missingExtensions。

预览看不到积木上的隐藏结构(mutation、菜单影子、布尔槽的空位),写回会悄悄改掉它们,所以含预览的页一律不能写: write_file、edit_file、apply_patch、transaction 都报 E_DEGRADED_WRITE(check 也报,details.missingExtensions 列出缺的扩展), 页和积木表原样不动。先装好扩展,重新读这一页拿到正式写法,再改。

  • 扩展 id 带下划线(my_ext)时,按已知的扩展 id(已装的、扩展库里的)取最长前缀还原,不会当成 my。
  • search_files 先在预览上搜,只为命中的缺扩展页装扩展,再重新打印命中页;大列表折叠成占位的页搜不到列表里的内容, 结果带 folded: true、totalExact: false。
  • 多场景:积木页按角色所在场景的舞台解析变量和广播,那个舞台取不到时读、检查、写入都报 E_STAGE_CONTEXT,不会悄悄换成入口场景的舞台。 页面里指向看不见的变量(别的场景舞台上的、已删除的)的旧引用,写回时沿用原来的 id,不新建变量,给 W_VARIABLE_NOT_VISIBLE 警告。 场景在读和写之间改过名,写入会因为修订号变了报 E_CONFLICT;文本里的场景名和积木原来指向的场景对不上时给 W_SCENE_RENAMED。

报错#

代码 原因 改法
E_CHAINED_COMPARE a < b < c a < b && b < c
E_ASSIGN_PARAM 给自制积木的参数赋值 复制到已声明的变量再改
E_ASSIGN_TARGET 给整个列表赋值 L.push(v)、L[i] = v 或 L.clear()
E_UNKNOWN_VAR 变量没有声明 在文件开头 const x = sprite.variable("x", 0);
E_UNSUPPORTED_FOR for 不是计数形式 for (let i = 1; i <= n; i++),或用 while
E_UNSUPPORTED for...of(作品里没有「遍历」积木时,或写法不是 for (const [k, v] of Object.entries(x)) / for (const v of x))、do...while、switch 改用 while、if 链;见遍历
E_JS_EXPR 不支持的表达式 报错的 fix 里给出对应的积木写法
E_SLOT_TYPE 布尔槽里放了非布尔值,数字槽里放了文字,值槽里放了 true / false,终结积木后面接了积木 布尔槽写比较,文字用 text("..."),值槽写 1 / 0;while (true) 后面要接语句就在循环里加 break
E_PARSE 不是合法的 JavaScript 语法 按报错位置改;repeat 回调里的 break; 写 control.break()
E_DECL 声明写错:重复、不在文件开头、不是 stage.variable / sprite.variable / sprite.list / broadcast(...) 照声明表写,声明放在文件开头、frame() 外面
E_UNKNOWN_ARG 命名参数里有不存在的键,或位置参数多了 fix 里列出这块积木的输入和字段名
E_MISSING_ARG 新积木缺必填的输入或字段(data.set() 没写变量) 补上缺的参数
E_UNKNOWN_BLOCK 积木不存在(拼错、扩展没装、raw(...)) fix 给相近的写法;缺扩展按 fix 里的 id 先装扩展(add_extension)
E_MDT_MISSING 写了「高级数据结构」的写法(store.set、JSON.parse、o.has("k")、size(o)……),作品里没装这个扩展;或装的线上版没有集市版才有的积木(o.add(x)、o.map(...)) 先装扩展:线上版 moreDataTypes,集市版 test.moreDataTypes,见高级数据结构
E_BAD_OPTION 菜单、字段的值不在选项里 用 fix 列出的选项
E_UNKNOWN_SCENE 场景积木里写的场景名不存在(gandiScene.switchTo("第三关")) message 列出所有场景名,fix 给最接近的一个,见 场景积木
E_SCENE_AMBIGUOUS 场景名同时对上多个场景 写完整的场景 id
E_DYNAMIC_LIMIT 可增减的参数组少于个数下限 按 message 里的范围写
E_VARIADIC_LIMIT 可增减的参数组超过个数上限(写多了,或积木上的旧数据超限) 按 message 里的上限拆成几块积木
E_DEGRADED_WRITE 写入的页里还有没装扩展的积木(只读预览) 先装 details.missingExtensions 里的扩展,重新读这一页再改
E_STAGE_CONTEXT 角色所在场景的舞台没有加载,变量、广播解析不了 先加载那个场景
E_POSITION @at 写在嵌套的积木上 @at 只能写在顶层脚本前
E_PROC 自制积木的定义或调用写错(模板、参数个数、返回类型) 调用写 call["完整模板"](...)
E_NOTE 游离注释不是 @note(x, y, w, h) comment("...") 照格式写;积木上的注释用 /** ... */
E_FRAME frame() 写法错(嵌套、没有脚本、在里面声明变量) frame("标题", () => { 脚本 }),声明放在外面
E_BROADCAST 广播菜单里写了字符串 用声明过的广播标识符
E_AMBIGUOUS_VAR 角色和全局有同名变量,或变量和列表同名 按 fix 声明要用的那个
E_HAT_PARAMS 回调形参个数和 hat 的参数椭圆(或积木上的参数槽)对不上 去掉多余的形参
E_PARAM_SHADOWED 里层回调体里用了外层回调的形参,而里层绑定了同一块参数积木,读到的是里层的值 外层的值先放进变量,见回调形参
E_RETURN_OUTSIDE return 语句写在 define 之外 放进定义里;停止脚本写 stop("this script")
E_DECORATOR 装饰器写在回调里,或后面没有语句 写在顶层语句或 frame() 前
E_TOO_DEEP 嵌套超过上限(解析 400 层,打印 180 层) 拆成几条语句
E_INTERNAL 编译器遇到意外错误 报告问题,附上源文

警告(warnings,不阻断写入):

代码 含义
W_FOREACH_BREAK for...of(遍历积木)的循环体里写了 break / continue:编译模式里不起作用(解释执行有效);改法:把后面的语句放进 if。嵌套的 for...of 里的 break 只算里层那个循环
W_GANDI_ONLY 用了 Gandi 专有积木(===、**、三元、break、continue),原版 Scratch 打不开导出的作品
W_COMMENT_DROPPED 注释没存进积木:普通注释,或不在语句 / 表达式前面
W_INDEX_FROM_ONE 字面量序号 0:Scratch 序号从 1 起,s[0]、L[0] 总是空
W_RETURN_OUTSIDE procedures.return 写在定义之外,只会停止脚本
W_LITERAL_CHANGED 写进输入框的字面量读回来和写的不一样(不该发生)
W_SCENE_REF_DANGLING 场景积木引用的场景已被删除:保留原值,积木不执行任何操作
W_SCENE_RENAMED 文本里的场景名和积木原来指向的场景(现在叫另一个名字)对不上:读完文本之后场景改过名,积木会改指到文本里名字对应的场景
W_VARIABLE_NOT_VISIBLE 积木引用的变量在这里看不见(别的场景舞台上的、已删除的):沿用原来的引用,没有新建变量
W_STALE_CALL_IDS、W_REPORTER_LOOP_NOT_WARP、W_FRAME_LOOP_NOT_WARP、W_MENU_AS_VALUE 自制积木调用绑定、@warp、菜单积木当值用的提示,见各自的 message

相关#