返回首页

LuaJIT Scratch 模拟器:12k 脚本 30 FPS

文章剖析了基于 LuaJIT 和 LÖVE2D 的高性能视觉解释器的开发,该解释器能在弱硬件上执行 12289 个脚本。描述了模块化架构、块结构、递归解释和 EXE 构建。示例代码保留供中高级开发者分析。

LuaJIT 上的 12 千个 Scratch 脚本:代码剖析
Advertisement 728x90

基于LuaJIT与LÖVE2D的高性能可视化解释器:在低端硬件上运行12,000个脚本

一位开发者实现了一个可视化积木编程编辑器,能够在低端笔记本电脑的单核CPU上稳定以30 FPS运行12,289个包含IF、ROTATE和WHILE TRUE积木的脚本。该项目基于LuaJIT和LÖVE2D库构建,确保跨平台兼容性:Windows、macOS、Linux、Android、iOS。解释器与编辑器分离,独立的EXE构建已可运行。

选择LuaJIT是因为其字节码和即时编译带来的高执行速度。LÖVE2D因其简单语法和作者在Roblox Studio的经验而被采用。VS Code作为主要编辑器使用。

项目架构

项目分为模块以实现可扩展性:

Google AdInline article slot
  • Main.lua — 主编辑器。
  • Micropaint.lua — 精灵编辑器。
  • GameLoader.lua — 游戏加载器。
  • BlockList.lua — 积木注册表(518行,包含渲染函数)。

GUI通过love.graphics手动实现,未使用外部库。按钮渲染示例:

--按钮:加载
love.graphics.rectangle("line", 230, 10, 120, 40)
love.graphics.print("加载", 240, 10)
--按钮:创建
love.graphics.rectangle("line", 360, 10, 100, 40)
love.graphics.print("创建", 370, 10)

点击处理带详细注释:

--按钮 创建
if x > 360 and x < 460 and y > 10 and y < 50 then
    createNewGame()
end
--按钮 加载
if x > 230 and x < 350 and y > 10 and y < 50 then
    if gload() == "suc" then
        GameLoaded = true
        love.window.showMessageBox("就绪!","游戏名为 "..game.name.." 已加载")
    else
        love.window.showMessageBox("错误","加载过程中发生错误")
    end
end

注释简化了维护,尽管GUI库会使代码更简洁。

Google AdInline article slot

积木结构与渲染

积木通过表格和元数据描述。随机数积木示例:

t[#t+1] = {
    type = 3, --积木类型 1 - 常规 2 - 执行 3 - 数据
    isStarter = false, --这是脚本起始积木吗?
    DisplayName = "随机值(从,到)", -- 显示名称
    name = "random", -- 系统名称
    args = 2, -- 参数数量
    containBlocksIn = false, -- 内部包含积木
    color = {0, 0, 0}
}

积木支持嵌套:参数可以是其他积木。通过RenderBlock()渲染,尝试递归(部分实现)。白色方块是输入字段。

解释器为简化起见在单线程中运行。积木分为类型:常规、执行、数据。参数执行是递归的,结果存储在args[i].data中。

Google AdInline article slot

积木解释

解释器代码检查name并计算值:

if name == "getX" then --获取X
        return sprite.pos.x
    elseif name == "getY" then --获取Y
        return sprite.pos.y
    elseif name == "random" then --随机
        return love.math.random(tonumber(args[1].data),tonumber(args[2].data))
    elseif name == "getrotation" then --旋转
        return sprite.rotation
    elseif name == "getcostume" then --服装
        return sprite.costumeNumber
    elseif name == "getsize" then --大小
        return sprite.size
    elseif name == "mathplus" then --加
        return tonumber(args[1].data) + tonumber(args[2].data)
    elseif name == "mathminus" then --减
        return tonumber(args[1].data) - tonumber(args[2].data)
    elseif name == "mathmultiply" then --乘
        return tonumber(args[1].data) * tonumber(args[2].data)
    elseif name == "mathdivide" then --除
        return tonumber(args[1].data) / tonumber(args[2].data)
end

Lua数组索引从1开始。LÖVE2D默认不支持俄语 — 通过love.graphics.newFont使用系统字体(如Comic Sans等)。

构建与部署

EXE构建:

  • Love Fusion将DLL和文件打包成EXE。
  • Enigma Virtual Box将所有内容合并为单个可执行文件。

计划支持APK/HTML。演示:12,300个线程包含IF/ROTATE/WHILE TRUE积木,以30 FPS运行。

关键点:

  • LuaJIT + LÖVE2D使弱CPU能运行12k+脚本。
  • 模块化架构:解释器与编辑器分离。
  • 通过love.graphics手动实现GUI,嵌套积木递归执行。
  • 跨平台构建至EXE/APK/HTML。
  • 积木类型化(数据/执行),参数递归计算。

— Editorial Team

Advertisement 728x90

继续阅读