[Unity实战]剧情对话

在网上看到了一篇不错的文章,讲的是游戏中的剧情动画,感觉去做一做也是挺好玩的事,于是就有了这篇文章。游戏中的剧情(非CG动画)主要有两种,一种是自动播放的,另一种是含有对话的。可以把剧情中的一个个动画(这里的动画不仅仅包含角色动画,还包含位移,旋转,时间等待等等)当成一种种状态(有点像状态机),放到一个链表或者队列中,每当一个状态完成时便跳到下一个状态,于是就会形成连环的剧情动画了。

要注意的是,在普通状态下,一个动作完成会跳到下一个动作,但是在对话状态下,一个动作完成时不会自动跳到下一个动作,而是每出现一个新的对话,就会触发动作。

在这里给出核心代码(一个动作基类以及一个管理动作的类):

using UnityEngine;
using System.Collections;

public class Command {

    public virtual void Execute() { }
    public void Next()
    {
        CommandManager.instance.Next2();
    }
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class CommandManager : MonoBehaviour {

    public static CommandManager instance;

    private List<Command> commands = new List<Command>();
    private int nowIndex = 0;
    public bool isDialogueMode = false;

    //缓存Transform
    [SerializeField]
    public List<string> startObj = new List<string>();//一开始就存在的物体
    public Dictionary<string,Transform> allObj = new Dictionary<string,Transform>();

    void Awake()
    {
        instance = this;
    }

    void Start()
    {
        for (int i = 0; i < startObj.Capacity;i++ )
            allObj.Add(startObj[i], GameObject.Find(startObj[i]).transform);

        commands.Add(new CommandMusic("Taylor Swift - Red"));

        //场景一 对话驱动画面
        commands.Add(new CommandDialogueModeEnter());

        commands.Add(new CommandDialogue("Story1", 0, 0, 1));
        commands.Add(new CommandMove("Main Camera", new Vector3(-3.5f, 3.4f, -5.5f), 6f));

        commands.Add(new CommandDialogue("Story1", 1, 1, 2));
        commands.Add(new CommandMove("Main Camera", new Vector3(-4.8f, 3.4f, -4.8f), 0f));
        commands.Add(new CommandMove("Main Camera", new Vector3(-2.5f, 3.4f, -4.8f), 5f));

        commands.Add(new CommandDialogue("Story1", 2, 2, 3));
        commands.Add(new CommandRotate("Main Camera", new Vector3(10f, 180f, 0f), 0f));
        commands.Add(new CommandMove("Main Camera", new Vector3(-2.5f, 3.4f, -1f), 0f));
        commands.Add(new CommandMove("Main Camera", new Vector3(-4.6f, 3.4f, -1f), 5f));

        commands.Add(new CommandDialogueModeExit());

        //场景二 自动
        commands.Add(new CommandMove("Main Camera", new Vector3(-20.5f, 5.8f, -7.9f), 0f));
        commands.Add(new CommandRotate("Main Camera", new Vector3(12f, 180f, 0f), 0f));

        commands.Add(new CommandWait(2f));
        commands.Add(new CommandPlayAnim("skeleton_warrior1", AnimatorManager.instance.run));
        commands.Add(new CommandPlayAnim("skeleton_warrior2", AnimatorManager.instance.run));
        commands.Add(new CommandPlayAnim("skeleton_warrior3", AnimatorManager.instance.run));
        commands.Add(new CommandPlayAnim("skeleton_warrior4", AnimatorManager.instance.run));
        commands.Add(new CommandPlayAnim("skeleton_warrior5", AnimatorManager.instance.run));

        commands.Add(new CommandWait(2f));
        commands.Add(new CommandPlayAnim("magic", AnimatorManager.instance.attack1));

        commands.Add(new CommandWait(1f));
        commands.Add(new CommandPlayAnim("skeleton_warrior1", AnimatorManager.instance.dead));
        commands.Add(new CommandPlayAnim("skeleton_warrior2", AnimatorManager.instance.dead));
        commands.Add(new CommandPlayAnim("skeleton_warrior3", AnimatorManager.instance.dead));
        commands.Add(new CommandPlayAnim("skeleton_warrior4", AnimatorManager.instance.dead));
        commands.Add(new CommandPlayAnim("skeleton_warrior5", AnimatorManager.instance.dead));

        commands.Add(new CommandPlayAnim("magic", AnimatorManager.instance.stand));

        commands.Add(new CommandDialogue("Story1", 3, 5, 0));

        commands.Add(new CommandWait(1f));
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q))
            commands[nowIndex].Execute();
    }

    //对话模式下直接进入下一状态
    public void Next()
    {
        nowIndex++;
        if (nowIndex < commands.Count)
            commands[nowIndex].Execute();
    }

    //自动模式下直接进入下一状态
    public void Next2()
    {
        if (isDialogueMode)
            return;
        else
            Next();
    }
}

只需要根据自身的需要,写一些继承Command的类即可达到想要的效果了。以下是本人自己扩展的类:

效果图:

完整视频链接:http://v.youku.com/v_show/id_XOTMxMjIyMDU2.html

