【UTの底层代码】攻防数据战
毫无技术的鸽子
2026年07月30日 08:01

好吧,标题起的很明显,那么直接进入正题,先来说说标题是什么意思:

攻击——指的是对其他人造成的伤害数值。在绝大部分游戏中,这个值越大,代表对别人造成的伤害越高。

英文Attack,缩写为ATK或AT。

防御——指的是抵抗其他人对你的伤害的数值。同样的,这个值越大,代表别人对你造成的伤害就越低。

英文Defense,缩写为DEF或DF。

但是,光有这些东西还不够,你需要合理掌控玩家的AT&DF,以及怪物的AT&DF来使得数值不会膨胀或严重缩水。这也是堪称数值策划地狱的区域。数据战。


接下来,我们将讨论UNDERTALE中使用的计算策略,和一些你可以在其他游戏使用的计算策略,方便大家按需取用学习。


一、原版UNDERTALE的逻辑

1.文件位置

scr_attackcalc

代码块
PlainText
自动换行
复制代码
defarg = global.monsterdef[global.mytarget]
global.pwr = global.wstrength + global.at
damage = global.pwr - defarg

解释:
defarg - 玩家瞄准的敌人防御
global.pwr - 玩家的伤害(自己+专武)
damage - 最终造成的伤害
复制成功

obj_targetchoice Step_0

代码块
PlainText
自动换行
复制代码
if control_check_pressed(0)
    {
        mons = global.monsterinstance[global.mytarget]
        hspeed = 0
        script_execute(scr_attackcalc)
        global.damage = damage
        global.damage += random(2)
        myx = x + sprite_width / 2
        myperfectx = obj_target.x + obj_target.sprite_width / 2
        bonusfactor = abs(myx - myperfectx)
        if (bonusfactor == 0)
            bonusfactor = 1
        global.stretch = (obj_target.sprite_width - bonusfactor) / obj_target.sprite_width
        if (bonusfactor <= 12)
            global.damage = round(global.damage * 2.2)
        if (bonusfactor > 12)
            global.damage = round(global.damage * global.stretch * 2)
        with (mons)
            takedamage = global.damage
        instance_create((mons.x + wd / 2 - 5), (mons.y - 5), obj_slice)
        global.hurtanim[global.mytarget] = 1
        image_speed = 0.4
    }
复制成功

解释:

1.造成的伤害在这里会进行2的浮动(著名GE速通景点之散光眼119伤害差一血击杀),所以打出的伤害拥有一定的浮动不是你的问题。

2.如果条的距离小于等于12,会打出这个伤害的2.2倍四舍五入取整,若大于12,这个值会变成stretch*2。stretch公式为:2 × (1 - bonusfactor / 目标宽度)


2.第一次结论

不过综上而言,UNDERTALE的攻击方式怎么算其实不太重要,重要的是它计算AT&DF的数学模型:也就是最基础线性的攻击减去防御

接下来我们去掉所有系数来看这里:

假设你有10的攻击力,对方有5的防御,那么本次造成的伤害就是 10-5=5,这就是UNDERTALE最底层的判定原理。只不过多乘了一个2.2倍或其他的系数


3.数值的规划

既然我们已经查清楚了它的公式,那么对于数值规划,又要怎么做呢?

Toby在这里,主张用防御来告诉玩家这个怪到底值不值得去打/去杀

Jerry的面板,红箭头所指地方为AT和DF

比如Jerry,防御足足有8,是什么概念?我们先回去看其他怪物:

防御数值

上面这些数值分别是遗迹怪物和雪町镇的狗狗们的防御。

我说句实话,你连其他怪都要砍两三刀才能砍死的,他们防御已经如此之低了,Jerry的8防御在这里意味着什么相信大家也很清楚。

那么,还有一种怪物,是鼓励玩家速杀的:

老滑头Glyde的面板

-20的防御,你可以比平时打Jerry的时候多打出28的伤害(还没有算上系数,要是暴击2.2倍可以直接多打62的伤害),虽然血量比较多,但是Jerry的血量也有足足80。

如果玩家直接干了一刀,发现血量掉的很快,那么就会鼓励玩家继续去打。

如果大家后续要设计/制作全流程AU游戏,可以参考一下这种做法。


4.第二次结论

数值都很低,因为DF的膨胀本身就没那么强,要知道从掉下来那一刻那你就有10的防御,而LV 20满级你也才只有14的裸防。

