U3D游戏开发之中剧情系统的制作

news2024/10/7 4:00:33

今天我们来揭秘带有人物选项的剧情系统该如何制作。

半年前我接到了一个剧情系统的需求,本着能抄代码绝不自己动手的想法在B站上面找现成系统,大概看了一些内容,发现比较繁琐就直接自己动手写了。

目录

 1 需求分析

 2 梳理代码逻辑

 3 代码书写

 4 代码测试与系统验收


 1 需求分析

拿到需求之后我们开始分析列表之中需要的参数:


里面包含对话ID,对话具体内容string,对话可能需要用到的图片路径icon,对话者名字,对话类型(是对话还是选项)对话出现的时间(比如第几章节),对话出现的音效(比如可能出现打雷,喧闹声,笑声,鼓掌等等声音),跳转的对话ID(主要是方便对应下一句的ID:比如我从ID为1 的对话结束后,下一句是ID为4的对话,当我选择继续按钮时就会显示ID为4的这一条数据),还有选项数,例如这段对话结束出现选项提供玩家选择,此时程序员需要知道有几条选项,方便我们动态加载他们并且初始化他们,如果出现选项则不可点击继续按钮(意思是:只有选择了选项才可以继续剧情,而不能直接跳过选择)

根据上方的梳理,我们的数据也差不多够用了,表格list是我个人设置的编辑器小工具功能,如果填写list就自动生成链表(此处不附加小工具源码,仅提供剧情系统开发思路)

我们将内容分析完成之后,就可以将表格内容拿给策划填写参数,(如果你是独立游戏开发者就自己填写,如果你们公司策划自己填写了表头那么上面一步直接省略,如果你是打gamejam比赛,那么多数情况下是需要你自己或者你协助策划一起填写表头的)

 2 梳理代码逻辑

一切准备就绪之后,我们就开始分析代码逻辑:

首先,我们要制作初始化的方法,让剧情显示的时候同时显示人物名字,人物对话的具体内容,如果有音效的就播放音效,如果是选项就隐藏继续按钮,并且动态加载选项内容,点击之后获取跳转的ID,然后再根据跳转的ID查找到下一条对应的剧情内容,依法炮制,知道结束,表格内剧情状态为END,就关闭剧情界面。

 3 代码书写

大概思路已经非常清晰,我们开始写代码:

using System.Collections.Generic;
using NicoleFrameWork;
using UnityEngine.UI;

public class StoryPanels : StoryPanelsBase
{
    public int ID=1;
    
    private List<StoryLevel1> _storyLevel1s;
    private int _id;
    public override void Start()
    {
        base.Start();
        _storyLevel1s = GameJsonDataMgr.Instance.StoryLevel1List;
        InitShowStory();
    }

    public override void HideMe()
    {
        base.HideMe();
        
    }

