精华游戏算法整理——关于SLG中人物可到达范围计算的想法

关于SLG中人物可到达范围计算的想法

下面的没有经过实践,因此很可能是错误的,觉得有用的初学朋友读一读吧:)
希望高人指点一二

简介:
在标准的SLG游戏中,当在一个人物处按下鼠标时,会以人物为中心,向四周生成一个菱形的可移动区范围,如下:

0
000
00s00
000
0

这个图形在刚开始学习PASCAL时就应该写过一个画图的程序(是否有人怀念?)。那个图形和SLG的扩展路径一样。

一、如何生成路径:
从人物所在的位置开始,向四周的四个方向扩展,之后的点再进行扩展。即从人物所在的位置从近到远进行扩展(类似广宽优先)。

二、扩展时会遇到的问题:
1、当扩展到一个点时,人物的移动力没有了。
2、当扩展的时候遇到了一个障碍点。
3、当扩展的时候这个结点出了地图。
4、扩展的时候遇到了一个人物正好站在这个点(与2同?)。
5、扩展的点已经被扩展过了。当扩展节点的时候,每个节点都是向四周扩展,因此会产生重复的节点。

当遇到这些问题的时候,我们就不对这些节点处理了。在程序中使用ALLPATH[]数组记录下每一个等扩展的节点,不处理这些问题节点的意思就是不把它们加入到ALLPATH[]数组中。我们如何去扩展一个结点周围的四个结点,使用这个结点的坐标加上一个偏移量就可以了,方向如下:

3
0 2
1

偏移量定义如下:
int offx[4] = { -1, 0, 1, 0 };
int offy[4] = { 0, 1, 0, -1 };

