游戏制作

  贴在群空间里没人看所以贴在自己空间里自己看。
  游戏制作的几个层次是:引擎->脚本->编辑器->游戏
  2010-1-25 ~ 2010-2-25
  这段时间开始制作引擎。
  第一周引擎设计产生的成果会贴在下面。
  后来的时间沉入图形学习的汪洋大海里了……到现在用DX9做个完全的超级玛丽是完全没有问题的。但是,这没有意义。我想象中的一些华丽的有趣的特效要弄出来还要大量学习和研究的。
  不过我又没有说我着急了,反正已经弄了那么久,既然决定了要做就还是再多花一些时间耐心地把它做到极致就是了!

2010的第一个学期

  这个学期继续制作引擎。
  反正接下来做什么该怎么做都很清楚了,然后要继续把整个引擎实体化成代码。
  重点不在于每天能做多少,重点在于不管多少每天都要坚持做,这样就能保证总有一天能够完成了。

游戏系统的大概构思

  大概设计的是游戏是单人游戏,游戏模式类似网游MapleStory(或者说超级玛丽),但同时有两个主要角色(传说中的男女主角……),游戏时玩家控制一个,电脑模拟控制另外一个。
  这样在第一次玩的时候的另外一个角色和主角都是没有数据的,在你用其中一个角色玩过一遍后,你就可以用另外一个角色,然后电脑模拟有数据的角色和你一起玩(配合)。
  当然如果你只是一个人玩两遍的话就近似等于是你自己和自己配合。你也可以自己玩了以后,留下你的玩法记录,然后让你的男(女)友玩另外一个人物,让他(她)试着与另外那个“你”配合。
  如果你是一个很笨的玩家,然后你把你的记录传给别人,别人就会和“你”玩得很痛苦。但如果你是个很厉害的玩家,对方也许就会玩得更容易一点。但更重要的是参与玩这个游戏的两个人的“默契指数”(我以前想过一个游戏里的默契系统,以后说给你听听),如果两个玩家很有默契的话,在游戏中就能取长补短,玩出配合(因为有个电脑模拟的中间层,这个对于游戏对玩家的模拟度要求比较高,不然难以让人感觉真的是两个“人”的配合)。
  如果两个人开始是缺乏默契的,但是利用电脑的记录和模拟,每个玩家都可以按照自己的意愿,通过游戏慢慢反复训练和培养出一些默契来。

游戏的两个核心的点就是:
  1.人工智能的学习和模拟
  2.默契这个主题的表达
其中1是为2服务的,其实游戏的中心词就是“默契”

  然后有个女生说,我说的那么复杂,其实说到底就是设计给情侣玩的游戏是这个意思吧……呃……的确是可以有这个意思了……不过这些东西可以到真正制作游戏的阶段设计游戏怎样表现的时候再考虑,现在只是引擎阶段呢……和真正的游戏还有很远的距离啊啊没关系的!

关于AI系统的大概思路

  关于AI系统的大概思路(真的很大概,后面会补充细节的):

AI系统的大概思路

AI系统的大概思路

###AI系统
  • 列出条件列表。枚举所有可能的条件情况,如:平路,需要跳跃达到的台阶,有单个敌人,生命值低……等等,需要大量细分和筛选有效条件。
  • 列出动作列表。一组条件达成时所对应要做的动作,如跳跃,行走,攻击,使用技能->该处涉及默契系统中的组合技设计的动作……等等,需要排列优先级。
  • 设计人物需求状态的判定。需求状态是用于在同一个游戏状态下记录到多个玩家动作后,在模拟玩家时,决定对同一状态下所要作动作的选取。
  • 设计使用的算法
    • 在记录玩家玩法时
        采取每个循环时刻获取一次游戏状态(每个状态由多个条件组成),并给该[状态计数](nC)加一,玩家每做出一个动作时也同样一次捕捉游戏状态并给[该状态下的该动作记数](nA)加一。记录所有获取的游戏状态、对应的动作反应、该状态的状态计数、该状态下的该动作记数。
    • 在用记录模拟玩家时
        先由记录数据生成查询表(用AVLTree?读入后做次排序?又再说),然后也是每个循环时刻获取一次游戏状态,由该状态生成需求状态,并通过游戏状态用查询表获得对应动作集,由需求状态选取应采用的动作,在执行动作时用上面的[nA/nC]作为执行动作发生的概率。

