本来说好的每周一更又鸽了...
今天来水一期,介绍一款很棒的剧情编排应用 YarnSpinner

介绍

YarnSpinner是一款开源免费的剧情编排应用(或者说是一种用于剧情编排的标记语言)。
试想我们在开发游戏时,剧情有分支选择,有各种条件检查,如果我们全在代码中去判断和检查不仅繁杂而且非常麻烦,策划学习成本高,耦合性过强。你可能自己想出一套标记语言来表述剧情流程,但自己的力量毕竟是有限的,难免出现一些bug和坑。此时,不妨试试这款免费开源,多人共同维护的应用吧。

快速食用

代码式编辑

这里我使用vscode作为编辑器,下载一下插件:

我们先创建一个.yarn格式的文件,并写入以下内容:

title: cc
tags:
colorID: 0
position: 1,-22
---
Fasty97: Hi
PC: 你好?!
Fasty97: 我又回来了!
PC: 是忘了什么东西吗?
===

这是一段剧本最基本的格式(一个yarn文件至少包含一段剧本):

title: cc
tags:
colorID: 0
position: 1,-22

以上被称为一个剧本头,表示一段剧本,这些是一些剧本段的基本信息,其中title必填,position必填.position为剧本段的标识符类似于ID一样的东西,不要重复。

在unity中使用

  1. 下载相关的unity支持包(官网有)
  2. 在场景中放入一个Dialogue预制体,预制体包含一个默认的设置示例。
  3. 创建一个脚本
  4. 设定好相关的资源和引用
  5. 运行游戏尝试按下空格键吧

脚本设定

using System;
using System.Collections.Generic;
using UnityEditorInternal;
using Yarn.Unity;
using UnityEngine;
using Yarn;

public class YarnTest : MonoBehaviour
{
    public DialogueRunner dr;
    public YarnProgram scriptToLoad;
    private void Start()
    {
        //注入对话资源
        dr.Add(scriptToLoad);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            print("开始对话");
            //开始一个对话
            dr.StartDialogue("cc");
        }
    }
}

使用自定义方法

我现在希望我第一次与角色交流时输出前2句,之后每次与角色交流只输出最后2句,这是一个游戏中常用的机制。但现在我们的对话只是按照流程依次执行,我们希望这个流程应该是能够动态控制的。
我们修改上面的yarn为:

title: cc
tags: 
colorID: 0
position: 1,-22
---
<<if visited("cc") is false>>
    Fasty97: Hi
    PC: 你好?!
<<else>>
    Fasty97: 我又回来了!
    PC: 是忘了什么东西吗?
<<endif>>
===

可以看到这次我们使用 类似if语句的东西? 这是yarn中提供的一种语法模式,在这里我们会执行一个自定义的方法visted并将"cc"传入方法中,如果返回的结果是 false就执行下面的语句块。

处理自定义事件

private HashSet<string> visitedNodes=new HashSet<string>();    //已使用节点
private void Start()
{
    //注入对话资源
    dr.Add(scriptToLoad);
    //注入处理方法
    dr.AddFunction("visited",1,(Value[] parameters) =>
    {
        var nodeName = parameters[0];
        return visitedNodes.Contains(nodeName.AsString);
    });
    //绑定事件
    dr.onNodeComplete.AddListener((name) => { visitedNodes.Add(name); });

}

创建一个HashSet集合用于存放所有已经被使用过的node,绑定一个onNodeComplete事件,这个事件有系统自动调用,在实现中为集合加入元素。
然后注入一个方法,第一个参数指定方法名(在yarn文件下的名称),第二个参数指定参数个数,第三个参数就是写入一个方法了,在方法中我们检查集合是否已经包含该值返回结果,一个自定义不可重复方法就处理好了。

使用相同的方法你还可以创建各种各样的方法在yarn中使用。
值得注意的是:
通过源代码我们可以知道,yarn只支持以下几种数据类型。

case Value.Type.Number:
  return (object) this.NumberValue;
case Value.Type.String:
  return (object) this.StringValue;
case Value.Type.Bool:
  return (object) this.BoolValue;
case Value.Type.Null:
  return (object) null;

相关链接

YarnSpinner 官网
YarnSpinner 在线编辑器
YarnSpinner github