所以怪物的数值普遍都比较低。这也多亏了有很好做的线性攻防系统。


总结:

使用了ATK - DEF的方法来计算防御,对于这个方法的优点和缺点,以及例子我们后续就会说。

如果你不想要特别麻烦的计算,你可以直接使用原版的逻辑。

接下来,我会介绍四种方法来计算ATK和DEF的数据攻防战,如果你能接受数学,或者想要使用更高级的伤害计算方法,那么让我们就此开始。


二、常用的伤害计算策略及其优缺点

这里将介绍四种方法,你可以选择混搭用,也可以只用一种。总之——按需取用。

不过首先,你需要先了解一下我在数学公式中会写的东西:

Damage - 伤害

max - 取最大值函数,一般写成max(a,b),若a大则这个值等于a,反之同理。

ATK - 玩家的总伤害

DEF - 敌人的总防御

神秘字母 - 大部分是用来调手感的系数,都是1则是原汁原味的公式

文字描述 - 我说什么就是什么


1.线性相减法

基本公式:

Damage = k × max(ATK - DEF, ATK*0.05)

就是UNDERTALE用的那个。

优点:攻击加了多少,就是加了多少;防御减了多少就是减了多少,十分直观,而且好算。

缺点:数值涨幅太慢了,由于是超级线性,不会产生指数爆炸的情况,这就导致你有个超武+99攻击的时候,然后要是还想合理发育,怪物防御也得加巨量数值,导致逐渐膨胀。收益稀释十分严重。

个人评价:当然很适合UNDERTALE这种少量怪物的游戏,因为所有数值不会膨胀太多,只要规划好即可。


2.抗性相除法

基本公式:

Damage = ATK × ( 1 - DEF / (DEF+C) ) = ATK × ( C / (DEF+C) )

可控线性来咯!也是绝大部分策划都喜欢的一个公式。

优点:设C=1000,ATK=2000,DEF=1000,通过计算承伤为1000;现在让DEF=2000,承伤为667。可以明显感受到敌人的百分比在压缩,而且数值永不溢出。

缺点:假设拥有无视防御等能力,该算法会膨胀。举例,若DEF是10000,无视防御后造成2000伤害,伤害会多溢出22%(虽然对大部分人来说这还在可接受范围内,但是承伤真的溢出了1/5)。

个人评价:目前来看还是可以用的,而且谁没事会用无视防御的能力啊?


3.平方比除法

基本公式:

Damage = (ATK ^ 2)/(ATK+DEF)

优点:极度对称,若ATK恰好等于DEF则会造成ATK/2的伤害。极度适合高攻打高防、低攻打低防。让战斗时间趋于稳定值。例如:玩家ATK=100,DEF=30;敌人ATK=80,DEF=70。玩家打敌人造成58.8的伤害,敌人打玩家造成58.2的伤害,极其公平。(注意看面板的时候不要只看我写的ATK,带着DEF一起看)

缺点:最不适合养成碾压系列的打法,会造成数值膨胀。例如:玩家ATK=50,敌人DEF=100,造成16.7的伤害,但是ATK翻倍,攻击力会翻3倍变成50,导致后续指数爆炸很难收回。

个人评价:这个看目前来说或许是膨胀速度最快的。


4.分段函数法

果然最复杂的函数最好用......

基本公式:

Damage =

①ATK > DEF × i时:ATK - DEF × j

②其他情况:ATK × k

一般设i=0.8,j=1.2,k=0.3

在破防区间为线性减法,在未破防区间为乘法。人为制造“断点”,将防御属性拆分为“物理抵抗”和“破防属性”两个赛道。

优点:变化平缓。玩家ATK=120,怪物DEF=100,伤害40;玩家ATK=110,怪物还是100,伤害33

缺点:卡分段函数临界点不可导,导致ATK×k变成唯一解了:ATK=119,DEF=100,造成伤害35.7;而ATK=120,DEF=100,造成伤害40。离谱吗,1点伤害的差距造成了近5点伤害的差距,这就导致所有玩家的装备属性必须精确卡在阈值上,其余属性全部视为废属性,配装失去多样性。

个人评价:建议卡阈值特殊处理,其他情况下表现的还是非常好的。


结论:虽然给出这些公式了,以及它们适用和不适用的情况。但是更重要的是调控里面的可变参数,压制其膨胀能力,这也是数值策划要考虑的事情之一。

如果你有其他更好的公式想要分享,欢迎打在评论区——