序章说明
本次更新衔接了之前的 FC 小游戏篇,进入到游戏的正式篇(序章部分)。
序章讲述了主角 Ace 与女主角瞳相遇,并且进入到「Monster」之前的故事。
Demo 下载
此处为演示版的下载,请优先选择最新版,即版本号比较高的下载。
如果测试过程遇到 BUG,请联系 QQ:874811226 反馈。
v0.3.1
6月26日更新。
更新说明:
- 修复对话角标不动问题
- 减少部分调查事件对话内容
- 修复对话框可能在不同分辨率显示不全问题
经过测试 Windows 10 发现了对话卡死问题(非必现问题)如果遇到这种情况请联系 QQ:874811226 反馈。
v0.3.0
本地下载:点击下载
百度云:https://pan.baidu.com/s/18ALimW9GmS8UXlqhpRdd_g 提取码:s5co
请下载最新版。
更新说明
目前的 Demo 版使用的素材均为临时素材,部分图片是草图甚至缺了一张 CG 用文字代替了。
因为正在赶进度,所以素材会比较潦草,不过到了正式发布的时候就会重新绘制。
小游戏从 cocos creator 移植到 unity 花了快一个月,接着制作序章基本是爆肝模式,从 6-11 开始,前两天其实就完成了,总的制作了差不多 10 天,从零开始构建了游戏的基本系统,然后测试加调整又花了两天,总的来说,这次的制作速度提高了不少。
其实也就不到十分钟的长度而已,游玩十分钟,制作花十天。
小游戏关卡
进入游戏会先进入小游戏关卡,根据玩家通关与否会触发不同的剧情对话。
其实小游戏跟正式篇没有什么必然的关系,只是用来纪念我和 Cee 小时候玩 FC 游戏的童年而已。
场景系统
游戏的地图采用横版移动,在 RPG 游戏十分少见的类型。
因为这部新作本身就带有解谜要素,横版场景更适合「调查」,而且场景效果看起来也会比较好。
除此之外,采用横版地图还有一个考虑就是减少跑地图的时间,让玩家专注于剧情和玩法。
对话系统
带有人物立绘的对话系统。
事件系统
在场景中按[Z]键即可进行调查,因为横版的关系可能会出现多个调查对象重叠在一起的情况,所以我临时做了一个选择调查对象的 UI。
后续计划
序章还没有接触到游戏的核心玩法,要等到下次更新的「第一章」。
提前发布序章 Demo 主要还是为了让等了很久的群友先体验一下。
再不发布新作品,连我自己都怀疑我们到底有没有在做游戏了[○・`Д´・ ○]
这次的更新也证明了我们是真的有在做游戏(~ ̄▽ ̄)~
之后也会在博客同步更新进度,建议还没入群的盆友加一下 QQ 群:84334403
因为写博客有点花时间,而且贴了代码感觉没什么人想看o(╥﹏╥)o
后面的博文就一切从简了,有时间的话,我会写制作花絮记录制作过程。
制作花絮
这一部分是与游戏预告无关的,记录游戏制作过程的花絮(技术向)。
如果想要了解这部游戏是怎么做出来的盆友可以看看。
如何实现RPG游戏的剧情文本?
众所周知,一部剧情向的游戏都有很长的剧情文本。
那么,剧情的文本到底是怎么写进游戏里面的?
看起来很简单的对话系统,其实要实现起来……也不难,但是难的如何将文字量庞大的语言用代码表达出来。
如果是文字量很小的游戏,可以用简单的代码控制:
1 | Dialog.Show("小白", "我是小白,本作的主人公。"); |
只要提供一个对话方法:Dialog.Show(string name, string content)
调出对话框就行了。
其中 name
是人物名字,content
是对话内容。
按照上面的思路,写一段简单的对话可以用下面的形式:
1 | Dialog.Show("小白", "可恶的魔王,快把公主放了!"); |
但如果是长篇且文字很多的游戏,这种方法就行不通了。
像 GalGame 动则百万字,这样写怕不是要累死程序员。
而且把剧情文本写在代码里,不仅工作量大,也不利于本地化(多语言)。
指令集
在用 cocos creator 制作的时候,我采用的是十分常见的数据存储类型:JSON。
第一个文件用来保存文本:
1 | { |
第二个文件用来保存文本调用及对应的指令:
1 | "test": [ |
通过第二个 JSON(指令集)来调用第一个对话中对应的文本,type
字段定义了不同的指令,例如显示普通的对话或者显示/隐藏图片。
这样虽然实现了剧情对话系统,但是工作量却异常恐怖,而且调试起来非常麻烦,因为对话文本都是用数字编号的形式,所以光看指令集根本看不懂对话内容是什么。
这种方式我叫它「指令集」的对话系统,因为不实用所以舍弃了。
命令集
指令集的缺点是无法看懂对话内容,那只要让对话连在一起就行了。
所以第二版的对话系统,我采用了 Excel 表格的方式进行配置。
用 excel 配置其实就是把指令集变成可视化的而已,看起来更直观。
上面所示的就是对话的配置,role
即角色名称,avatar
即显示的头像,action
可以增加一些特殊的事件,比如显示图片之类的,然后是 zh-cn
是简体中文对应的语言,zh-tw
就是繁体中文的文本,其他语言填写在对应的格子即可。
接着,还需要再新增一个 sheet 用来保存对话的指令:
在指令里调用对话的 ID,这里我写了一个可以自动简化输入的符号 ~
,意思是从 x 到 n 之间连续的数字。
比如 1~3
,就会自动生成:c_00001
、c_00003
、c_00003
这三条对话指令。
因为是把命令整合在一起,所以叫它「命令集」。
这套系统解决了无法看到对话内容的问题,而且也大大减少了输入指令的工作量。
但麻烦的是要填充剧情对话的表格,这套对话系统还采用了双边立绘,填充剧情对话表格的工作量直接翻倍了。
而且这套系统的对话全部保存在一个 excel 表格里,后期文本量巨大,全部加载到内存占用空间。
所以「命令集」式的对话,也被弃用了。
文本集
既要解决可视化问题,又按需调用节省内存,就需要再次改进原系统。
最终版是我在制作「梦兽的世界」(宝可梦同人)时想到的。
由于宝可梦游戏的对话系统很简单,没有头像,只是单纯的文本。
所以最开始我是以简单文本(txt)形式保存剧情对话的:
1 | ???:欢迎来到死后的世界。 |
左边是角色名称,右边是对话内容,十分简洁。
然后对话的文本单独存放,每一段剧情对话都新建一个 TXT 保存:
当玩家与 NPC 对话的时候,根据需要取加载对应的本地文件,对话结束就释放内存节省空间。
这种方法我叫它「文本集」,就是新建许多文本的集合。
但是怪物游戏的对话系统可比这个复杂多了,所以我对这套系统进行了一些改进。
改进之后的文本变成了如下形式:
1 | #xiaoxing,normal |
井号开头的就是一条指令,左边是名字,右边是对应的立绘。
这样就实现了怪物游戏的对话系统。
但是新的问题又来了,剧情对话不仅仅只是显示文本而已,中间如果要显示图片呢?如果要停顿 1s 呢?
在还没改进这套系统之前,我是这样实现剧情的:
1 | private void SelectGame() |
不仅要手动控制屏幕的淡入淡出、显示图片,而且这种无限嵌套的地狱也十分令人绝望。
改进之后,将这些特殊的指令也融入到文本里,最后就变成了这样:
1 | #none |
井号开头的部分会被系统自动识别,不同的指令解析成对应的脚本执行。如此一来就不需要再手写代码控制显示图片和淡入淡出等操作了。
这套系统到最后的文本文件数量会非常多,不过这个缺点可以直接忽略就是了,因为文本文件基本不需要改动。
目前想到的最好方法就是文本集,但这样控制剧情还是避免不了要用代码,比如控制场景中的角色移动,如果能做到更完美的话,应该是不写一句代码就能控制整个游戏场景,很遗憾目前还不能做到完美,等到以后技术不断提高的时候就有可能实现了。就像最早的指令集到命令集,最后再到文本集的演变一样。
如何解决按键问题?
这里的按键问题指的是「并行的按键问题」。
场景中有很多东西在监听玩家的按键,比如按「Z」键可以调查,按「X」键可以打开菜单,按「方向键」可以控制角色在场景中移动。
这么多监听事件,就会存在并行监听的情况。
比如玩家与地图上的 NPC 对话,此时玩家再按「Z」键会怎样呢?
① 角色在地图上可以按[Z]来调查
② 在对话中,玩家按[Z]键会切换到下一句对话
注意,这两个按键是同时监听的,也就是说,玩家想要按[Z]键切换下一句对话的时候,同时也会触发场景调查的[Z]键监听,结果就是对话切换到下一句,而且又触发了调查事件。
为了解决并行按键同时执行的问题,就需要确定事件的执行优先级。
当打开新窗口的时候,按键的监听权应该转交给最高级的那个窗口。
比如上面的例子,在没与 NPC 对话之前,[Z]键是监听调查事件的;
而在于 NPC 对话的时候,新建了一个对话窗口,此时应该把监听权交给对话窗口。
可以用数据结构里的「栈」来实现这种对话系统。
当一个新窗口被创建时,原来的监听对象就被压入栈,在压入栈之前还要解除对象的事件监听。
当一个新窗口被关闭时,就从栈弹出这个窗口的对象,把这个窗口删掉,同时继续弹出下一个对象,将操作权限赋予这个对象,再压回栈里。
最后,回到开头的那句话 游玩十分钟,制作却要花十天。
虽然看起来很简单的事情,但是要实现起来可真不容易呀!!!