|  | 
 
| 首先,我要声明一下,虽然代码还没有写,不过我绝不是纸上谈兵的,以下算法都是可实现的,代码有空再完成呵呵~ 
 以下算法包括了吃药,武功选择,走位以及最新的特殊状态和特殊武功等等的处理,只有文字,不知道各位代码狂人能否融入代码中,呵呵~
 
 首先说说整个算法的基本价值判定,也就是AutoBattle中各种判断的基本流程
 在我的代码中,AI的价值观为:
 自保>杀人>加持>伤人>休息
 
 自保,顾名思义就是保持自己不死,吃药,医疗,或者使用特殊武学治疗等都算,这是放在所有事情的第一位,相信这是没有什么悬念的,对了,还有逃跑,因为休息可以恢复一部分生命内力等,所以逃跑也算是自保,有一些特殊状况,后面再说
 如果吃药医疗等判断为false,那么AI将会判断是否存在可以杀掉的敌人,然后杀之,解决敌人(我方?)的有生力量是自保之后的第二件事情,而战斗判断复杂,同样后面再说
 加持,也就是对友军施加正面状态,相信这是一个让AI设计者头痛的东西,往往不知道放在哪里好,对吧?在判断不能减少敌人数量之后,加强自我属性状态往往是一个比纯粹伤害敌军更佳的选择
 伤人,就是使用武功,可能你会发现,伤人跟杀人同样使用武功,那是否意味着要重复进行武功判断呢?看下面就知道
 休息就不说了,直白点说,什么都做不成就会休息
 
 
 有了这么一个大的方向,剩下的就是把判断不断地细分的一个过程了~AI说起来神秘,其实也就是处理一堆变量的假设和循环罢了
 
 然后,如何才能做出一个比较聪明的AI呢?如果只是跟以前的一样,那这AI就没有必要写了
 
 我的变革有如下几点:
 1,使用药品对象从自我变为友军
 这个在代码中是很好实现的,我刚接触复刻源码时就做出来了这么个系统,只是加几行代码罢了。就是改了一下case mode后面的~
 procedure BattleMenuItem(bnum: integer);
 var
 i, rnum, inum, mode, step: integer;
 str: widestring;
 begin
 if MenuItem then
 begin
 inum := CurItem;
 rnum := brole[bnum].rnum;
 mode := Ritem[inum].ItemType;
 case mode of
 3:              //战场吃药系统强化,突破只给自己吃药的限制,药物可以作用于队友
 begin
 CalCanSelect(bnum,1);
 step:=2;
 if ( SelectAim(bnum, step) ) then                  //选定某个坐标的角色
 begin
 for i:=0 to (BRoleAmount-1) do                 //在战场上搜索所有人物对照
 begin
 if (BRole[i].X = Ax ) and (BRole[i].Y =Ay) and (BRole[i].Team=0) then        //坐标上人物非空,为队友
 begin
 EatOneItem(BRole[i].rnum, inum);
 instruct_32(inum, -1);
 Brole[bnum].Acted := 1;
 waitanykey;
 end;
 end;
 end;
 end;
 4:
 begin
 UseHiddenWeapen(bnum, inum);
 end;
 end;
 end;
 
 end;
 
 然后在AI中,我的建议是用等级判断,每个角色行动前,先判断可使用药品范围内(如果药品范围是离自身两格内,那就是移动格数+2),是否存在需要使用药品的角色,如果存在,并且角色等级比自身要高,则优先给等级高的角色使用药品
 
 例如,一个小兵跟欧阳锋同时被打成红血,然后小兵会给欧阳锋用药,欧阳锋攻击,这改革意义就大了,小兵的存在也只不是充当经验值了
 
 2,记录最高伤害数值和角色
 在源码中,单场战斗的数据是不被记录在什么R,D,S之类的文件中的,也就是战斗数据不会影响文件结构,所以为战斗人物加几个变量是很简单的事情
 
 有见及此,我提议为角色加入最高受伤和带来该伤害的攻击者记录,提升AI的智能
 不明白怎么回事?
 我也举个例子:
 例如郭靖一个降龙打欧阳锋(又是他)500,那在欧阳锋的最高受伤纪录就会变成500,攻击者为郭靖的人物编号
 如果欧阳锋的生命值少于500的双倍1000,他就会采取吃药等自保行动,而郭靖也成了他攻击的第一顺位目标,这样就不会再被“快马”拉着跑了吧?
 
 同样地,如果他的最高受伤纪录才50,那有1000血的他就没必要神经兮兮地吃药了。
 这设计的价值在于更符合效益的吃药和攻击等行为判断,是否好用还是要经过调试,不太好说。
 
 3,对逃跑坐标的记录
 所谓的逃跑坐标,就是当角色放弃攻击而选择逃跑(如吃药,休息等)时,的移动坐标
 我的设计中,把这坐标放到了所有判断的最前面!
 而不同于一般的设计中,当角色逃跑时,才来计算
 为什么要如此设计呢?
 因为逃跑坐标被应用到了更广的方面来,更聪明的AI走位的实现其实不难
 
 首先说说逃跑坐标是如何决定的吧
 
 对每一个可以移动的格子,判断该格坐标与所有非我方角色的坐标差值的和,最大的那一格的坐标就是逃跑坐标了
 如,敌人A的坐标为(1,1),敌人B为(2,3),如果可选择的行动坐标分别为C(1,4)和D(2,5)
 那么可得,C与A,B的总距离为0+3+1+1=5,D与A,B总距离为1+4+0+2=7
 得到D为逃跑坐标
 
 当然,实际中不可能只有两格可走,不过从这个例子我们可以看出,逃跑坐标简而言之就是离所有敌人相对最远的一格了
 
 记录这一格的好处是很大的,除了吃药跑路等,应用是多方面的,也是例子说明吧~
 例子1,假设欧阳锋(呃)的蛤蟆功范围为线5,移动为7,跟敌人的距离为3格,
 那欧阳锋坐标为(10,10)的话,敌人坐标为(10,13)
 因此,我们可以得到逃跑坐标应该为离敌人最近的一格(10,3),
 利用了逃跑坐标后,在攻击时,欧阳锋的AI就不再是一味地接近敌人然后攻击了,他完全可以后退两步,找到一个离逃跑坐标最近,而又让武功触及到敌人的移动坐标(10,8)才进行攻击
 也就是说,我们的AI懂得后退攻击了!怎样,比想象中的要简单对吧?
 
 
 或许有人说,不记录逃跑坐标,临时计算也可以实现啊,这没错,
 但是!
 如果有10个武功判断呢?这临时计算就要走10次,先把坐标记录了,计算时可以直接代入轻松地找到最佳的走位点,那在效率方面就高了
 
 当然,也有可能是接下来的流程中都没有用到这个坐标,白算了 = =!,不过这样的可能性较小
 
 4,正面状态的判断
 正如我上面说的,这玩意往往不知道怎么让AI处理好,因为特殊武功的判断复杂,总不可能一个个去判断吧?难道必须让敌人舍弃特殊武功吗?
 这明显是不妥的,因为AI不止用在敌人身上,也要用于我方!
 谁也不想见到一按“自动”,AI就瘫痪了不是?
 
 其实说出来一文不值,就是增加武功类型数量,也就是,武功不在局限于拳剑刀特,看到这里,或许有人要喝乌鸦的倒彩了,先别急,看下去先~
 我说增加武功类型,不是说要在拳剑刀特后面再加一个什么辅助武功类型,不是!所有武功归类在四基之中在很多mod之中都是必要的,创造一个辅助类那不是变相的束缚吗?
 
 我的建议是,增加不如细化,把四基根据目标分化为对敌武功和对我武功变成8基,甚至再加上全体武功,变成12基
 
 ——拳敌,拳我,拳全,剑敌,剑我……
 
 说出来工作量似乎很大,不过就是复制一下代码,然后改一下switch case函数,阵型变量改一下罢了~~我是这么认为的
 
 对于辅助状态的存在,这样的改动是必要的,武功使用时,判断一下人物是否有对我方的武功(总不会有武功杀友军吧?),如果存在,而且我方附近存在不含某某状态的友军,则使用该武功,为友军加持正面状态。
 这样很方便是吧?至少比输入特殊武功的编号,然后一个一个的判断来得简单
 
 5,负面状态的选择
 两个字,加权~
 相比起正面状态,带负面状态的武功判定相对是比较简单的,因为这种武功完全可以看做是普通的伤害性武功,而负面状态则可看作是一个附加的伤害,多调试几次,设置好就结了
 如武功A的威力是1000,无效果,武功B是800,但带麻痹,假设设定麻痹的价值等同300伤害
 那攻击某敌人时,AI自然会选择武功B,如果敌人已经带有麻痹,则武功A更佳,这没有什么意见吧?
 哦,对了,对复数敌人也是一样的,如存在3个敌人,都是正常状态,而且武功一次性可以含盖3个敌人
 第一轮攻击,武功A的价值为1000*3=3000,武功B的价值为800*3+300*3=3300,选武功B攻击,两人麻痹
 第二轮,武功A价值依然为3000,武功B为800*3+300=2700,则选武功A
 
 
 这是AI的设计(上)的全部内容,下篇将呈现整个流程(或者我会直接写成代码?)
 
 欢迎各位研究讨论,谢谢
 
 [[i] 本帖最后由 winson7891 于 2009-7-14 08:23 编辑 [/i]]
 | 
 |