关于获取游戏状态中的地形状态

目前有两种想法:

方案一

地形标识法

地形标识法

* 地形条件 注释: T:AI响应循环周期,假设0.5秒 A:单位在T时间内移动距离+10 B:单位一次完全跳跃的距离 ——————————————— 编号 | 编号b | 地形名称 | 地形描述 0 | 0 | 平路 | 单位面朝方向A距离无任何特殊地形 1 | 1 | 坑 | 单位面朝方向A/2距离内有下陷地形 2 | 10 | 台阶A | 单位面朝方向B/2距离内有不可从下方走过的高起地形 4 | 100 | 台阶B | 单位面朝方向B/2距离内有可从下方走过的高起地形 8 | 1000 | 梯子A | 单位面朝方向B/2距离内有梯子 16 | 10000 | 梯子C | 单位所处位置有梯子 32 | 100000 | 梯子B | 单位正上方有梯子
  • 方案要求
    在创造各种地形的同时产生【地形条件标识】
    单位的跳跃距离可控
    用行动队列产生组合动作

  • 方案说明
    游戏的AI循环周期定为0.5秒左右比较合适
    【地形条件标识】在游戏过程中,随着单位进入区域,动态地加入【标识表(树?)】
    单位通过【标识表(树?)】中查找当前所处的标识范围的所有标识,获得多个<地形条件>
    这多个<地形条件>组合成《地形状态》
    【地形条件标识】中应包含该标识位置、范围、该标识所代表的<地形条件>
    优点:
      AI运算时间分配较少
    缺点:
      设置地形标识较为复杂,而且可能需要在制作地图时手工设置
      需要算法优化各项查找
      如果AI循环周期增长会导致人物灵活性较低

  • 该地形条件安排方法需要对应动作
    注:前为单位面朝方向
    【向前行走】
    【转向】(改变面朝方向)
    【跳跃】(原地向上)
    【向前跳跃(短)】(【跳跃】+【向前行走(短)】)
    【向前跳跃(中)】(【跳跃】+【向前行走(中)】)
    【向前跳跃(长)】(【跳跃】+【向前行走(长)】)
    【向前跳上梯子】(【跳跃】+【向前行走(长)】等待碰撞梯子物体时+【向上爬梯子】)
    【向上跳上梯子】(【跳跃】等待碰撞梯子物体时+【向上爬梯子】)
    【向上爬梯子】
    【向下爬梯子】
    【原地跳下梯子】(【跳跃】)
    【向前跳下梯子】(【向前跳跃(长)】)

方案二

地形物体距离法

地形物体距离法

