示例
虽然 Naninovel 包已经包含了几个 演示示例 来帮助您上手视觉小说和对话模式这两种使用场景,但我们还提供了一组额外的专用示例来演示常见的开发用例。请继续阅读,了解如何访问这些示例以及每个示例的简要说明。
访问示例
从 下载归档 下载高级示例项目。
解压下载的目录并在 Unity 编辑器中将其打开。项目加载后,打开 Assets/Scenes/Main.unity 场景并进入播放模式。您将看到我们 演示项目 的标题屏幕。您可以开始演示,或单击“SAMPLES”按钮浏览可用的示例,下文将逐一介绍这些示例。
Addressable
此示例展示了如何手动向 Addressable 提供者 注册 Naninovel 资源(不使用资源编辑器菜单)并从远程主机提供资产。
请注意,虽然示例项目中的大多数资源未在资源管理器菜单中分配:
— 但它们仍然可以用相同的方式在剧本脚本中访问:
@back Snow这之所以可行,是因为这些资产被分配了 Naninovel 资源地址:
透视场景
此示例展示了一个由多个带动画的环境精灵组成的通用背景、透视模式下的摄像机渲染以及散景(景深)效果。背景存储在 Content/Backgrounds/Perspective 目录下。
编译器本地化
要在示例项目中激活编译器本地化,请将 Settings/Naninovel/CompilerRu 资产分配给脚本配置菜单中的 Compiler Localization 字段。然后重新启动 Unity 编辑器和 VS Code 扩展。现在您可以使用 VS Code 打开项目并运行 Compiler Localization 示例剧本。
E2E
E2E Tests 示例展示了如何设置 自动化端到端测试 套件并使用大多数可用的 API。
测试脚本存储在 Scripts/E2E 文件夹下。请注意放置在该文件夹中的 .asmdef 文件:这是在 Unity 测试环境下编译测试源代码所必需的。还要注意 Packages/manifest.json 文件中的 testables 条目,它将测试程序集公开给 Unity 的测试运行器。
通用 Actor
请查看 Content/Backgrounds/Beach 和 Content/Backgrounds/Perspective 通用背景 以及 Content/Characters/Kohaku/K3D 通用角色,它们展示了如何借助通过 Unity 的 Animator 制作的 3D 模型和动画来设置和使用通用 Actor 实现。
对话模式
一个示例项目,演示了 Naninovel 既用作 3D 冒险游戏的嵌入式对话系统,又用作可切换的独立小说模式。
所有特定于项目的示例脚本都存储在 Scripts/Runtime/DialogueMode 文件夹中。
库存
虽然库存系统超出了视觉小说的范围,但我们收到了许多关于如何将其与 Naninovel 集成的请求和问题。库存示例演示了如何创建和集成库存扩展,无需修改引擎源代码,即可将扩展添加到已安装的 Naninovel 中。
注意
该库存系统不是独立产品,也不是 Naninovel 的一部分。您可以用它来学习如何扩展和自定义引擎,但不要指望它是可直接用于生产的库存系统解决方案。如果您正在寻找这样的解决方案,请 查看 Asset Store 或从头开始创建一个自定义的。
此示例项目展示了如何制作具有网格布局、分页和拖放窗口的自定义库存 UI,添加自定义引擎服务和相关配置菜单,添加输入绑定,将状态管理交给引擎,以及编写自定义剧本命令和表达式查询。
要从模板创建预制的库存 UI,请使用 Create -> Naninovel -> Inventory -> Inventory UI 资产上下文菜单。然后在编辑器中通过 Naninovel -> Resources -> UI 将预制件添加到 Naninovel UI 资源中。添加后,可以像所有其他 UI 一样使用 @showUI 和 @hideUI 命令显示/隐藏该 UI。
Inventory UI 组件具有 Capacity 属性,您可以通过它更改库存中的栏位数量。栏位网格通过 Content/InventoryGrid 游戏对象进行配置(栏位数量和布局、每页栏位数等)。窗口拖放行为可以通过附加到 Content 游戏对象的 Drag Drop 组件进行配置(或禁用)。
库存物品预制件可以使用 Create -> Naninovel -> Inventory -> Inventory Item 资产上下文菜单创建。然后需要通过编辑器中的 Naninovel -> Resources -> Inventory 将物品预制件分配为库存资源。
如果您有很多物品,并且通过编辑器菜单分配它们不方便,您可以将它们放在 Resources/Naninovel/Inventory 文件夹中,它们将自动公开给引擎。您还可以使用子文件夹来组织它们;在这种情况下,在剧本脚本中引用它们时请使用正斜杠(/)。例如,存储为 Resources/Naninovel/Inventory/Armor/FullPlate.prefab 的物品可以在脚本中引用为 Armor/FullPlate。
也可以使用 Addressable 资产系统 手动公开资源。要公开资产,请为其分配一个地址,该地址等于使用上述方法时的路径,但省略 Resources/ 部分。例如,要公开 FullPlate.prefab 物品,请为预制件分配地址 Naninovel/Inventory/FullPlate。请注意,在编辑器中时,始终首先使用特殊的“Editor”资源提供者;只有未通过编辑器菜单分配的资源才会尝试使用 Addressable 提供者。
每个物品都有一个 Stack Count Limit 属性来限制这种类型的物品可以在单个库存栏位中堆叠多少个,以及一个 On Item Used Unity 事件,该事件在物品被使用时调用(通过 @useItem 命令或当玩家单击库存中的物品时)。下面是一个示例,说明如何使用 Play Script 组件设置该事件,以便在使用物品后将其移除、生成故障特殊效果并打印文本消息。
您可以使用 @addItem 命令向库存添加物品,并使用 @removeItem(或 @removeItemAt、@removeAllItems)将其移除。物品 ID 等于物品预制件名称。库存栏位 ID 等于网格栏位索引(例如,第一个栏位是 0,第二个是 1,依此类推)。
为了方便起见,还提供了 itemExist() 和 itemCount() 自定义 表达式查询:前者检查物品是否存在于库存中,后者返回现有物品的数量。
以下是示例项目中的脚本:
# Start
请选择一个行动。[>]
@choice "拾起剑" lock:itemExist("Sword")
@addItem Sword
@choice "拾起盔甲" lock:itemExist("Armor")
@addItem Armor
@choice "冒险在等待,出发吧!"
# Adventure
@if itemExist("Sword")
@set monstersSlayed={ itemExist("Armor") ? random(3,5) : 2 }
@addItem Food amount:{monstersSlayed}
你遇到了 {monstersSlayed} 只怪物,并用剑将它们全部斩杀。
@goto #Start
@else
但是你没有武器!你被怪物打败了。
@goto #StartLive2D
该示例演示了如何在 Naninovel 中使用 Live2D 角色。您可以在 Content/Characters/Hiyori 和 Content/Characters/Senko 目录中找到它们。
本地化
- 生成的本地化文档存储在
Content/Localization目录中。 - 生成的表格存储在示例项目根目录下的“Sheets”目录中。
- 本地化专用的字体存储在
Content/Fonts中。
为本地化工具选择的文件夹:
| 文件夹 | 路径 |
|---|---|
| Script Folder (input) | Assets/Scripts/Scenario |
| Text Folder (input) | Assets/Content/Text |
| Locale Folder (output) | Assets/Content/Localization |
为电子表格工具选择的文件夹:
| 文件夹 | 路径 |
|---|---|
| Input Scripts Folder | Assets/Scripts/Scenario |
| Input Text Folder | Assets/Content/Text |
| Input Localization Folder | Assets/Content/Localization |
| Output Folder | Sheets |
地图
此示例展示了如何在不编写任何 C# 脚本的情况下实现交互式地图。
地图实现为存储在 Content/UI/Map 的自定义 UI。地图上的地点是放置在 UI 中的常规 Unity 按钮。
按钮的单击和悬停事件由 Naninovel 的 Play Script 组件处理。
地点的可用性由附加到按钮的 Variable Events 组件控制。
RTL
RTL 打印机存储在 Content/Printers/RTL。
Actor 着色器
该示例展示了如何创建和使用用于添加自定义过渡效果的纹理着色器以及支持光照和自发光的精灵着色器;后者用于为背景 Actor 模拟昼夜变化。
自定义着色器存储在 Scripts/Shaders 目录中。
背景纹理在 alpha 层中存储了一个自发光遮罩,自定义着色器使用该遮罩来确定哪些区域应忽略全局光并自行发光。
昼夜时段由 Scripts/Runtime/Shader/TimeOfDay.cs 控制,它允许为一天 24 小时中的任意时间点配置光照颜色和发光强度。
组件 API 通过 Scripts/Runtime/Shader/SetHour.cs 自定义命令公开给剧本脚本,从而可以使用 @hour 命令设置小时,例如:
; 在 3 秒内将当前时间设置为 18:00(下午 6:00)。
@hour 18 time:3Spine
该示例演示了如何在 Naninovel 中使用 Spine 角色。您可以在 Content/Characters/Spine 目录中找到它们。
UI
该示例包含以下全新自定义 UI 和修改后的内置 UI 的示例:
- 标题屏幕
- 音乐画廊
- 制作人员名单
- Chat 打印机中的时间戳
- 自定义选项处理程序
- 显示消息中的表情符号
- 显示消息中的字体变体
- 日历
所有示例 UI 都存储在 Content/UI 中。
分层 Actor
可在 Content/Characters/Miho 目录中找到分层角色,在 Content/Backgrounds/Particles 中找到以摄像机渲染模式设置的分层背景。
切片 Actor
可在 Content/Characters/Kohaku/Diced 中找到切片角色和图集。
视频 Actor
视频背景存储在 Content/Backgrounds/Video 目录中,而视频 Actor 可以在 Content/Characters/Ball 目录中找到。
场景背景
可在 Content/Backgrounds/Scene 目录中找到场景背景。
过渡效果
可在 Scripts/Scenario/Transitions 剧本脚本中找到依次应用所有可用过渡效果的演示。
自动配音
EN 和 JA 语言环境的语音剪辑存储在 Content/Audio/Voice 下。
进入“Auto Voicing”示例并尝试在游戏设置中切换语音语言。
音乐前奏
演示如何使用 @bgm 命令的 intro 参数,以便在循环播放音轨的主体部分之前先播放一次前奏部分。
背景匹配
背景匹配功能的演示,展示了不同纵横比的背景如何与显示视口匹配。
可视化脚本
Visual Scripting(以前称为 Bolt)是 Unity 默认捆绑的内置包。它让您能够使用基于单元的图来创建游戏或应用程序的逻辑,程序员和非程序员都可以使用,无需编写代码。
首先,确保在 Package Manager 中安装了 Visual Scripting 包。
将 Elringus.Naninovel.Runtime 库添加到 Visual Scripting 项目设置中的 Node Library 列表中。这是将引擎类型和 API 公开给可视化脚本图所必需的。
Visual Scripting 不会自动公开库中的所有可用类型,因此请将所需的 Naninovel 类型添加到同一设置菜单中的 Type Options 列表中。在下面的示例中,我们添加了 Engine、Script Player Interface 和 Script Player Extensions,但您可能需要更多类型,例如其他 引擎服务接口、配置等。
添加库和类型后,不要忘记重新生成单元以应用更改。
在 Visual Scripting 设置中添加 Naninovel 库和类型后,引擎 API 将出现在图视图下的模糊查找器中,并且可以像其他 Unity 或第三方 API 一样使用。下面是一个初始化引擎并播放脚本的示例。在尝试此示例之前,请确保禁用 Initialize On Application Load 并删除 Title UI。
如果您希望从剧本脚本向可视化脚本图或状态机发送事件,下面是一个 自定义命令 的示例,它将尝试查找具有所提供名称的游戏对象,并发送具有指定名称和参数的事件:
[Serializable, Alias("bolt")]
public class BroadcastBoltEvent : Command
{
[Alias("object"), RequiredParameter]
public StringParameter GameObjectName;
[Alias("name"), RequiredParameter]
public StringParameter EventName;
[Alias("args")]
public StringListParameter Arguments;
public override Awaitable Execute (ExecutionContext ctx)
{
var gameObject = GameObject.Find(GameObjectName);
if (!gameObject)
{
Debug.LogError($"Failed to broadcast '{EventName}' bolt event: '{GameObjectName}' game object is not found.");
return Async.Completed;
}
CustomEvent.Trigger(gameObject, EventName, Arguments);
return Async.Completed;
}
}只需将内容复制粘贴到存储在项目 Assets 目录内任何位置的新 C# 脚本中,命令就会自动可用,并可按如下方式使用:
; 使用提供的参数将“MyEvent”发送到“ExampleEvent”游戏对象
@bolt object:ExampleEvent name:MyEvent args:ExampleMessage,Script002下面是一个示例图,当附加到 ExampleEvent 游戏对象时,它将打印消息并开始播放指定的脚本。