半吊子
日历
网志分类
· 所有网志 (82)
站内搜索
友情链接
· 歪酷博客
· 我的歪酷 非非共享界

订阅 RSS

0069839

歪酷博客

« 上一篇: 帕格尼尼手中的木头 下一篇: 当一个妇科医生(5)——关于会追我的子弹 »
天地间有我 @ 2004-08-06 10:39

     昨天谈了很多,似乎都是在说文字。好像是在介绍C语言的一种高级用法而已。其实,如果各位老玩家注意一下,当年的《剑侠情缘》《中国球王》等DOS下的简体中文的游戏,都是有这么一个字库文件,有的还就是我昨天介绍的HZK16这个库文件。像《剑侠情缘》是工作在320×200×256下的游戏,16×16的一个字就会显得很好看,其实《仙剑奇侠传》的DOS版也是这样的,不过人家是用的繁体字库而已。由此可见,我昨天不是没有谈游戏的算法,而是谈了中文游戏中的一个关键性的问题。

     今天,我要谈的是游戏开发中同样也是很重要的一个问题——人工智能Artificial Intelligence(AI)。

     我在第一天就谈了即时战略(RTS)游戏中多个士兵同时工作的问题,但我使用看了一个虚拟的类型“行为模式”。这种模式是什么?就是我通过鼠标向士兵发号的指令,比如:移动,建造,物理攻击,魔法攻击,吃药,找NPC购物等等……但在RTS中,只要不是选择Multiuser Game就会出现一个问题,电脑是怎么去控制他一方的士兵移动,建造,物理攻击,魔法攻击,吃药,找NPC购物等等……这些动作的。这就牵涉到一门新星的学科“人工智能”。

     在我说我自己理解的“人工智能”之前,我再解释一下。我觉得,人工智能负责的是士兵A在什么情况下从(x0,y0)走到(x1,y1),士兵2什么时候攻击,士兵3什么时候使用魔法……至于从(x0,y0)走到(x1,y1)的算法是另外一个即将要讨论的“A*以及其他寻路算法”中要讨论的内容。简单的说:
[b][center]AI就是让电脑确定下步做什么[/center][/b]
     由于本人的能力有限,思考问题的深度有限,我今天讨论的AI主要是讨论角色扮演游戏(Role Playing Game)和策略与战棋类游戏(Simulation Game)中的人工智能。

     AI最容易制作的的方式是导向式思考方式,同时也是早期游戏AI发展的主要方向就是规则导向或称之为假设导向。在一些比较简单的电脑游戏中,程序员可以毫不困难地将游戏中的规则与设定转化成一条条的规则,然后将它们写成电脑程序。让我们以角色扮演游戏(RPG)为例。决大多数的企画在设定所谓电脑怪物时,所设定的属性通常有以下几种:
           1、生命值
           2、攻击力
           3、防御力
           4、法力
           5、属性
     最后一个“属性”不是所有游戏都有,或者有些游戏这事一个隐形的值。但有了这一属性,敌人将更有个性。透过这项属性的设定,我可以把怪物设定成“贪生怕死的”,也可以把战士设定为“视死如归”。以目前我们所掌握的资料,在战门系统中的大纲如是诞生了:                          
规则一
if (生命值< 10) /*判断是否濒临死亡*/
       { 
       if (属性== 贪生怕死)
               {
               结果 = 试图逃跑;
               }
       if (有任何恢复生命值的物品或法术可用)
               {
               结果 = 使用或施展相关物品或法术;
               }
       }
}

规则二
if (可施攻击性法术 && 有足够法力)
       {
       结果 = 施展攻攻击性法术;
       }

     由以上一连串的“如果--就--”规则设定,建立了最基本的AI。说这样的制方式只能建立基本AI其实并不当然正确。只要建立足够及精确的规则,这样的方式仍然有一定水准的表现。规则导向的最大优点就是易学易用。在没有深奥的理论概念的前提下,仍有广大的使用群。所以很多老道的玩家常常没两下就摸清楚敌人的攻击策略,移动方式等等。

     是不是不太好理解?现在让我进入《仙剑奇侠传》的世界……

     李逍遥在巫王神殿中见到的拜月教主,话不投机就动起手来。拜月教主来了两个小帮手,可是这些小喽啰怎么是我李大侠的对手,一个酒神之后就剩下拜月教主一个人对付逍遥哥哥、灵儿和阿奴了……这时候,一个很重要的问题摆在个拜月教主的面前:我到底要攻击谁呢?是打这个花花公子李逍遥呢?还是打那两个小丫头呢?拜月教主执行了这样一个函数:
[center]attack(((unsigned)biostime*rand())%3);/*电脑攻击函数*/[/center]
     这是一个虚拟的函数,代码省略了。拜月教主关心的只是它的入口,教主定义它的入口为要攻击的对象。选择对象使用了随机数与时间共同工作,这样敌人就在3个攻击对象中随机地选择攻击对象了。这样,打那三个小孩子的机会是均等的。这时候拜月教主觉得自己有点白痴,所以他决定多执行一段代码,让自己去优先选择最弱的一个小孩子去攻击,但不是每次就盯着他/她攻击:
       int  i,
            leastblood=20000,/*leastblood存储最弱对象的血量(初始化为一个比所有对象的可能血量都大的值)*/
            weakest;/*weakest存储最弱对象的代号*/
       for(i=0;i<3;i++)
               {
               if(blood[i]<leastblood)/*blood数组为已知的我方对象的血量*/
                       {
                       leastblood=blood;
                       weakest=i;
                       }
               }
       i=((unsigned)biostime*rand())%4;
       switch(i)
               {
                 case 0:
                 case 1:
                       i=leastblood;
                       break;
                 case 2:
                       i=(leastblood+1)%3;
                       break;
                 case 3:
                       i=(leastblood+2)%3;
                       break;
               }
       attack(i);

     这样,最弱对象受攻击的机率就提高到了1/2,拜月教主顿时觉得自己聪明了许多。

     用导向式思考方式设计AI是不是很简单?其实用这种方法AI有深有浅,这只是一个最简单的而已。要深奥,只不过是把制约的条件增多罢了。

     相对来说,RPG游戏AI是最容易设计的。这也显而易见的,PRG重在剧情战斗只是为了推动剧情的。如果AI过高,就是踩个地雷都有“大侠,请从新来过”的威胁的话,这个RPG就一定不是一个成功的作品。

     在AI设计上,难度在RPG之上的是SLG游戏,SLG游戏电脑AI一般遵循的规则有:
           1、最弱对象攻击原则;
           2、就近攻击原则;
           3、最大攻击力原则。

     在这三个原则中,排在最先的是就近攻击原则,即电脑对象要攻击,则向距离该对象最近(最节省MP)的对象靠近攻击。排在第二的是最弱对象攻击原则,在可以攻击到的对象中,选择最弱的对象进行攻击。排在第三的是最大攻击力原则,如果电脑选中了一个攻击目标,则会使用电脑对象能使用的最大攻击力的方式去攻击。

     分析到这一步,玩起游戏来似乎真的没有趣味了。因为,我们已经可以用电脑的思考方法去推倒电脑下一步,这样就像孙膑会六爻金钱,能算出庞驸马的下一步军事路线一样,能算出庞驸马死在马陵道的某一棵大树下。我们先不说能怎么样赢电脑,最起码我们可以有针对性的保护某一个战棋游戏中的“精灵”。

     其实不是这样的,在战棋游戏中,我分析游戏中AI的深度与制约条件有关。制约电脑行动的条件远不止上面的三条原则。如电脑游戏就有一种攻击指定目标的玩法。在这种模式下,电脑优先攻击的就是你也能推算出来,已经指定保护的目标。但,如果加入魔法机制,电脑的行动就不光是攻击了,而且要定义使用魔法的条件,程序将更为复杂。

     还有一种AI的方法是:推论式思考。相信曾经接触过电脑语言课程,或是自习过相关书籍的朋友们,都曾曾经听过一个著名的程序,那就是井字游戏。在严奶奶的《数据结构》的前言部分,也有这个例子。用井字游戏作为讨论AI的入门教材,我个人觉得是最适当的例子。或许有人还不知道井字游戏怎么玩。只要任何一方在三乘三的方格中先先成一线便胜利了。我们在前面谈过的规则导向,在这里也可以派得上用场。

       if任何一线已有我方两子&&另外一格仍空//我方即将成一线吗
               {
               结果 = 该空格;
               }                     
       if任何一线已有敌方两子&&另外一格仍空//防止敌方作成一线 
               {
               结果 = 该空格;
               }                    
       if任何一线已有我方一子&&另外两格仍空//作成两子    
               {
               结果 = 该空格;
               }

     有一次我在某本电脑书上,同样地也看到某些以井字游戏为介绍的范例。不同的是,我几乎看不到任何规则导向的影子。但在仔细分析该程序码后,我得到了极大的启发,原来AI是可以不用这么多规则来制作的。它用的方法正是在AI理论中重要的概念:极大极小法。

     以井字游戏为例,电脑先在某处下子,接着会以假设的方式,替对方下子,当然,必须假设对方下的是最佳位置,否则一切则毫无意义。在假设对方下子的过程中,自然又需要假设我方的下一步回应,如此一来一往,直到下完整局游戏为止。