请暂时无视图上的粉色OO和橘色XX的线,注意上面的几个标数字的矩形
  • 方案要求
    单位跳跃距离为定长值
    注释:
    L:0.4个跳跃长度
    R:2个跳跃长度
    N: 3
    A:单位跳跃最大高度
    B:0.5个跳跃长度

  • 物体类型
    编号 地形物体名称
    0  无物体
    1  单位可穿过可站立的矩形
    2  单位不可穿过可站立的矩形
    3  梯子矩形

  • 距离类型
    编号 与地形物体水平距离情况
    0  0~L
    1  L~2L
    2  2L~3L
    3  3L~R

  • 将地形划为各种地形物体
      在地形中,单位[是否站在某地形物体边缘]和在单位面朝方向R水平距离内与[N个地形物体]对应[N种距离情况]的组合为该单位所处地形状态。

  • 地形物体的条件限制
      单位面朝方向R水平距离内检查的地形物体还应满足,物体上边缘与单位下边缘纵坐标差小于A(保证该物体表面是单位可一次就到达的)。

  • 单位站在地形物体边缘条件
      向单位面朝方向距所站的物体边缘距离小于L。

  • 地形状态编码
      每个【类型】占2位对应4种情况。
      按照距离类型编号从小到大排序,为:
      (←高位)【是否站在某地形物体边缘】+【物体类型1】+【距离类型1】+ … +【物体类型N】+【距离类型N】(低位→)。

  • AI查询方法
      当表现AI时,当查询到某种地形状态不存在则从编码中从较低位起去掉一个物体类型和其对应距离类型后再次查找,反复进行直到查询成功(这个设置是为了解决某些复杂的地形状态组合未曾被记录而又被查询的情况。
      从较低位开始去掉物体其实就是去掉离单位最远的物体,使地形状态变简单)。

  • 距离类型的确定待进一步研究。

  • 需要的对应动作
    注:前为单位面朝方向
    跳跃距离是定长的(必须是)
    【停止】
    【向前行走】
    【转向】(改变面朝方向)
    【跳跃】(原地向上)
    【向前跳跃】
    【向前跳上梯子】(【向前跳跃】+【向上爬梯子】)
    【向上跳上梯子】(【跳跃】+【向上爬梯子】)
    【向上爬梯子】
    【向下爬梯子】
    【原地跳下梯子】(【跳跃】)
    【向前跳下梯子】(【向前跳跃】)

实现AI的其它相关设计

动作队列

  每个单位有个动作队列,单位有什么需要执行的动作就都往里面塞,然后每个周期循环执行这个队列中所有动作。
  这个队列主要用于产生单位的组合动作
  在单位的动作中有可以并行执行的动作又有冲突的动作。
  单位的动作之间有优先级的关系,如:【停止】应该高于【向前行走】,后者会被前者打断如果后者是可以被打断的。
  在获取游戏状态后一般会查询到好几个对应要执行的动作,如游戏状态为:
  前方在半个跳跃距离内有个梯子这样的地形物体&前方在攻击距离内有怪物,则可能查询记录数据得到可能对应动作为【向前跳上梯子】&【攻击】并且两个动作的执行概率检测通过都需要执行,则这个时候只要往动作队列中添加动作:
  【向前跳跃】
  【向上爬梯子】
  【攻击】
  然后在循环执行队列动作时会先执行【向前跳跃】,后发现【向上爬梯子】(按住↑键不放)可与之并行执行,后动作为【向前跳跃并按住↑键不放】,然后又发现【攻击】与【向前跳跃可并行且优先级高于【向上爬梯子】且【向上爬梯子】可被打断,最终执行动作的结果就变成【向前跳跃并攻击】

需求状态

  需求状态是用于电脑表现AI,在查询到一个游戏状态对应有多个动作时,帮助电脑选取较为正确的执行动作,但是否用需求状态帮助电脑选取动作还要由发生概率决定。
  需求状态是预先设定好的一组状态,每个状态对应着我们认为该状态下应该执行的动作
  比如:需求状态是【需要回复生命】,预先设定对应应该执行的动作为【喝下药水】
  在游戏表现AI时,当需求状态为【需要回复生命】,电脑就会从当前游戏状态中对应的动作组里选取【喝下药水】的动作来执行(如果动作组中有该动作,如果没有,则按照动作组中的动作概率来决定选哪个动作)。
  在游戏中每次获取游戏状态和对应动作作记录的同时,由游戏状态生成当前人物的需求状态和记录相关数据,需求状态记录的相关数据如下:
  nT:每个需求状态出现的总次数
  nC:每个需求状态下玩家执行预设动作的次数
  帮助电脑选取动作的发生概率 = nC / nT

路径指引

地形物体标记

地形物体标记

请注意图上的粉色OO和橘色XX的线