大约两分钟,建议全屏模式下播放(因为不太清晰),自认为剧情还是挺好的。。。

一个更好的方法是写一个编辑器类,将配置保存下来(保存在xml或者json文件),每次运行时读取。不过这里先放一放,最近好忙啊(因为课程的关系,大二下比之前都要忙啊),也不知道下一次写博客是什么时候!哎!

时间: 2024-10-18 14:16:06

[Unity实战]剧情对话的相关文章

[Unity实战]剧情对话(二)

在上一篇文章中,我们在CommandManager中直接写入一个个的指令,实际上这样是很不好的,因为一个游戏可能会出现很多的剧情动画,那么不就是要写n个类吗?而且修改起来也不是很好的.所以一个比较好的方法就是写一个编辑器类. 以下是本人写的一个编辑器类,功能还不是很完善,例如可以加入"插入命令","从文本中读取命令"等等等的功能,不过,先将就用了.. using UnityEngine; using UnityEditor; using System.Collect

[Unity实战]剧情对话(三)

在这里,我们使用xml来实现保存与读取功能. 首先,是头文件的引用: using System.Xml; 保存到xml文件: void Save() { string filePath = Application.dataPath + @"/my.xml"; XmlDocument xmlDoc = new XmlDocument(); XmlElement root = xmlDoc.CreateElement("root"); for (int i = 0; i

[Unity实战]虚线的绘制

说起在unity中画虚线,本人想到了两种方法: 1.无数条小直线组成一条虚线. 2.写一个shader. 前者比较简单,所以这次的重点就放在结合shader实现画虚线了. 首先,需要准备一张背景透明,仅有一条虚线的png图片,如下所示(千万不要以为背景是白色的!). 然后在场景中建一个Plane,把下面的shader给它. Shader "Custom/NewShader" { Properties { _MainTex ("Base (RGB)", 2D) = &

[Unity实战]详解换装系统(四)

关于换装系统基本上就是前三篇文章所说的那样了,这里说一下一些琐碎的.. 1.在网游中,推荐将各个部位打包成assetbundle,比如一个男性的角色,将他的基础骨骼打进一个包,再将身体各个部分的模型分别打包.如果一个模型由头.脸.身体.手臂.脚五个部分组成,那么打包后将会有六个资源包,分别是基础骨骼.头.脸.身体.手臂.脚. 2.合并mesh要注意的地方: 来源模型与材质数量必须相对应,否则模型的贴图将会变得不正常,也就是说如果裤子的 material 有两个,其他部位的 materail只有一

[Unity实战]详解换装系统(三)

在阅读本文章之前,本人强烈建议你先看看本系列的前两篇文章,对换装系统有一些了解后再继续! 在上一篇文章中,运行之后是这样的: 我们的target上挂上各种类型的mesh,而每一个mesh上都有一个Skinned Mesh Renderer组件,这无疑会增加运算量,根据官方demo的指引,我们应该合并mesh,这样target上就只有一个Skinned Mesh Renderer组件,从而达到优化的目的! 本人对上一篇文章的代码进行了一些修改,主要是添加了6处新的代码,并对不需要的代码进行了注释(

[Unity实战]相机观察物体

在原有的旋转.缩放的基础上加上了"惯性". using UnityEngine; using System.Collections; public class CameraObserve : MonoBehaviour { public Transform targetObj; public float rotateSpeed = 100f; public float translateSpeed = 10f; public float minDistance = 3f;//缩放观察的

[Unity实战]制作卷动的波浪

参考链接:http://tieba.baidu.com/p/2655013091#40457365538l 效果图: 这里,我们制作的波浪是通过改变mesh上的顶点来实现的.更准确的说,是改变mesh上顶点的y值,从而形成一种高度变化的效果. 1.通过观察,我们发现每个顶点的y值变化的情况都不一样,因此,很容易想到将顶点的y值与该顶点的x,z值关联起来. 2.通过观察,我们发现第一图的波浪数较少,第二图的波浪数较多,波浪数较小说明各顶点的y值差异较大.可以通过"放大"x,z值来增加不同

[Unity实战]一个简单的任务系统(一)

对于任务系统来说,最重要的就是处理脚本之间的消息传递,所以任务系统的核心必定就是事件委托了.这里给出核心代码: using UnityEngine; using System.Collections; public class TaskCondition { public string id;//条件id public int nowAmount;//条件id的当前进度 public int targetAmount;//条件id的目标进度 public bool isFinish = fals

[Unity实战]自定义mesh

参考链接:http://blog.csdn.net/zuoyamin/article/details/9287507 对于自定义mesh,有三点很重要: 1.顶点个数=三角形数+2:三角形顶点数=3*三角形数 2.顶点创建的顺序最好是顺时针或者逆时针创建的,这样可以大大地减少算法的复杂度 3.顶点绘制的顺序必须是顺时针或者逆时针绘制的,这样才能正确地绘制以顶点为边界点的图形,顶点绘制的顺序参考mesh.triangles using UnityEngine; using System.Colle