    public override void ShowMe()
    {
        base.ShowMe();
    
        
    }
    /// <summary>
    /// 刷新对话和选项的方法
    /// </summary>
    public void RefreshAll()
    {
        InitShowStory();
        ShowChooseStory();
    }
    /// <summary>
    /// 显示对话框内的对话内容(直接刷新对话的方法)
    /// </summary>
    public void InitShowStory()
    {
        HideBtns();
        //播放音效
        if (_storyLevel1s[ID-1].Source != "null")
        {
            
        }
        //修改名字
        Name.text = _storyLevel1s[ID-1].TalkName;
        if (Name.text != "我")
        {
            NameImage1.gameObject.SetActive(false);
            NameImage.gameObject.SetActive(true);
        }
        else
        {
            NameImage1.gameObject.SetActive(true);
            NameImage.gameObject.SetActive(false);
        }
        
        //修改人物图片
        
        //修改对话内容
        Story.text = _storyLevel1s[ID-1].Story;
        //修改下一步按钮状态
        //如果选项个数不为0 (有选项)   或者 对话以后没有其他内容了
        //后续要对于没有内容的做更详细的内容
        if(_storyLevel1s[ID-1].ChooseNum!=0||_storyLevel1s[ID-1].JumpID==0)
            BtnNext.gameObject.SetActive(false);
        else
        {
            BtnNext.gameObject.SetActive(true);
        }
    }
    /// <summary>
    /// 处理按钮显示逻辑
    /// </summary>
    /// <param name="numID"></param>
    public void ShowChooseStory()
    {
        int ChooseNum = _storyLevel1s[ID-1].ChooseNum;
        _id = _storyLevel1s[ID - 1].JumpID-1;
        switch (ChooseNum)
        {
            case 0:
                HideBtns();
                break;
            case 1:
                Choose1.gameObject.SetActive(true);
                Choose2.gameObject.SetActive(false);
                Choose3.gameObject.SetActive(false);
                Choose1.GetComponentInChildren<Text>().text = _storyLevel1s[_id].Story;
                break;
            case 2:
                Choose1.gameObject.SetActive(true);
                Choose2.gameObject.SetActive(true);
                Choose3.gameObject.SetActive(false);
                Choose1.GetComponentInChildren<Text>().text = _storyLevel1s[_id].Story;
                Choose2.GetComponentInChildren<Text>().text = _storyLevel1s[_id+1].Story;
                break;
            case 3:
                Choose1.gameObject.SetActive(true);
                Choose2.gameObject.SetActive(true);
                Choose3.gameObject.SetActive(true);
                Choose1.GetComponentInChildren<Text>().text = _storyLevel1s[_id].Story;
                Choose2.GetComponentInChildren<Text>().text = _storyLevel1s[_id+1].Story;
                Choose3.GetComponentInChildren<Text>().text = _storyLevel1s[_id+2].Story;
                break;
                
        }
    }
    /// <summary>
    /// 处理所有按钮隐藏的方法
    /// </summary>
    public void HideBtns()
    {
        Choose1.gameObject.SetActive(false);
        Choose2.gameObject.SetActive(false);
        Choose3.gameObject.SetActive(false);   
    }
    protected override void Choose1Click()
    {
        base.Choose1Click();
        ID = _storyLevel1s[_id].JumpID;
        HideBtns();
        InitShowStory();
        MusicMgr.Instance.PlayerSound("Choose",E_LoadingMethod.ABRes);
    }

    protected override void Choose2Click()
    {
        base.Choose2Click();
        ID = _storyLevel1s[_id+1].JumpID;
        HideBtns();
        InitShowStory();
        MusicMgr.Instance.PlayerSound("Choose",E_LoadingMethod.ABRes);
    }

    protected override void Choose3Click()
    {
        base.Choose3Click();
        ID = _storyLevel1s[_id+2].JumpID;
        HideBtns();
        InitShowStory();
        MusicMgr.Instance.PlayerSound("Choose",E_LoadingMethod.ABRes);
    }

    protected override void BtnNextClick()
    {
        base.BtnNextClick();
        MusicMgr.Instance.PlayerSound("Choose",E_LoadingMethod.ABRes);
        ID = _storyLevel1s[ID-1].JumpID;
        if(_storyLevel1s[ID-1].ChooseNum==0)
            InitShowStory();
        else
        {
            InitShowStory();
            ShowChooseStory();
        }
    }
}

 4 代码测试与系统验收

代码写的比较暴力,但是符合之前所说的所有条件。我们在main脚本之中测试一下我们的剧情系统:

         if(Input.GetKeyDown(KeyCode.S))
            UIMgr.Instance.GetPanel<StoryPanels>((story) =>
            {
             story.InitShowStory();   
             
            });
        if(Input.GetKeyDown(KeyCode.D))
            UIMgr.Instance.GetPanel<StoryPanels>((story) =>
            { 
                story.InitShowStory();
                story.ShowChooseStory();
            });

完美运行,于是我们将剧情系统的测试视频发送给策划看,通过一系列交流发现该系统与我们的策划案需求完美符合。

至此,一个对应游戏需求的剧情系统制作完毕。

(提供剧情系统思路,仅供参考,喜欢就请点赞收藏吧!)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2193504.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s 中存储之 NFS 卷