注释:
A:单位跳跃最大高度
B:0.5个跳跃长度
T:单位移动0.5个跳跃长度的时间

  • 指引方法的说明
    单位需要到达的目的地有如:
      队友附近的位置
      怪物附近的位置
      前进路线上未到达的某处
      当地形设置比较复杂时,电脑模拟的单位只能通过生成到目的点的路径导引来到达目的地。所谓的导引只是适当的改变单位面朝方向,使单位走向应走的移动路径。但在各种地形环境下基本移动动作的选择仍由记录数据来决定。

  • 指引路径的生成

  • 生成路径节点
      规则:除梯子外的地形物体上边缘的两个端点必设为节点,两端点间由左往右每B距离设置一个节点。梯子的左右侧上下端点设为节点,上下端点间每B距离设置一个节点。

  • 连结路径节点成为路径搜索图
      规则:每两个节点间,纵坐标相差不超过A,横坐标相差不超过B,即可连结。
      连结的算法:赵健宇的无向图算法
      路径搜索图应在游戏开始前生成。

  • 生成单位位置节点到目的地节点的指引路径
      没有是最短路径的需要。一般和一个需求状态(需要跟随队友?需要去攻击某个敌人?)一起生成。

  • 更新指引路径
      重新搜一遍路应该不是特别费时间,但不建议通过反复更新来完成某些功能。

  • 确定单位位置节点和目的地节点

  • 游戏开始时给定单位的起始点,以后每T时间更新一次位置点。

  • 更新方法
      a.先用广搜从前一个位置点开始,直到搜到第一个与【单位】横坐标相差小于B,纵坐标相差小于A的节点,后从该节点开始第二次用广搜遍历所有同样的节点,获得所有与单位横纵坐标分别的差值和(|x1-x2|+|y1-y2|)最小的节点,为更新后的位置点。
      b.上面的方法好像有点脑残。或者在每T时间获取单位所站的地形物体后,遍历该物体上的路径节点找出最近点为更新后的位置点。(因为游戏一直在进行单位与地形物体的碰撞检测,所以不用额外循环就可以得到单位所站的地形物体,但要在之前建立好物体与路径点的对应关系)。

  • 获取目的地节点,用上述寻找更新后的位置点类似的思路就可以了。

  • 进行指引

  • 指引节点
      从指引路径中找出单位下一步应该到达的节点,当单位靠近该节点后更新。
      具体步骤:每T周期检查单位与指引节点的距离,当纵坐标相差小于A并且横坐标相差小于B后指引节点更新为下一个节点。

  • 进行指引
      判断单位面朝方向是否面对指引节点,没有对着的话就给单位添加转向动作。

引擎的名字

  这是两周以来最为头疼的一个问题……
  是到了应该开始写代码的时候了,可是面对空白的框框,不知道按键应该从哪儿敲起,并且不明白是什么将支撑我们要把无趣的代码要一直写下去。
  ……因为我给引擎起了一个名字。
  ……因为你想啊,写代码实现一个游戏引擎是一件多么无趣的事,而有爱一点,明白这其实是一件努力制造小孩的事就有趣的多了。
  呃,应该起什么名字好呢,有以下几点要求:
  1.应该是一个Loli的名字(不要问我为什么不是正太这种无法回答的问题)。因为我们这个引擎必将会是一个不很成熟(就像一只Loli)的作品,因为是处女作,因为有着一张稚气的脸之类之类的原因。
  2.名字应该短,方便记忆。
  3.名字音节应该少,方便呼唤。
  4.名字的缩写应该显得小巧不碍眼。因为这个名字将贯穿整个引擎的编写,出现在每一行代码,因为这是她的名字。
  最后,我抛弃了活泼可爱的Becky(汤姆·索亚的小女友)。
  勇敢坚强的Coraline(Why not saw buttons on your eyes?)
  仿Miku似的Mika
  ……
  她被命名为聪颖而喜欢思考的Sophie(Sophie`s World?哲学?)。
  以后如果看到以小写的so开头后跟一个大写字母的东西,不要觉得奇怪,so只是Sophie名字的缩写而已。

本文写于2010年1月

标题目录