底下是节录书中的程序片段:
 
bestMove(int p, int*v)
{
       int     i, 
               lastTie,
               lastMove,
               subV;
       /*First, check for a tie*/
       if (isTie())
               {
               *v=0;
               return(0);
               };
       /*If not a tie, try each potential move*/
       for (*v=-1, lastTie=lastMove=-1,i=0;i<9;i++)
               {
               /*If this isn't a possible, skip it*/
               if (board[i]!=0)
                       {
                       continue;
                       }
               /* Make the move. */
               lastMove=i;
               board[i]=p;
               /* Did it win? */
               if (hasWon(p)) *v=1;
               else
                       {
                       /*If not, find out how good the other side can do*/
                       bestMove(-p,&subV);
                       /* If they can only lose, this is still a win.*/
                       if (subV==-1)
                               {
                               *v=1;
                               }
                       /* Or, if it's a tie, remember it. */
                           else
                               {
                               if (subV==0)
                                       {
                                       *v=0;
                                       astTie=i;
                                       };
                               };
                           };  
               } 
       /* Take back the move. */
       board[i]=0;
       /*If we found a win, return immediately (can't do any better than that)*/
       if (*v==1)
               {
               return(i);
               }
       /*If we didn't find any wins, return a tie move.*/
       if (*v==0)
               {
               return(lastTie);
               }
       /*If there weren't even any ties, return a loosing move.*/
       else
               {
               return(lastMove);
               }
};

     上面这段代码是摘录的核心代码,看的真是赏心悦目啊。程序控制AI就谈这些,下面谈谈影响AI的状态的游戏脚本。关于这个脚本,我本人没有做过。这个概念是看同学弄游戏外挂上知道的。但一些开发游戏的朋友告诉我他的重要性,下面的内容更多的是我空想出来的,和复述一些朋友的言论,为的只是介绍AI介绍的完整。在我有过一定研究之后,会单独撰文的。

     游戏脚本就跟乐器演奏的乐谱一样,影响着整个游戏进程:在什么时候、什么条件下执行什么动作,地图上出现什么,消失什么,谁的状态(如攻击力、防御力等)的改变。都要在游戏脚本中详细说明,只不过是使用符号化的语言而已。可以说游戏脚本就是一种解释类的AI。这是我理解的脚本。

     游戏脚本是非常重要的,RPG游戏不用说,因为RPG游戏几乎是单线式的,绝对需要脚本的支持。而在SLG游戏中,也是非常的重要。比如说,在一关设计时我布置了大量的强大的敌人。如果不用脚本加以控制的话,那么敌人将蜂涌而上,玩家绝对吃不消。而使用脚本控制后,每隔一定时间后有一部分敌人进入搜寻并攻击状态,其它的敌人仍然在待机状态。玩家将敌人一部分一部分吃掉,即不费多大力,又有一种一对N的成就感,娱乐的目的就达到了。ACT(动作类游戏)中,也要使用脚本控制游戏进程,不过这种脚本非常简单,只要写明什么地方出现什么敌人,什么机关工作就可以了。即时战略游戏的脚本相对复杂和抽象,我还没有太想通这是一种什么样的脚本。

最新评论


lemonhall

2004-08-06 15:17

人工智能研究所,我姐姐上研究生的地方。。。觉得是老外搞出来的大馅饼。



红移

2004-08-09 17:45

写得很好! 鼓励一下 :)
其实还可以复杂一些。教主不是有小罗罗吗,他也需要指点一下小罗罗的动作吧。比如让那个小罗罗去骚扰、断路,当然身为老大给属下疗下伤也无可厚非。。。
挑战你的编程和思考能力哦 :)



快刀无双

2005-02-01 15:30

很好,但斜斜的字体有点看不清楚


评论 / 个人网页 / 扔小纸条
* 昵称

已经注册过? 请登录

新用户请先注册 以便能显示头像及追踪评论回复

Email
网址
* 评论
表情
 


 

分类小组论坛
杂谈 , 娱乐、八卦 , 文学、艺术 , 体育 , 旅游、同城 , 象牙塔 , 情感 , 时尚、生活 , 星座 , 科技

请注意遵守中华人民共和国法律法规, 如威胁到本站生存, 将依法向有关部门报告, 同时本站的相关记录可能成为对您不利的证据.

相关法律法规
全国人大常委会关于维护互联网安全的决定
中华人民共和国计算机信息系统安全保护条例
中华人民共和国计算机信息网络国际联网管理暂行规定
计算机信息网络国际联网安全保护管理办法
计算机信息系统国际联网保密管理规定