目录 1 NFS 卷的介绍 2 NFS 卷的实践操作 2.1 部署一台 NFS 共享主机 2.2 在所有k8s节点中安装nfs-utils 2.3 部署nfs卷 2.3.1 生成 pod 清单文件 2.3.2 修改 pod 清单文件增加 实现 NFS卷 挂载的 参数 2.3.3 声明签单文件并查看是否创建成功 2.3.4 在 NFS 服务器 创建默认发布…

[c语言]一句话讲清循环中break和continue的作用与区别

1.两者的作用 break和contuinue都只能在循环中使用&#xff0c;都用来停止循环。 2.两者的区别 break 在循环中只要遇到break&#xff0c;就直接永久终止当前循环&#xff0c;开始执行当前循环之外的代码。 continue 在循环中只要遇到continue&#xff0c;就结束本次循环&…

免费送源码:Java+ssm+JSP+Ajax SSM棕榈校园论坛的开发 计算机毕业设计原创定制

摘要 随着计算机科学技术的高速发展,计算机成了人们日常生活的必需品&#xff0c;从而也带动了一系列与此相关产业&#xff0c;是人们的生活发生了翻天覆地的变化&#xff0c;而网络化的出现也在改变着人们传统的生活方式&#xff0c;包括工作&#xff0c;学习&#xff0c;社交…

数据库软题6.1-关系模式-关系模式的各种键

关系模式的各种键 题1-由关系模式求候选键 1. 候选键唯一不冗余 对选项进行闭包运算&#xff0c;如果得到全部属性U&#xff0c;则为候选码 A:AC-ABC-ABCD B:AB-ABC-ABCD C:AE-ABE-ABCE -ABCDE-ABCDEH D:DE2. R的候选码可以从A1,A2,A3,A1A2,A1A3,A2A3,A1A2A3中选择&#xff…

Flutter String 按 ,。分割

在 Flutter 中&#xff0c;如果你想将一个字符串按特定的字符&#xff08;例如中文逗号 &#xff0c; 和英文句号 .&#xff09;进行分割&#xff0c;可以使用 Dart 语言的字符串处理功能。具体来说&#xff0c;你可以使用 split 方法&#xff0c;并传入一个正则表达式来匹配这…

CSS基础-常见属性(二)

6、CSS三大特性 6.1 层叠性 如果样式发生冲突&#xff0c;则按照优先级进行覆盖。 6.2 继承性 元素自动继承其父元素、祖先元素所设置的某些元素&#xff0c;优先继承较近的元素。 6.3 优先级 6.3.1 简单分级 1、内联样式2、ID选择器3、类选择器/属性选择器4、标签名选择器/…

数据结构之树(1)

课程&#xff1a;b站王道数据结构 5.1.1 树的定义和基本术语_哔哩哔哩_bilibili 写在前面&#xff1a;基础不牢&#xff0c;地动山摇。。 一、树 1、概念 树是n&#xff08;n>0)个结点的有限集合&#xff0c;n0时&#xff0c;称为空树 非空树的特性 有且仅有一个根节点…

智能家居有哪些产品?生活中常见的人工智能有哪些?

智能家居有哪些产品? 1、智能照明设备类&#xff1a;智能开关、智能插座、灯控模块、智能空开、智能灯、无线开关。 2、家庭安防类&#xff1a;智能门锁、智能摄像机、智能猫眼、智能门铃。 3、智能传感器类&#xff1a;烟雾传感器、可燃气体传感器、水浸传感器、声光报警器…

CentOS7系统配置Yum环境

新安装完系统的服务器往往缺少我们常用的依赖包&#xff0c;故需要设置好yum源&#xff0c;方便软件安装&#xff0c;以下是CentOS7为例&#xff0c;系统安装后yum默认安装。 //备份之前的配置文件 mv /etc/yum.repos.d /etc/yum.repos.d.bak mkdir -p /etc/yum.repos.d 1…

鸿蒙开发之ArkUI 界面篇 十八 京东app登录界面实现

鸿蒙UI实现某东App登录界面,如下图鲜果,我们先分析整体架构是什么! 我们整体架构分析,分为区域1、2、3、4、5、6、7、8、9区域,下图: 8个区域的整体方向是垂直的,容器使用的是Column,区域1使用的是子容器Row,左边是Image,右边是Text,区域2是Image,区域3第一感觉是…

