VisionGal 引擎VisionGal 引擎
主页
快速开始
API文档
主页
快速开始
API文档
  • 快速开始

快速开始

visiongal

介绍

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

screenshot1screenshot1

功能特点

  • 可视化编辑器:提供完善的可视化编辑器,支持实时预览编辑效果,方便创作和管理视觉小说内容
  • 自定义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")
  • 使用 :开始动画( 动画参数, 持续时间, 动画曲线, 循环次数, 循环是否改变动画方向 ) 可以开始一个动画。
  • 使用 :添加动画关键帧( 动画参数, 持续时间, 动画曲线 ) 可以添加一个动画关键帧。
最近更新:: 2025/11/2 16:25
Contributors: 梦旅缘心