扩展一个节点的相邻的四个节点的坐标为:
for(int i=0; i<4>int nodecount=0; //AllPath数组中的点的个数(包含待扩展节点和已经扩展的节点 int cutflag=0; //用于划分已经扩展的节点和待扩展节点 NODE temp; //路径中的一个点(临时) temp.x=pRole[cur]->x; //假设有一个关于人物的类,代表当前的人物 temp.y=pRole[cur]->y; temp.curmp=pRole[cur]->MP; //人物的最大MP AllPath[nodecount ]=temp; //起始点入AllPath,此时的起始点为等扩展的节点 while(curflag=MAP_MAX_WIDTH|| temp.y<0>=MAP_MAX_HEIGHT) continue; //出了地图的范围 if(pMap[temp.x][temp.y].flag) continue; //已经扩展了的结点 //经过了上面几层的检测,没有问题的节点过滤出来,可以加入AllPath AllPath[nodecount]=temp; } pMap[AllPath.x][AllPath.y].flag=1; //将已经扩展的节点标记为已扩展节点 } cutflag=n; //将已扩展节点和待扩展节点的分界线下标值移动到新的分界线 } for(int i=0;i

http://www.eb163.com/club/thread-3497-1-4.html

RPG&SRPG伤害式计算方式杂谈

以下的损伤式,如果没有特别指明的话,一般讨论的都是普通物理攻击的损伤。魔法攻击、特殊攻击暂不考虑。

基本型:
损伤=攻击力-防御力
其中,攻击力一般要分为人物自身的攻击力和武器的攻击力,所以又有:
损伤=人物攻击力+武器攻击力-防御力
防御力当然也可以分为人物的和防具的:
损伤=(人物攻击力+武器攻击力)-(人物防御力+防具防御力)
但也有个别游戏在这里选择了简化。最典型的就是FE系列。
这种基本型的一个重要之处,是人物攻击力和武器攻击力的重要性要平衡好。
以FE为例,人物部分最大值在20~30左右,而武器也一般在这个数值附近。使得二者的作用基本是对半分,其中武器的值一般略低于人物的值。
而且因为FE的数值都偏小,加上必杀的大损伤、敌人的能力值不十分高、武器的损耗等因素,使得一些初级的武器能一直使用到后期。比如776中,攻击力只有6的铁剑就能一直比较活跃。
反之,如果游戏中的人物能力值数值很高,变化很大,而损伤公式仍然是基本型的话,则存在一个武器不断替换的问题。
比如SN3,人物的能力值由开始的几十升至最后的几百,在人物能力值不同提升的同时,装备也一批一批的被更换。游戏最开始时入手的是攻击力只有十几的武器,而到最后入手的武器攻击力均在二百左右。如此的话,初期和中期入手的武器在后期是肯定不会考虑使用的。造成了武器之间的强弱等级差别很大,略失真实性。但更多的RPG都情愿采取这样的模式,因为装备的不断替换更能体现出RPG的育成、增强的感觉。
基本型的损伤式看似简单,但实际游戏中往往还要加上各种系数修正。最常见的是乱数的修正,而像SN3般虽然没有乱数影响,却也有着攻击方向、高低差、距离等因素影响,其结果并非都像FE般能比较精确地预测。

关于防御力:
防具的防御力还好理解,人物自身的防御就实在很难解释是怎样的一个概念……再强的肌肉,在刀剑面前也不见得能有多少抵抗力。所以有不少游戏采取的是只有防具防御力,没有人物防御力的做法。但仍然有很多的游戏保留着人物的防御力。看着穿布服的人用肉身承受数十下刀砍,真不知道是什么感觉>_
人物的力气和武器攻击力之间的作用关系,也一直是一个很难解释清楚的地方。按基本型的算法,只需2者之和超过对方的防御力,即使其中一者低到何种程度,也确实能给对方造成损伤。不过也有着很多游戏,对武器攻击力和人物攻击力采取的是不同的算法,这就是下面要介绍的系数型……

系数型:
人物攻击力和武器攻击力的平衡是损伤公式相当重要的一个环节。系数型与基本型最大的区别就在这里:系数型中,人物攻击力和武器攻击力不再是简单的相加关系,而是将人物能力对攻击力的影响作为系数作用在武器攻击力之上。
如下便是系数型最基本的形态:
损伤=(武器攻击力-防具防御力)×人物能力系数
这样的基本公式,被FF系列数代所采用。
系数型的计算比基本型略为复杂,损伤结果更难预测,尤其是数值比较大时更是如此。
但其实从设计者的角度,系数型的数值设定却不一定就比基本型的复杂。
系数型和基本型的区别,主要在如下的一些方面:
1、基本型自始至终都要控制好人物能力和装备能力之间的关系,而系数型因为将这二者的算法分开,便能将这二者由不同的角度去控制。
拿776来说,如果将攻击力为6的武器换为攻击力12的武器,给损伤带来的影响仍然会因为使用者的力气而有很大区别。如果人物的力为6,那么损伤增至原来的150%。但如果人物的力为20,则损伤的增加仅为原来的123%。
但对系数型来说,武器攻击力由6变为12,则意味着损伤一定是原来的200%。就是说武器攻击力的变化和人物能力的变化是比较独立地分别作用在总损伤值之上的。
2、通过控制不同时点获得的武器和防具,能将(武器攻击力-防具防御力)这一项始终稳定在一个范围之内,再通过能力值对攻击系数和HP上升这2者关系的影响公式,就能最终保证在所有数值不断增加的同时,损伤值能比较稳定地得到平衡。而正是武器攻击力和防具防御力直接作用的这个特点,为游戏带来了这样的特性:一旦防具防御力高于武器攻击力,无论系数多大,也不会有任何影响了,损伤固定为0。一般在系数型的公式算法下,高防御力的作用更容易被突出。如果是基础型的公式,尤其是那种忽略了人物防御力的公式,很容易出现到了后期各项数值都很高时,防御力的作用越来越被减弱的现象。
用系数型损伤式的游戏,最典型的就是FF9。FF9中人物能力系数在很多情况下就直接等于人物的力气值。
FF5也是系数型的代表,不过跟FF9相比,系数值除了力气的影响外,还加入了人物等级的影响。这是很多RPG,尤其是现在难度越发偏低的RPG惯用的方法。因为FF系列的能力成长很多都不是采取跟等级同步上升的方式,损伤有了等级的直接影响,对于一些不太熟悉系统的玩家,最起码还能靠练级来直接增强实力-_-
FF5的基本物理、魔法攻击系数计算式:
物理系数:(LV×力/128)+2
魔法系数:(LV×魔力/256)+4
最后附加的2和4可以看作系数的基本值,作用是保证攻击威力的程度,不至于lv、力/魔力都很低时完全没有损伤。

RPG和SRPG的区别:
跟RPG不同,SRPG往往会要求对损伤有比较精确的计算。损伤值如果由系数型计算,能比较方便的产生很大的损伤数值,但同时也会给喜欢精确计算的玩家带来一定的麻烦。
不过作为SRPG的FFT使用的也是这样的系数式。出现在FFT中的武器攻击力和人物的AP值(相当于系数)都很小,整个流程中基本都是在几到十几的范围。

简化型&综合型:
之前提到过有简化了防御力,将人物防御力去掉的损伤式。
不过更有直接把防御力都去掉,损伤式只剩攻击力的类型。
FFT便是没有防御力概念的系数型,防御的作用是增加HP。
不过游戏中的实际公式除了攻击力、防御力这些最基本的概念外,往往还要加上很多的附加项。
其实上面这样的分类是十分不严谨的。
FM4没有防御力的概念,也没有人物能力值的修正。如果按上面的分类,将是最简化的形式:
损伤=武器攻击力
但实际的公式,却有着很多其他的修正项:
损伤=武器攻击力×武器等级修正×属性修正×特技修正×Chain修正×格斗出力修正×敌方技能修正×(1+RND)
像这样每项系数相乘的公式还是很容易理解的。不过有更多的情况是在不同地方有相加也有相乘的复合公式。下面我们具体看看几个损伤公式的例子。

FFTA:
损伤=武器攻击力×(总武攻-敌总武防/2)/100
总武功=人物攻击力+武器攻击力
总武防=人物防御力+防具防御力
FFTA的损伤式比较特别的地方是,武器攻击力在计算中使用了两次,其作用被提升到了最重要的地位。武器攻击力间的差别很大,由最低的十几,到最高的87,整整相差了好几倍。而防具的防御力,仅仅只能作为跟人物防御力相加后的系数项的一部分,之后还被除2,完全放到了被忽略的地位。人物间因为不同职业成长而产生的人物攻击力差距,也不能很好的得到体现。

TO:
[(人物攻击力+武器攻击力)×攻击系数+人物防御力×防御系数]×抵抗系数
TO的损伤式是出名的复杂的,不过稍加归纳后,也可以写成如上的简洁形式。最终的损伤值还要加上乱数和攻击方式的影响。
人物攻击力一项,是:人物STR+人物DEX/2
武器攻击力是:武器STR+武器DEX/2
人物防御力是:人物VIT+人物STR/2
两个系数的影响项很多,攻击系数有:地形修正、地形属性修正、必杀修正、武器属性修正、天候-性格修正、天候抵抗、得意武器修正、对龙效果、恐怖效果、支援效果,如此多项。防御系数则少一些。影响项很多,但一般比较需要留意的也就是地形效果、武器属性等几项而已。
抵抗系数指RES,有防具的影响,也有攻击方武器属性和被攻击方人物属性的影响,作用是对整个基本损伤值按一定比例的减轻。
感觉TO的公式更多的是从设计的角度而不是数值的角度去考虑,数值的平衡性也确实有着一些问题。比如武器的攻击力是和人物攻击力直接相加,但武器攻击力一般只有3、40左右,人物攻击力后期却高达数百,使得选择武器时武器的攻击力完全放到了被忽略的位置上。

FF6:
FF6的魔法损伤式很FF5的很类似,但物理损伤式却出奇地复杂:
基本损伤=武器攻击力+(等级^2×(武器攻击力+人物力气×2)/256×3/2)
损伤=基本损伤×防御修正
防御修正=(255-防御力)/256+1
武器攻击力的最大值为255,而人物力气×2的最大值也仅255。这样的公式使得等级对损伤值的影响十分大。而任凭基本损伤一项再大,如果防御力有255,防御修正项也会使得攻击基本无效化。这点其实跟TO的防具防御力处理是很类似的。

VP:
损伤=[(人物攻击力+武器攻击力)×武器的攻击信赖度-敌方防御力]×各种修正值
本身就很高的武器攻击力,加上各种系数相乘后达到很夸张的损伤值,是VP的一大特色。
VP后期也有着明显的人物攻击力和武器攻击力不平衡的问题。武器攻击力过万,而人物攻击力不过一千多,人物间的攻击力差距更是被忽略……

RO:
MMORPG的公式经常有改动,使得讨论起来比较麻烦。比如RO中VIT对防御力的影响,在β2就被去掉了。
RO中防具的作用基本是参考了TO,损伤式比较特别的地方在于对攻击的最大值和最小值的处理上。
基本攻击力=STR+STR十位^2+DEX/5+技能影响
最大值=基本攻击力+武器攻击力×武器修正
最小值=基本攻击力+DEX
武器攻击力确定的只是损伤的最大值,而DEX能减少损伤波动的幅度。但因为STR相对于DEX的影响太大。

http://www.eb163.com/club/thread-4329-1-3.html

开始学习python

原来一直想学这个,但是没有机会,在新项目中的聊天室,打算用python+flex+socket 来实现,效率还不知道,正好顺便学学 python ,看它的语法,感觉还是很简洁的,不过习惯php 了,老是想以 php 的写法来写,这个比较郁闷了!

关于C和Python之间通信的方法

这些天在做一个项目,前端使用python来作,便于快速开发,底层使用C来写,效率高,速度快。这样就牵扯到二者之间的通信问题。我查了相关文档,发现有以下几种解决方式:

使用标准的数据表示形式,比如xml或者xdr,然后在C和python两端都有自己的相应的库,可以对这些数据进行解释,自然就可以通信了。
在C中定义一个结构对象,把它打包成二进制形式(python把它作为字符串来解释),然后使用python中的struct模块的pack函数来解析,这样就牵扯到一个解析格式串的问题,一个简单的方式是在c和python两端定义对应的两套数据结构,分别有自己的pack和unpack函数,它们可以对中间结果---二进制串,进行解析,这样就可以实现通信了。在python那一端还可以使用array模块,处理类型统一的数据,特别方便,有时候比用struct模块要爽!
使用一个xml文件将C中定义的结构都包含进去,然后在python那一端进行解析这个xml文件,自然就知道如何对每个C中的struct对象进行解析了,这样扩展性好一些。
使用第三方的库,我所知道的有boost.python和ctypes,具体怎样我也没有是用。
我在实现的时候使用了第2种方式,下面举个例子:

在c中有这样一个结构:

typedef struct test_tag {
        int a;
        int b;
}test_t;

char* test_pack(test_t* ptr){
         char * p=NULL;
         p = (char *) malloc(sizeof(test_t));
         memcpy(p,ptr,sizeof(test_t));
         return p;
}

test_t* test_unpack(char* ptr){
         test_t* p=NULL;
         p=(test_t *)malloc(sizeof(test_t));
         memcpy(p,ptr,sizeof(test_t));
         return p;
}

在python端有这样的对应数据结构:

class test:
           format='2i'
           members=('a','b')

           def __init__(self):
                  for item in test.members:
                          self.__dict__[item]=-1
            
            def pack(self,order='@'):
                        return struct.pack(order+test.format,self.a,self.b)

             def pack2(self,order='@'):
                        bin=array.array('l')
                        for item in test.members:
                               bin.append(self.__dict__[item])
                        if (sys.byteorder=='little' and order=='>') or (sys.byteorder=='big' and order=='<'):
                                 bin.byteswap()
                        return bin.tostring()
              
              def unpack(self,data,order='@'):
                        (self.a,self.b)=struct.unpack(order+test.format,data)

              def unpack2(self,data,order='@'):
                        bin=array.array('l')
                        bin.fromstring(data)
                        for i,item in enumerate(test.members):
                              self.__dict__[item]=bin[i]

然后就可以使用这些函数进行通信了