欧姆龙(Omron)协议解析

1. 协议概述    欧姆龙(Omron)是来自日本的知名电子和自控设备制造商&#xff0c;其中、小型PLC在国内市场有较高的占有率&#xff0c;有CJ、CM等系列。PLC可以支持Fins、Host link等协议进行通信。 支持以太网的欧姆龙PLC CPU、以太网通信模块根据型号的不同&#xff0c;一般…

dockertop提示Failed to fetch extensions

解决办法&#xff1a;重装dockertop 第一步&#xff1a;卸载当前的dockertop 如果卸载过程中存在AlibabaProtect的相关软件关不掉&#xff0c;那么参考这篇文章&#xff1a;卸载AlibabaProtect 第二步&#xff1a;删除C:\Program Files路径下的Docker文件夹 第三步&#xff1…

代码随想录Day 62|Floyd 算法精讲、A \* 算法精讲 (A star算法),题目:97. 小明逛公园、127. 骑士的攻击

提示&#xff1a;DDU&#xff0c;供自己复习使用。欢迎大家前来讨论~ 文章目录 图论part11Floyd 算法精讲题目&#xff1a;97. 小明逛公园解题思路&#xff1a; A \* 算法精讲 &#xff08;A star算法&#xff09;题目&#xff1a;127. 骑士的攻击问题描述算法选择解题思路C代…

什么是重卡充电桩?

有什么广告&#xff1f;没有广告&#xff0c;纯纯的介绍。 在政策与市场双重驱动下&#xff0c;充电桩市场已经开启加速模式&#xff0c;行业的火苗越烧越旺。同时&#xff0c;随着新能源重卡的广泛普及&#xff0c;重卡充电桩也迎来了新的发展机遇。 此种背景下 &#xff0c…

Pikachu-敏感信息泄露

直接访问页面&#xff0c;查看页面源码 如&#xff1a;返回了测试账号信息&#xff1b; 例如&#xff1a;返回服务端的信息

仿RabbitMQ实现消息队列三种主题的调试及源码

文章目录 开源仓库和项目上线广播交换模式下的测试直接交换模式下的测试主题交换模式下的测试 开源仓库和项目上线 本项目已开源到下面链接下的仓库当中 仿RabbitMQ实现消息队列 广播交换模式下的测试 消费者客户端 在进行不同测试下&#xff0c;消费者客户端只需要改变交换机…

【Blender Python】4.获取场景对象的几种方式

概述 有时候我们需要获取场景中已经添加或存在的对象。本节就总结在Blender Python中获取场景中对象的一些方法。 通过名称获取 py.data的objects()方法返回一个对象集合&#xff0c;可以使用键名或者下标形式获取具体的对象。 在默认新建的场景中&#xff0c;存在三个对象…

初始Linux(二)基础命令

前言&#xff1a; 之前那一篇我们已经介绍了一部分的基础命令&#xff0c;当然那只不过是九牛一毛&#xff0c;本篇我们继续介绍一些比较重要且需要掌握的基础命令。 mv命令&#xff1a; 其实这个命令有两个功能&#xff0c;一个是移动&#xff08;剪切&#xff09;文件&#…

可查询全部快递api接口分析

使用三方平台该API接口需要先注册后申请此API接口。申请后可直接在线请求接口数据。 该api接口可自动识别单号信息。调用简单方便&#xff0c;性价比高&#xff0c;一条链接即可。 API接口地址为&#xff1a;https://www.tanshuapi.com/market/detail-68 其中&#xff0c;KEY…

掌握嵌套子查询:复杂 SQL 中 * 列的准确表列关系

在日常开发中&#xff0c;我们常常需要对复杂的 SQL 进行数据血缘分析。 本文重点讨论在具有 * 列的嵌套子查询中建立表和列之间正确关系的挑战。使用 Teradata SQL 代码示例来说明该过程。 本文聚焦于一个别名为 SUBSCRIBER_ 的子查询及其派生的列&#xff0c;这些列在外层查…