上一篇里面,我们初次接触了 ink 语言,并且完成了一段非常简单的代码。在这一篇中,我们要试着将它放到 Unity 里面去跑一下!
Unity 插件
inkle 提供了将 ink 整合到 Unity 中的插件,我们可以到如下地址下载:
ink Unity 插件
去下载我们下载的是 v 0.8.1 的稳定版。UnityInkIntegration0.8.1.unitypackage
准备我们的 Unity 项目
创建一个新的 2D 项目,并且保存 Scene 为 Main,然后引入 Unity 插件。
再把我们上一篇完成的 ink demo 拖进项目,我们的叫做 demo.ink。
引入 ink 文件之后,会自动编译成 JSON 的可用格式,我们的素材库看起来会像下面这样:

然后创建 Canvas 画布并且增加两个必要的元素:Button(按钮)和 Text(文本),并且将它们做成 Prefab,供后面使用。按钮是用来显示选项并做出选择的,而文本使用来显示基本内容的。
因为要使用 Prefab 所以将 Canvas 清空即可,然后给 Canvas 增加 C# 脚本,取名 Script.cs 吧!
这样,我们的素材就准备完毕了:

其实 ink 脚本引入以后,是可以直接在 Unity 中测试的。选中 .ink 文件,属性栏里面就会出现 Play 按钮,可以直接运行并测试。

编写脚本
脚本代码如下,已经添加了注释:
using UnityEngine;
using Ink.Runtime;
public class Script: MonoBehaviour
{
// ink JSON
[SerializeField] private TextAsset inkFile;
// 画布
[SerializeField] private Canvas canvas;
// ink 故事
private Story _inkStory;
// 是否需要新的故事片段
private bool _storyNeeded;
// 距离(用来确定内容和按钮位置)
private int _padding = 10;
/* UI Prefabs */
// 文本
[SerializeField] private UnityEngine.UI.Text text;
// 按钮
[SerializeField] private UnityEngine.UI.Button btnChoice;
// 初始化
private void Awake()
{
_storyNeeded = true;
_inkStory = new Story(inkFile.text);
// 设置玩家名称
_inkStory.variablesState["player_name"] = "Someone";
}
// Update is called once per frame
private void Update()
{
if (!_storyNeeded) return;
// 清空画布内容
RemoveChildren();
// 各个元素的偏移,需重新计算
float vOffset = 0;
// 如果故事可以继续
if (_inkStory.canContinue)
{
var storyText = Instantiate(text);
// 取得要显示的文字
storyText.text = _inkStory.Continue();
// 定位相关
storyText.transform.SetParent(canvas.transform, false);
storyText.transform.Translate(new Vector2(0, vOffset));
vOffset -= (storyText.fontSize + _padding);
}
// 如果有多个选择,那么逐个处理
if (_inkStory.currentChoices.Count > 0)
{
for (var i = 0; i < _inkStory.currentChoices.Count; i++)
{
// 定位相关
var choiceButton = Instantiate(btnChoice);
choiceButton.transform.SetParent(canvas.transform, false);
choiceButton.transform.Translate(new Vector2(0, vOffset));
// 取得选择
var choice = _inkStory.currentChoices[i];
// 设置按钮的选择文本
var choiceText = choiceButton.GetComponentInChildren<UnityEngine.UI.Text>();
choiceText.text = choice.text;
// 定位相关
var layoutGroup = choiceButton.GetComponent<UnityEngine.UI.HorizontalLayoutGroup>();
vOffset -= (choiceText.fontSize
+ layoutGroup.padding.top
+ layoutGroup.padding.bottom
+ _padding);
// 获取按钮点击后对应的路径
var path = choice.pathStringOnChoice;
choiceButton.onClick.AddListener(delegate { ChoicePathSelected(path); });
}
}
// 本次操作完成,等待响应
_storyNeeded = false;
}
/// <summary>
/// 清空画布内容
/// </summary>
private void RemoveChildren()
{
var childCount = canvas.transform.childCount;
for (var i = childCount - 1; i >= 0; --i)
{
Destroy(canvas.transform.GetChild(i).gameObject);
}
}
/// <summary>
/// 选择路径
/// </summary>
/// <param name="path">路径名称</param>
private void ChoicePathSelected(string path)
{
_inkStory.ChoosePathString(path);
_inkStory.Continue();
_storyNeeded = true;
}
}代码还是很简单的,基本上跟官方提供的差不多,我们加入了:
_inkStory.variablesState["player_name"]
来进行玩家名称的设置,并且通过 path 来进行导航。
收尾工作
我们回到 Unity 编辑界面,将程序运行所需要的对象一一绑定,如图所示:

不过这还没有完,我们需要给按钮和文本加上自动居中的设置,并且做一些边距控制颜色调整等等的美化工作,基本上是这样:

如果一切顺利,就可以跑啦:

项目文件
如果懒得自己尝试,那么我们也提供了源代码供您下载使用:
项目源代码
去下载结束语
好了,这一次的 ink 初次尝试就完了啦,后续有什么问题或者需要交流的,请前往我们设立的小组继续探讨:


暂无关于此文章的评论。