本
文
摘
要
====================关于伤害=================== 伤害是一个事件,发生时一般带有如下参数: - 伤害来源(物体/物体的整数id) - 伤害目标(物体/物体的整数id) -原始伤害值(实数或整数) - 伤害类型(类型/整数) 伤害来源: 施加该次伤害的游戏物体,可以是玩家,怪物或者自然环境。 伤害目标: 受到该次伤害的游戏物体,一样可以是玩家,怪物或自然环境。 原始伤害值: 该次伤害的字面数值,告诉伤害系统这次伤害本来该打多少。一些游戏里的伤害来源的加强伤害效果会直接在在这一层结算,比如炉石法强寒冰箭,比如一些游戏的暴击效果和攻击力浮动等。 伤害类型: 不少游戏有不止一个伤害的类型参数,这里统一讲了。 伤害类型决定伤害带有什么样的属性,是将游戏设计者想不同流程结算的伤害区分开的方式。 一个典型的例子是将伤害分为(物理,魔法,真实),物理伤害吃护甲,魔法伤害吃魔抗,真实伤害什么都不吃的设定。 这样的伤害系统的结算方式就是: -判断伤害类型 -物理:(顺序先后视情况而定) --判断物理免疫,决定是否施加此次伤害。 --获取伤害目标的物理抵抗能力(百分比或固定值)及物理伤害加深效果,乘以或从原始伤害值减去/增加。 --获取伤害目标的护甲值,计算护甲减伤公式,乘以上一步得到最终的物理伤害。 --判断伤害来源或伤害目标一些特殊技能会不会因此次伤害触发。 -魔法:(顺序先后视情况而定) --判断魔法免疫,决定是否施加此次伤害。 --获取伤害目标的魔法抵抗能力(百分比或固定值)及魔法伤害加深效果,乘以或从原始伤害值减去/增加。 --判断伤害来源或伤害目标一些特殊技能会不会因此次伤害触发。 -真实:(顺序先后视情况而定) --判断伤害免疫,决定是否施加此次伤害。 --这里不计算物理和魔法抗性,只计算一些对真实伤害有效的效果。 --判断伤害来源或伤害目标一些特殊技能会不会因此次伤害触发。 -伤害施加完毕,判断伤害来源或伤害目标其他一些特殊技能会不会因此次伤害触发。 魔兽争霸3中的伤害有攻击类型(穿刺,普通,英雄等),伤害类型(魔法,加强,普通等)还有其他杂七杂八的东西作为参数(远程,近战,攻击等),由这些参数与受伤害单位的护甲类型等属性共同决定伤害能否施加,以及最终施加的数值。 在一些其他游戏中,伤害类型则分的更加细致,也会告诉伤害系统此次伤害是由什么技能施加的,从而方便系统根据特定技能对应做出特别的效果。 =================关于伤害系统的定位================= 我认为一个伤害进入伤害系统时,已经丢失了除伤害系统参数以外的其他属性(也就是说,其他部分的结算应当提前进行)。比如这样一个伤害系统 进行攻击: -计算攻击是否命中。 -计算攻击是否被格挡/躲闪/招架。 -计算攻击是否暴击。 -计算浮动攻击力与装备攻击强度直接加成。 -将攻击伤害参数(x点,伤害来源,伤害目标,伤害类型(物理,暗影,神圣,火焰,冰霜,奥术,自然),是攻击伤害)进入伤害系统。 施加法术: -计算法术是否命中。 -计算法术是否被抵抗。 -计算法术是否暴击。 -计算法术浮动伤害与装备法术强度直接加成。 -将法术伤害参数(x点,伤害来源,伤害目标,伤害类型(物理,暗影,神圣,火焰,冰霜,奥术,自然),是攻击伤害)进入伤害系统。 环境伤害: -计算环境伤害。 -将环境伤害进入伤害系统。 伤害系统: -根据伤害类型再次分支 - 计算天赋带来的攻击/法术伤害加成 - 计算装备带来的攻击/法术伤害伤害加成 -根据伤害触发一些特效。 当然也可以认为攻击结算和法术结算这些原始伤害的结算部分也都属于伤害系统的预分支,这样说也没有问题。只是这里要明确的是,在进入伤害系统时,这次伤害才被称为(游戏界面指明的)“伤害”,得到技能和天赋的加成,在此之前,只是通过攻击力,装备属性等计算出应该施加多少伤害,而伤害系统负责计算伤害会产生怎样的变化。 ================关于公式====================== 伤害系统是由许多个公式组成和参与结算的。每一个公式对应伤害系统的一步结算。 比如魔兽争霸3所使用的护甲伤害公式(也被应用于wow和一些moba游戏): D = d * (1 - a*s / (1+ a*s) ) D:结算护甲后的伤害。 d:结算护甲前的伤害。 a:护甲值(a>=0, a为负数时有另一套公式且有上限) s:护甲减伤系数,在魔兽3和dota1里是0.06(可调整),也就是说在16.666护甲时减少50%的攻击伤害。 这样一个公式画出来就是这样。 可以看到在护甲增加时,伤害无限趋近于0,但是不会等于0。这样指望堆高护甲做到物理免疫显然是很难的了。可护甲对于玩家的收益却不是递减的。 事实上这里的护甲结算系数0.06有个更深层次的意义:面对攻击时每点护甲提升的有效生命百分比。 比如这个0.06系数下,100生命值,1点护甲值的单位受到多少攻击伤害才会死呢? D = d * (1 - a*s / (1+ a*s) ) 100 = d * (1 - 1*0.06/ (1+ 1*0.06)) 解得d = 106。 也就是说该单位因这1点护甲值可以多获得6%得有效生命。 比如这个0.06系数下,100生命值,2点护甲值的单位受到多少攻击伤害才会死呢? D = d * (1 - a*s / (1+ a*s) ) 100 = d * (1 - 2*0.06/ (1+ 2*0.06)) 解得d = 112。 也就是说该单位因这1点护甲值可以多获得12%得有效生命。 这么看来,这种护甲的收益还是很线性的嘛。 套用公式时要注意公式的特点是否符合你的设计意图。 比如这个公式的特点就在于护甲收益线性提升,和生命值相辅相成,护甲过高不会导致伤害免疫,护甲值为0时不改变伤害。 有些公式也具有上述一个或多个特点,但不具备其他的一些特点。比如每点护甲减少一定百分比物理伤害,乘法叠加。 这样的话公式就变为 D = d * (1-s) ^ a D:结算护甲后的伤害。 d:结算护甲前的伤害。 a:护甲值。 s:护甲减伤系数,表示每点护甲在上一点护甲的基础上减少多少百分比物理伤害。 图像看起来也是递减并趋近于0,然而护甲对于有效生命的提升则不是线性的。 在此公式下,100点生命1点护甲的单位的有效生命: D = d * (1-s) ^ a 100 = d * (1-0.06)^1 , d=106.38.比0点护甲提升6.38有效生命。 在此公式下,100点生命2点护甲的单位的有效生命: 100 = d * (1-0.06)^2 , d=113.17.比1点护甲提升6.79有效生命。 在必要时你也完全可以用其他公式结算护甲,甚至一刀切的方式。 在诸如《坎巴拉太空计划》的游戏中,一些部件在撞击时的伤害结算是一刀切的。部件有个最大撞击速度的极限,一旦撞击速度超过该极限部件就会爆炸,否则则相安无事。这种非此即彼的护甲结算方式可以认为是: if (d>s) { D = d; } else { D = 0; } =====================结语==================== 所有的伤害计算方式是为了游戏设计者的设计意图服务的,不要过分的追求公式的先进,掌握公式的特点并能发挥其作用才是硬道理。 转载请私信。