快速开始
![]()
介绍
VisionGal 是一个功能强大的视觉小说引擎,专为创建高质量视觉小说和交互式叙事体验而设计。引擎采用 C++ 开发,剧情脚本使用Lua进行编写,具有良好的跨平台性和可扩展性。


功能特点
- 可视化编辑器:提供完善的可视化编辑器,支持实时预览编辑效果,方便创作和管理视觉小说内容
- 自定义UI界面:全部自定义的UI界面,用类似html和css的语法来定义界面,用Lua脚本定义界面的行为
- 剧情脚本语言:支持丰富功能的剧情脚本语言,优雅的链式语法编写剧情
- 中文支持:提供完善的中文支持,包括中文语法,中文字体,中文界面等
- MIT协议:开源的MIT协议,开发的游戏版权属于个人所有,你也可以修改引擎源代码,完全不受限制
快速开始
使用安装包
在VisionGal Github Releases页面下载最新的安装包,根据你的操作系统选择对应的安装包
编译 VisionGal 引擎
VisionGal 引擎使用 CMake构建,库依赖使用 vcpkg 管理,所以需要使用 vcpkg 来安装依赖库
安装依赖库
vcpkg install freetype
vcpkg install sdl3
vcpkg install sdl3-image[jpeg,png,tiff,webp]
vcpkg install rmlui[freetype]
vcpkg install ffmpeg
安装ffmpeg的时间可能会比较长,需要耐心等待,因为需要编译ffmpeg的源代码。
构建
安装完依赖库后,使用Git和CMake按以下命令构建VisonGal
git clone https://github.com/DarlingZeroX/VisionGal
cd VisionGal
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE="<path-to-vcpkg>/scripts/buildsystems/vcpkg.cmake"
cmake --build Build
第三行的 <path-to-vcpkg> 替换为你实际的vcpkg安装路径,例如:C:\vcpkg
编译运行引擎
运行VGLauncher程序,启动编辑器启动器。
开始使用VisionGal引擎
启动示例项目
运行VGLauncher程序,启动编辑器启动器,双击示例项目,即可打开示例项目。
运行场景
在编辑器中,点击上方中间的三角形按钮,即可运行项目。
在运行项目时,你可以在编辑器中查看项目的运行效果。
编辑指定场景
在内容浏览器中双击打开 主菜单场景 或者 游戏场景 资产文件,即可编辑指定场景。
运行游戏剧情场景
在内容浏览器双击打开 游戏场景 资产文件,运行场景即可查看示例剧情场景。
运行示例剧情脚本
- 在 内容浏览器 面板根目录双击打开打开游戏场景资产文件
- 在场景浏览器中点击 Galgame引擎, 可以发现 细节 面板已经显示了一些内容。
- 在内容浏览器打开 剧情脚本 目录后,选择目录下的一个 Lua脚本 资产文件,将脚本拖放到 细节 面板的 剧情脚本 编辑区域,可以发现剧情脚本的路径已经变成了被拖动的脚本的路径。
- 然后在编辑器中运行场景,即可游玩对应示例剧情脚本场景。
编写剧情脚本
VisionGal引擎的脚本使用Lua语言编写,大部分剧情脚本都可以用中文语法进行编写。
采用面向对象以及链式调用的语法,编写起来非常方便。
创建或者编辑剧情脚本资产文件
在内容浏览器打开 剧情脚本 目录后,双击打开目录下的 Lua脚本 资产文件,即可编辑示例剧情脚本。
或者在内容浏览器中右键菜单创建一个新的 Galgame剧情脚本 资产文件,即可开始编写新的剧情脚本。
基础脚本
local 梦缘 = GalGame:创建人物('梦缘')
return function()
梦缘:说('你好,Galgame')
梦缘:说('你可以在这里添加剧情内容')
return
end
创建人物
- 第一行
local 梦缘 = GalGame:创建人物('梦缘')是创建一个人物,用于在剧情中使用。
你可以根据需要创建多个人物,用于在剧情中使用。 - 由于剧情脚本采用面向对象,创建人物都需要使用
GalGame:创建人物('人物名称')方法,
其中人物名称是你为人物对象指定的名称,用于在剧情中引用人物对象。 - 人物对象创建后,会返回一个人物对象,比如上面用
local 梦缘 =接收了这个人物对象,可以任意命名,但推荐使用人物名称作为变量名。 - 你可以根据需要创建多个人物对象,每个人物对象都有自己的属性和方法,用于在剧情中使用。
编写剧情主体
return function()和end是每个剧情脚本必须包含的部分,引擎才能运行这个剧情脚本return function()到end之间的代码是剧情脚本的主体,你可以在其中添加剧情内容。
你可以在主体中使用人物对象的方法,例如:梦缘:说('你好')来让人物零在对话框显示文本。
你也可以使用其他的Lua语法,例如:if语句,for循环,函数调用等。
基础语法
- 所有的脚本剧情都需要在
return function()和end之间编写,引擎才能运行这个脚本。 - 很多语法都是采用链式调用的方式,一般在对象后面用 : 符号加上一个方法,例如:
梦缘:说('你好')来让人物零在对话框显示文本。 - 很多方法都是用
GalGame这个对象来调用的,例如:GalGame:显示背景('图片/背景/教室背景.png')来显示背景图片。
显示背景图片
local 梦缘 = GalGame:创建人物('梦缘')
return function()
GalGame:显示背景('图片/背景/教室背景.png')
梦缘:说('显示了教室背景')
return
end
- 你可以使用
GalGame:显示背景('背景图片路径')方法来显示游戏背景图片。 其中背景图片路径是你为背景图片指定的路径,用于在剧情中引用背景图片。 - 图片路径是相对内容浏览器根目录的相对路径。
- 推荐将图片放在 图片/背景 目录下,方便管理。
显示人物立绘
local 旁白 = GalGame:创建人物('旁白')
local 梦女 = GalGame:创建人物('梦女')
local 缘心 = GalGame:创建人物('缘心')
return function()
--- 添加人物立绘
梦女:添加立绘('姿势1','图片/立绘/女孩1.png')
梦女:添加立绘('姿势2','图片/立绘/女孩2.png')
缘心:添加立绘('姿势1','图片/立绘/男孩1.png')
缘心:添加立绘('姿势2','图片/立绘/男孩2.png')
-- 剧情开始
GalGame:显示背景('图片/背景/教室背景.png')
旁白:说('(放学后的教室……夕阳透过窗子,尘埃在空气里闪着光。)')
缘心:显示立绘('姿势1')
缘心:说("梦女,你怎么还在这儿?不是说要和朋友一起回去的吗?")
缘心:显示立绘('姿势2'):设置位置X(-320)
梦女:显示立绘('姿势1'):设置位置X(320)
梦女:说("嗯……她们先走了。我想一个人待一会儿。")
梦女:显示立绘('姿势2')
梦女:说("不过,现在你来了,也不算是一个人了呢。")
return
end
- 你可以使用
人物对象:添加立绘('立绘名称','图片路径')方法来添加人物立绘。 其中立绘名称是你为立绘指定的名称,用于在剧情中引用立绘。图片路径是你为立绘指定的路径,用于在剧情中引用立绘图片。 - 推荐将图片放在 图片/立绘 目录下,方便管理。
- 你可以使用
人物对象:显示立绘('立绘名称')方法来显示人物立绘。 其中立绘名称是你为立绘指定的名称,用于在剧情中引用立绘。 - 立绘第一次默认显示在正中间,后续可以在
显示立绘后使用设置位置X(x)和设置位置Y(y)方法来设置立绘的位置。 - 后面的立绘默认显示在之前的立绘的位置上。
运行场景后可以显示立绘了,但是显示的立绘很生硬,并且后面的立绘与前面的立绘重叠了
这是因为引擎不会自动隐藏前面的立绘,也不会添加默认显示立绘的方式,这需要我们在剧情中手动添加 下面添加顺畅的显示立绘和隐藏立绘的方式
顺畅的显示和隐藏立绘
local 旁白 = GalGame:创建人物('旁白')
local 梦女 = GalGame:创建人物('梦女')
local 缘心 = GalGame:创建人物('缘心')
return function()
--- 添加人物立绘
梦女:添加立绘('姿势1','图片/立绘/女孩1.png')
梦女:添加立绘('姿势2','图片/立绘/女孩2.png')
缘心:添加立绘('姿势1','图片/立绘/男孩1.png')
缘心:添加立绘('姿势2','图片/立绘/男孩2.png')
-- 剧情开始
GalGame:显示背景('图片/背景/教室背景.png')
旁白:说('(放学后的教室……夕阳透过窗子,尘埃在空气里闪着光。)')
缘心:显示立绘('姿势1'):随着('淡入 0.6')
缘心:说("梦女,你怎么还在这儿?不是说要和朋友一起回去的吗?")
-- 隐藏立绘
缘心.当前立绘:随着('淡出 0.6')
缘心:显示立绘('姿势2'):随着('淡入 0.6'):设置位置X(-320)
梦女:显示立绘('姿势1'):随着('淡入 0.6'):设置位置X(320)
梦女:说("嗯……她们先走了。我想一个人待一会儿。")
-- 隐藏立绘
梦女.当前立绘:随着('淡出 0.6')
梦女:显示立绘('姿势2'):随着('淡入 0.6')
梦女:说("不过,现在你来了,也不算是一个人了呢。")
return
end
- 你可以使用
人物对象.当前立绘:随着('淡出 0.6')方法来隐藏人物立绘。 其中人物对象是你创建的人物对象,用于在剧情中引用人物。 - 你可以使用
人物对象.当前立绘:随着('淡入 0.6')方法来显示人物立绘,
也可以直接在人物对象:显示立绘('姿势'):随着('淡入 0.6')显示立绘后追加淡入来显示立绘 其中人物对象是你创建的人物对象,用于在剧情中引用人物。
引擎不会自动隐藏前面的立绘,但是我们可以在显示新的立绘前先隐藏当前的立绘,来实现顺畅的显示和隐藏立绘。 虽然这样可以顺畅的显示和隐藏立绘,但是不够简洁,因为我们需要在每个显示立绘的语句前都添加隐藏立绘的语句。
简洁的显示人物立绘
为了简化隐藏和显示人物立绘这个过程,我们可以为人物添加一个回调方法来自动淡入和淡出立绘,每当人物显示立绘时,就会使用这个。
我们先在剧情脚本开头添加两个函数
-- 当显示新立绘时,自动对新的立绘使用淡入效果,对上一个立绘使用淡出效果
游戏立绘 = 游戏立绘 or {{ }} --namespace
function 游戏立绘.立绘显示回调(人物立绘)
return 人物立绘:随着('淡入 0.6')
end
function 游戏立绘.立绘隐藏回调(人物立绘)
return 人物立绘:随着('淡出 0.6')
end
然后在添加人物立绘后面添加回调方法
-- 添加人物立绘显示和隐藏回调
梦女:添加立绘显示回调(游戏立绘.立绘显示回调)
梦女:添加立绘隐藏回调(游戏立绘.立绘隐藏回调)
完整的剧情脚本如下
local 旁白 = GalGame:创建人物('旁白')
local 梦女 = GalGame:创建人物('梦女')
local 缘心 = GalGame:创建人物('缘心')
-- 当显示新立绘时,自动对新的立绘使用淡入效果,对上一个立绘使用淡出效果
游戏立绘 = 游戏立绘 or {{ }} --namespace
function 游戏立绘.立绘显示回调(人物立绘)
return 人物立绘:随着('淡入 0.6')
end
function 游戏立绘.立绘隐藏回调(人物立绘)
return 人物立绘:随着('淡出 0.6')
end
return function()
--- 添加人物立绘
梦女:添加立绘('姿势1','图片/立绘/女孩1.png')
梦女:添加立绘('姿势2','图片/立绘/女孩2.png')
-- 添加人物立绘显示和隐藏回调
梦女:添加立绘显示回调(游戏立绘.立绘显示回调)
梦女:添加立绘隐藏回调(游戏立绘.立绘隐藏回调)
缘心:添加立绘('姿势1','图片/立绘/男孩1.png')
缘心:添加立绘('姿势2','图片/立绘/男孩2.png')
-- 添加人物立绘显示和隐藏回调,当显示新立绘时
缘心:添加立绘显示回调(游戏立绘.立绘显示回调)
缘心:添加立绘隐藏回调(游戏立绘.立绘隐藏回调)
-- 剧情开始
GalGame:显示背景('图片/背景/教室背景.png')
旁白:说('(放学后的教室……夕阳透过窗子,尘埃在空气里闪着光。)')
缘心:显示立绘('姿势1')
缘心:说("梦女,你怎么还在这儿?不是说要和朋友一起回去的吗?")
缘心:显示立绘('姿势2'):设置位置X(-320)
梦女:显示立绘('姿势1'):设置位置X(320)
梦女:说("嗯……她们先走了。我想一个人待一会儿。")
梦女:显示立绘('姿势2')
梦女:说("不过,现在你来了,也不算是一个人了呢。")
return
end
这样,当人物显示立绘时,就会自动使用淡入效果,隐藏当前立绘时,就会自动使用淡出效果。
转场效果
推入转场
local 梦女 = GalGame:创建人物('梦女')
return function()
GalGame:显示背景('图片/背景/教室背景.png')
梦女:说('测试开始')
GalGame:显示背景('图片/背景/走廊背景2.png'):转场('向左推入 2.0')
梦女:说('当前测试:向左推入转场')
GalGame:显示背景('图片/背景/学校操场.png'):转场('向右推入 2.0')
梦女:说('当前测试:向右推入转场')
GalGame:显示背景('图片/背景/走廊背景1.png'):转场('向下推入 2.0')
梦女:说('当前测试:向下推入转场')
GalGame:显示背景('图片/背景/教室背景.png'):转场('向上推入 2.0')
梦女:说('当前测试:向上推入转场')
return
end
- 你可以在显示背景后面添加
:转场('向左推入 2.0')方法来实现向推入转场效果。
其中的向左推入是转场的类型
其中的2.0是转场时间,单位是秒。你可以根据需要调整转场时间。 - 目前的推入转场效果只有向左、向右、向下、向上四种。
溶解转场
local 梦女 = GalGame:创建人物('梦女')
return function()
GalGame:显示背景('图片/背景/教室背景.png')
梦女:说('测试开始')
GalGame:显示背景('图片/背景/走廊背景1.png'):随着('向下滚动 1.0'):转场('溶解 2.0')
梦女:说('当前测试:溶解转场以及向下滚动')
-- 当前测试:黑屏溶解转场
GalGame:转场命令('屏幕','淡出 1.0')
GalGame:转场命令('屏幕','淡入 1.0')
GalGame:显示背景('图片/背景/走廊背景2.png')
GalGame:等待(2.0)
梦女:说('当前测试:黑屏溶解转场')
return
end
- 你可以在显示背景后面添加
:随着('向下滚动 1.0')方法来实现向下滚动效果。
其中的向下滚动是滚动的类型
其中的1.0是滚动时间,单位是秒。你可以根据需要调整滚动时间。 GalGame:转场命令('屏幕','淡出 1.0')是直接使用Galgame对象来进行转场,
其中的屏幕是转场的目标,转场的目标有三个,分别是屏幕、前景、背景,这里是屏幕
其中的淡出 1.0是转场的类型和时间,这里是淡出效果,时间是1秒GalGame:转场命令('屏幕','淡入 1.0')会在淡出转场完成后执行GalGame:显示背景('图片/背景/走廊背景2.png')是转场作用的目标背景GalGame:等待(2.0)会等待2秒,确保转场完成后再执行后续代码
自定义转场图片
local 梦女 = GalGame:创建人物('梦女')
return function()
GalGame:显示背景('图片/背景/教室背景.png')
梦女:说('测试开始')
GalGame:图片转场命令('背景','图片/转场/WIP_BLTR.png','2.0')
GalGame:显示背景('图片/背景/走廊背景1.png')
梦女:说('当前转场测试:图片/转场/WIP_BLTR')
GalGame:图片转场命令('背景','图片/转场/WIP_BRTL.png','2.0')
GalGame:显示背景('图片/背景/学校操场.png')
梦女:说('当前转场测试:图片/转场/WIP_BLTR')
return
end
- 使用
GalGame:图片转场命令('背景','图片/转场/WIP_BLTR.png','2.0')来自定义图片转场。
其中的背景是转场的目标 其中的图片/转场/WIP_BLTR.png是自定义的转场图片路径
其中的2.0是转场时间,单位是秒。你可以根据需要调整转场时间。
图层
目前VisionGal默认的图层有三个,分别是屏幕、前景、背景
- 屏幕图层是最前面的图层,作用在屏幕上的效果会显示在UI前面,包括游戏的UI对话框。
- 前景图层是在屏幕图层下的图层,位于中间的图层,作用在前景上的元素会显示在UI后面,一般是用于显示人物立绘。
- 背景图层是在前景图层下的图层,位于最下面的图层,一般用于显示背景图片。
在图层显示图片
local 梦女 = GalGame:创建人物('梦女')
游戏立绘 = 游戏立绘 or {{ }} --namespace
function 游戏立绘.立绘显示回调(人物立绘)
return 人物立绘:随着('淡入 0.6')
end
function 游戏立绘.立绘隐藏回调(人物立绘)
return 人物立绘:随着('淡出 0.6')
end
return function()
梦女:添加立绘('女孩1','图片/立绘/女孩1.png')
梦女:添加立绘显示回调(游戏立绘.立绘显示回调)
梦女:添加立绘隐藏回调(游戏立绘.立绘隐藏回调)
梦女:显示立绘('女孩1')
GalGame:显示背景('图片/背景/教室背景.png')
梦女:说('测试开始')
GalGame:图片转场命令('背景','图片/转场/WIP_BLTR.png','2.0')
GalGame:显示背景('图片/背景/走廊背景1.png')
梦女:说('当前转场测试:在背景层进行转场,不影响立绘')
GalGame:显示前景('图片/背景/学校操场.png'):转场('溶解 2.0')
梦女:说('当前转场测试:在前景层显示图片')
GalGame:显示屏幕('图片/立绘/女孩1.png')
梦女:说('当前测试:在屏幕前显示立绘')
end
- 使用
GalGame:显示前景('图片/背景/学校操场.png'):转场('溶解 2.0')可以在前景层显示图片并进行溶解转场。 - 使用
GalGame:显示屏幕('图片/立绘/女孩1.png')可以在屏幕前显示立绘。
在不同图层上转场
local 梦女 = GalGame:创建人物('梦女')
游戏立绘 = 游戏立绘 or {{ }} --namespace
function 游戏立绘.立绘显示回调(人物立绘)
return 人物立绘:随着('淡入 0.6')
end
function 游戏立绘.立绘隐藏回调(人物立绘)
return 人物立绘:随着('淡出 0.6')
end
return function()
梦女:添加立绘('女孩1','图片/立绘/女孩1.png')
梦女:添加立绘显示回调(游戏立绘.立绘显示回调)
梦女:添加立绘隐藏回调(游戏立绘.立绘隐藏回调)
梦女:显示立绘('女孩1')
GalGame:显示背景('图片/背景/教室背景.png')
梦女:说('测试开始')
GalGame:图片转场命令('背景','图片/转场/WIP_BLTR.png','2.0')
GalGame:显示背景('图片/背景/走廊背景1.png')
梦女:说('当前转场测试:在背景层进行转场,不影响立绘')
GalGame:转场命令('背景','向上推入 2.0')
GalGame:显示背景('图片/背景/走廊背景2.png')
梦女:说('当前转场测试:在背景层进行转场,不影响立绘')
GalGame:转场命令('前景','向左推入 2.0')
GalGame:显示背景('图片/背景/学校操场.png')
梦女:说('当前转场测试:在前景层进行转场,影响立绘')
GalGame:转场命令('屏幕','向右推入 2.0')
GalGame:显示背景('图片/背景/学校操场.png')
梦女:说('当前转场测试:在屏幕层使用转场图片进行转场,影响全屏')
end
- 使用
GalGame:转场命令('背景','向上推入 2.0')可以在背景层进行向上推入转场。 - 使用
GalGame:转场命令('前景','向左推入 2.0')可以在前景层进行向左推入转场。 - 使用
GalGame:转场命令('屏幕','向右推入 2.0')可以在屏幕层使用转场图片进行向右推入转场。
在图层上显示颜色
local 梦女 = GalGame:创建人物('梦女')
游戏立绘 = 游戏立绘 or {{ }} --namespace
function 游戏立绘.立绘显示回调(人物立绘)
return 人物立绘:随着('淡入 0.6')
end
function 游戏立绘.立绘隐藏回调(人物立绘)
return 人物立绘:随着('淡出 0.6')
end
return function()
梦女:添加立绘('女孩1','图片/立绘/女孩1.png')
梦女:添加立绘显示回调(游戏立绘.立绘显示回调)
梦女:添加立绘隐藏回调(游戏立绘.立绘隐藏回调)
梦女:显示立绘('女孩1')
GalGame:显示背景('图片/背景/教室背景.png')
梦女:说('测试开始')
GalGame:图片转场命令('背景','图片/转场/WIP_BLTR.png','2.0')
local 红色 = float4.new(1.0, 0.0, 0.0, 1.0)
GalGame:显示背景(红色)
梦女:说('当前测试:在背景层显示红色')
GalGame:图片转场命令('前景','图片/转场/WIP_BLTR.png','2.0')
local 绿色 = float4.new(0.0, 1.0, 0.0, 1.0)
GalGame:显示前景(绿色)
梦女:说('当前测试:在前景层显示绿色')
GalGame:图片转场命令('屏幕','图片/转场/WIP_BLTR.png','2.0')
local 蓝色 = float4.new(0.0, 0.0, 1.0, 1.0)
GalGame:显示屏幕(蓝色)
梦女:说('当前测试:在屏幕层显示蓝色')
end
- 使用
float4.new(r, g, b, a)可以创建一个颜色值,
其中r、g、b分别是红色、绿色、蓝色通道的取值(0.0 到 1.0)a是透明度通道的取值(0.0 到 1.0)。 - 使用
GalGame:显示背景(颜色)和GalGame:显示前景(颜色)以及GalGame:显示屏幕(颜色)可以在不同图层上显示不同的颜色。
动画
基本动画
缘心:显示立绘('疲惫')
:开始动画( {位置偏移X = 200}, 1.3, "弹跳 inout", 3, true)
:添加动画关键帧({位置偏移Y = 100}, 1.3, "弹跳 inout")
- 使用
:开始动画( 动画参数, 持续时间, 动画曲线, 循环次数, 循环是否改变动画方向 )可以开始一个动画。 - 使用
:添加动画关键帧( 动画参数, 持续时间, 动画曲线 )可以添加一个动画关键帧。