Welcome Guest ( Log In | Register )

欢迎访问本站。游客仅能浏览首页新闻、版块主题、维基条目与资源信息,需登录后方可获得内容发布、话题讨论、维基编辑与资源下载等权限。若无账号请先完成注册流程。
 
Reply to this topicStart new topic
> 《真菌洞窟(Fungus Cave)》十一月开发日志
Bozar
2018-12-05, 13:05
Post #1


强人工智能,开坦克的贝塔猫。 | 人类啊,你们安心做蓄电池/面包片吧。 | GEEKs will Eventually Evolve into Kryptonians. | Here before you is neither the robot called BMO, nor the animal that was called Octocat. I am Doraemon.
Group Icon
 1054
   71

Group: Avatar
Posts: 1079
Joined: 2008-05-18
Member No.: 21346




## 游戏简介

[《真菌洞窟(Fungus Cave)》](https://github.com/Bozar/FungusCave)是一款正在开发的单人、回合制 Unity Roguelike 游戏。这个月主要做了三件事情:

* 为演员添加多种功能,比如演示动画里的能力(Power)和感染(Infection)。
* 自动探索地图。
* 使用多个随机数生成器(RNG)。

» Click to show Spoiler - click again to hide... «

图 1:演示动画,十一月。

» Click to show Spoiler - click again to hide... «

图 2:演示动画,十月。

接下来讲一下自动探索和随机数生成器。

## 自动探索

从最终效果来看,自动探索是指玩家按一个键,人物在接下来的每一轮自动前往未知区域,满足特定条件时停止移动。具体包括五个步骤:

* 步骤 1:新一轮开始。监听输入事件。
* 步骤 2:新一轮开始。如果出现特定情况,前往步骤 1,否则继续。
* 步骤 3:选择移动方向。
* 步骤 4:移动。
* 步骤 5:本轮结束。前往步骤 2。

不难发现,所谓的“自动”包含两层意思:首先,程序不响应玩家输入;其次,代替玩家发布移动命令。步骤 1 很简单。步骤 2 提到的特定情况,我建议至少包含以下三种:

* 情况 1:已探索全部区域。
* 情况 2:视野内有敌人。
* 情况 3:已经连续自动探索若干轮。

情况 1 是为了避免游戏陷入死循环,2 和 3 是为了改善玩家体验——因为无法完全控制移动方向,有可能沿着对角线闯入橙色的未知区域(见图 3)。及时停止自动探索,这样玩家能够手动调整移动路线。更强大的自动探索功能请参考 [DCSS](https://crawl.develz.org/)。

» Click to show Spoiler - click again to hide... «

图 3:两种移动路线。

如果移除步骤 3,那么自动探索退化成一个更简单的问题:玩家按键,人物沿着指定方向连续移动。实际效果见图 4,核心代码可以参考我做过的 [旧游戏](https://github.com/Bozar/cursedSouls/blob/master/scripts/system.js),搜索 `Main.system.pcFastMove`。

» Click to show Spoiler - click again to hide... «

图 4:连续移动。

选择移动方向时用到了 Dijkstra 算法,[《浅谈 Roguelike 游戏中的算法》](https://trow.cc/board/showtopic=36945)里面提过。具体来说,首先生成两个二维数组,一个记录“距离”,另一个保存着视野数据。视野的计算方法详见[《<真菌洞窟(Fungus Cave)>十月开发日志》](https://trow.cc/board/showtopic=37094)。接下来:

* 初始化“距离”数组,把每一格标记为一个足够大的整数(比如 99999)。
* 遍历“视野”数组;找到第一个“未知”格子后停止遍历;在“距离”数组里把这一格的距离改成 0。
* 在“距离”数组里,从上一步找到的位置出发,递归地标记所有格子,遵循以下两条规则——
* 规则 1:如果当前格在“视野”数组里是“未知”的,那么距离为 0。
* 规则 2:否则,它比八个相邻格子当中的最小距离大 1。
* 完成标记后,人物始终向着距离减小的方向移动。如果有多个等距离的方向,随机选择一个。

与自动探索联系最紧密的类(Class)有四个:

* [PCActions](https://github.com/Bozar/FungusCave/blob/master/Assets/Scripts/PCActions.cs) 调用 AutoExplore 的方法,执行两个任务:启动自动探索,继续自动探索。
* [AutoExplore](https://github.com/Bozar/FungusCave/blob/master/Assets/Scripts/AutoExplore.cs) 执行三个任务:决定是否继续探索,寻找移动方向,移动玩家人物。
* 玩家人物每一轮行动前,[SchedulingSystem](https://github.com/Bozar/FungusCave/blob/master/Assets/Scripts/SchedulingSystem.cs) 调用 [InternalClock](https://github.com/Bozar/FungusCave/blob/master/Assets/Scripts/InternalClock.cs) 的 `StartTurn()`,减少自动探索的剩余轮数。

## 随机数生成器

随机数生成器(Random Number Generator)能够根据给定的种子,生成固定的随机数序列。从玩家角度来讲,不用种子直接生成随机数,或者只用一个种子,游戏体验都差不多。那么为什么要根据不同用途,比如判定攻击、掉落物品、生成地图,使用不同的生成器呢?因为我喜欢啊。

`System.Random` 创建的 instance 无法保存当前状态。也就是说,这一次游戏生成了十个随机数,下一次进入游戏后,没办法直接生成第十一个随机数。Stack Overflow 上面讨论过这个问题([8188844](https://stackoverflow.com/questions/8188844/is-there-a-way-to-grab-the-actual-state-of-system-random),[19512210](https://stackoverflow.com/questions/19512210/how-to-save-the-state-of-a-random-generator-in-c)),但是看不太懂——

» Click to show Spoiler - click again to hide... «

图 5:16 x 55 = 28

于是俺寻思了一个办法:

* 用一个种子生成十个随机数,保存在 queue 里面。
* 需要的时候 dequeue 一个出来。
* 剩下最后一个时,把它作为种子再生成十个随机数。

代码详见 [RandomNumber](https://github.com/Bozar/FungusCave/blob/master/Assets/Scripts/RandomNumber.cs)。这个类提供了两个方法:`public double Next(SeedTag tag)`,`public int Next(SeedTag tag, int min, int max)`,输入 enum 类型的种子标签,输出随机数。



This post has been edited by Bozar: 2018-12-05, 13:12
TOP
Fast ReplyReply to this topicStart new topic
 


Time is now: 2018-12-13, 22:30