VM API 参考
Bilup 虚拟机(VM)是驱动 Scratch 项目的核心执行引擎。它提供对运行时环境的全面程序化访问,允许外部代码控制项目执行、操作角色和资源、监听事件并配置运行时行为。
概述
VM API 通过 window.vm 访问,提供以下功能:
- 项目控制:启动、停止、暂停和管理项目执行
- 资源管理:加载、修改和管理 角色、造型和声音
- 运行时配置:控制性能设置、编译选项和舞台属性
- 事件系统:监听运行时事件和状态变化
- 扩展集成:注册自定义积木和功能
- 数据访问:读取和修改项目变量、角色和积木
获取 VM 实例
VM 实例全局可用,可以通过多种方式访问:
// 全局 VM 实例(最常见)
const vm = window.vm;
// 从 React Redux store
import { useSelector } from 'react-redux';
const vm = useSelector(state => state.scratchGui.vm);
核心架构
VM 由几个关键组件组成:
- Runtime (
vm.runtime):核心执行引擎和状态管理 - Targets (
vm.runtime.targets):角色和舞台对象 - Sequencer (
vm.runtime.sequencer):线程调度和执行控制 - IO Devices (
vm.runtime.ioDevices):输入/输出处理(键盘、鼠标等) - Extension Manager (
vm.extensionManager):扩展加载和管理
项目控制
启动和停止
vm.start()
初始化并启动 VM 运行时。
vm.start();
// 必须在项目执行前调用
vm.greenFlag()
触发绿旗事件,启动所有带有绿旗帽子积木的脚本。
vm.greenFlag();
// 等效于点击绿旗按钮
vm.greenFlag();
// 启动项目并触发"当绿旗被点击"积木
vm.stopAll()
停止所有脚本和声音。
vm.stopAll();
// 停止所有运行中的脚本和声音
项目加载
vm.loadProject(projectData)
从数据加载项目。
// 从 .sb3 文件数据加载
const fileData = await file.arrayBuffer();
await vm.loadProject(fileData);
// 从 JSON 加载
const projectJson = { /* 项目数据 */ };
await vm.loadProject(JSON.stringify(projectJson));
参数:
projectData(ArrayBuffer | string): .sb3 格式的项目数据或 JSON 字符串
返回: 项目加载完成时解析的 Promise
vm.saveProjectSb3()
导出当前项目为 .sb3 数据。
const projectData = await vm.saveProjectSb3();
// 返回可保存为 .sb3 文件的 ArrayBuffer
// 保存到文件
const blob = new Blob([projectData], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'project.sb3';
a.click();
返回: Promise<ArrayBuffer>; 包含 .sb3 项目数据
目标管理
vm.runtime.targets
所有目标(角色和舞台)的数组。
const targets = vm.runtime.targets;
console.log('所有目标:', targets);
console.log('角色:', targets.filter(t => !t.isStage));
console.log('舞台:', targets.find(t => t.isStage));
类型: 目标对象数组
vm.editingTarget
当前选中的角色/舞台。
const target = vm.editingTarget;
if (target) {
console.log('当前编辑:', target.getName());
}
类型: 目标对象或 null
vm.setEditingTarget(targetId)
设置编辑目标。
const sprite = vm.runtime.targets.find(t => t.getName() === 'Sprite1');
if (sprite) {
vm.setEditingTarget(sprite.id);
}
参数:
targetId(string): 要选择的目标 ID
vm.deleteSprite(targetId)
从项目中删除角色。
// 按名称查找角色
const sprite = vm.runtime.targets.find(t => t.getName() === 'Sprite1' && !t.isStage);
if (sprite) {
vm.deleteSprite(sprite.id);
}
参数:
targetId(string): 要删除的角色 ID
注意: 无法删除舞台目标
vm.exportSprite(targetId)
将角色导出为 .sprite3 文件 blob。
// 导出角色
const sprite = vm.runtime.targets.find(t => t.getName() === 'Sprite1');
if (sprite) {
const spriteBlob = await vm.exportSprite(sprite.id);
// 保存到文件
const url = URL.createObjectURL(spriteBlob);
const a = document.createElement('a');
a.href = url;
a.download = `${sprite.getName()}.sprite3`;
a.click();
}
参数:
targetId(string): 要导出的角色 ID
返回: Promise<Blob> 包含 .sprite3 角色数据
运行时信息
vm.getPlaygroundData()
获取当前运行时状态。
const data = vm.getPlaygroundData();
console.log('目标:', data.targets);
console.log('变量:', data.variables);
console.log('列表:', data.lists);
返回: 包含运行时状态的对象
vm.runtime.getSpriteTargetByName(name)
按名称获取角色目标。
// 按名称查找角色
const sprite = vm.runtime.getSpriteTargetByName('Sprite1');
if (sprite && !sprite.isStage) {
console.log('找到角色:', sprite.getName());
}
参数:
name(string): 角色名称
返回: 目标对象或 null(如果未找到)
vm.runtime.getTargetForStage()
获取舞台目标。
const stage = vm.runtime.getTargetForStage();
console.log('舞台目标:', stage.getName());
返回: 舞台目标对象
vm.runtime._monitorState
访问监视器(变量显示)状态。
const monitorState = vm.runtime._monitorState;
console.log('监视器状态:', monitorState);
类型: 包含监视器状态信息的对象
vm.runtime.monitorBlocks
访问监视器积木容器。
const monitorBlocks = vm.runtime.monitorBlocks;
console.log('监视器积木:', monitorBlocks);
类型: 监视器积木容器对象
Target API
目标对象代表角色和舞台。
目标属性
const target = vm.editingTarget;
// 基本属性
console.log(target.id); // 唯一标识符
console.log(target.getName()); // 显示名称
console.log(target.isStage); // 舞台为 true,角色为 false
// 位置和外观(仅限角色)
if (!target.isStage) {
console.log(target.x); // X 坐标
console.log(target.y); // Y 坐标
console.log(target.direction); // 方向 (0-359)
console.log(target.size); // 大小百分比
console.log(target.visible); // 显示/隐藏
}
// 造型和声音
console.log(target.getCostumes());
console.log(target.getSounds());
console.log(target.getCurrentCostume());
目标方法
target.setXY(x, y)
设置角色位置。
const sprite = vm.editingTarget;
if (sprite && !sprite.isStage) {
sprite.setXY(100, 50);
}
target.setDirection(direction)
设置角色方向。
sprite.setDirection(90); // 指向右边
target.setSize(size)
设置角色大小。
sprite.setSize(150); // 原始大小的 150%
target.setVisible(visible)
设置角色显示/隐藏。
sprite.setVisible(false); // 隐藏角色
target.goToFront()
将角色移动到最前面。
sprite.goToFront();
target.goToBack()
将角色移动到最后面。
sprite.goToBack();
事件系统
VM 会发出可监听的事件。