查看: 947|回复: 5

[原创] FM的CA到底怎么算的:通过逆向pre-game editor得到的CA计算公式

[复制链接]
发表于 2026-11-4 12:07 | 显示全部楼层 |阅读模式
本帖最后由 ChoreaW 于 2026-11-4 14:45 编辑

先把做的计算CA的小工具下载链接放在前面,如果不想看具体计算公式的话可以直接下载这个小工具进行计算,预设数据有凯恩、C罗、哈兰德、梅西(打开默认是凯恩)

https://pan.baidu.com/s/1TaxF13-m9HoG48Y1aqPZUw?pwd=e4sv

逆向的起源

我是2026年8月入坑FM的,玩上就开始沉迷其中,一直到现在。

同时,我是一个习惯于找教程的玩家,尤其对于这种策略向游戏(因为在此之前对足球一窍不通,把它当作策略向游戏来玩),所以顺理成章地就开始接触爆棚、A站;开始用神阵、球探工具。

不得不说这样的玩法确实很容易就很枯燥,在最初的游玩热情褪去之后,我对这款游戏的热情却没有褪去,而是转向对游戏机制的研究,甚至更乐在其中了。

我对FM26第一个研究就是从CA的计算开始的。最初,我九月末的时候在SI社区找到了一篇说pre-game editor中包含各位置球员属性分配权重的帖子,进而激发了我寻找具体的CA计算公式的想法

具体的权重表如下(这里不得不吐槽一下,那篇帖子的部分数值居然是错的,更可恶的是我找不到原帖了)







由于我人工校对了一下,所以当时很容易就发现,编辑器中有CA和推荐CA(也就是后文中的RCA)的两种说法,并且显示权重的球员属性页只展示一种权重,我是查找的不同球员的属性页获取的全部的属性权重表;在检查边翼卫和边后卫的时候发现,在这两个位置熟练度都是20的球员,有人显示的是边后卫的权重,有人显示的是边翼卫的权重(我一开始还以为原帖权重怎么错这么多),后来在位置页发现RCA的描述时,我的直觉告诉我这应该是两个位置计算CA取最高值,后来也确实验证了这一猜想。

但是即便我们确定了CA是根据这份位置权重计算出不同位置的RCA,然后取最高值这个基本猜想,距离获取最终的计算公式还是远远不够的,到这里我的兴趣被激发起来了,于是我做了一个大胆的决定:花费我宝贵的GPT订阅额度,逆向验证我的猜想(对于月薪600的穷学生来说真的很宝贵了)

不得不说AI的强大,给了我一个极大的震撼,前后不到一个小时就给出了CA的完整计算公式并验证零误差(当时还没有REA这个项目,我也只给了AI可以使用Ghidra的提示),下面我向各位教练讲解一下这个公式是怎么运行的(Astra强大归强大,但是也是真的不说人话,不到一个小时就出来的公式,我硬是看了一晚上才看懂)

计算公式

开始算之前,还是得把CA和RCA分开说一下。我们从属性算出来的是推荐CA,也就是RCA,不一定等于存档里保存的CA。所以下面先算“这套属性对应多少RCA”,至于球员怎么成长、什么时候涨CA或者掉属性,留到后面有机会再聊,不然这一篇估计就没完了。

有了权重表,最容易想到的算法就是把每项属性乘上权重,加起来,再换算到200以内(就和大学计算GPA一样),但是真正的计算并不止一轮,尤其是多位置和属性分布,不处理这两部分,可能计算出来的值总会偏差几个数字。

为了不让大家和我一样看一晚上,我们直接造一个球员,跟着他算一遍:只有前锋位置,熟练度20,普通属性全部13,左脚20,右脚10。

这里还有一个小细节,计算使用的是内部1—100的属性,不是面板上的1—20。这个例子里,我们明确把普通属性设为65,左脚100,右脚50。实际存档的面板数字经过取整,不能保证每个显示13的属性内部都是65(实测开档时,确实有很少一部分的球员,在计算的时候内部计算值不是属性x5,这个区别我主要在一些年纪很小的球员上见到,我猜测实际上各属性的取值范围就是百分制,我们看到的20取值都是经过除以5取整的属性值,球员在成长过程中是按照百分制成长的),所以拿截图里的数字去算,可能会差一点。

1. 先算一个大概的CA

先拿上表的ST这一列,把每项属性乘上自己的权重,加起来,再除以总权重,就是加权平均。权重为0的自然乘完还是0,所以决心、才华这些就算从1改到20,也不影响这一步的结果(不过不占CA不代表没用,这个大家应该都知道)。

脚法这里要单独看一下。我们这个球员左脚100,程序就不算左脚,只把右脚50乘上前锋的脚法系数7.5,一起加进去。

最后得到:

权重之和=123.5

属性乘权重之和=7915

加权平均=7915 ÷ 123.5 ≈ 64.089(此时满分100)

换回比较熟悉的20分制,就是12.818左右。因为右脚比其他属性低,这个平均数也被拉低了一点。

接下来套入:

初始CA=(加权平均 ÷ 5 - 6)× 20

算出来约为136.36,去掉小数就是136。如果算出来连1都不到,就按1算。

算到136,感觉已经可以收工了,但这个136还只是程序先猜的一个数。我们的球员最后会算出135,差的这1点,就得接着往下算才能看出来。

2. 属性分布修正:为什么136最后变成135

现在只有前锋一个位置,先不用管多位置的事。拿刚才猜的136反过来算一个属性基准,后面每项属性都要和它比:

基准=(136 ÷ 20 + 6)× 5=64

然后拿球员每一项参与计算的属性,和64比较:

加权偏差=(属性内部值 - 基准)× 该属性权重 ÷ 5

这里一定要把权重乘进去,比如属性差了14,并不是直接拿14去和阈值比较,还要乘上这个属性的权重,再除以5。至于阈值怎么算,又要用到前面那张权重表:

阈值=3.75 × 总权重 ÷ 非零权重项数

我们的前锋有33个非零权重项,所以阈值就是3.75 × 123.5 ÷ 33,约为14.034。也就是说,每项属性的偏差要按各自的权重算,但比较的时候用的是同一个阈值14.034。

加权偏差在-14.034到14.034之间,就不用额外修正;超过这个范围,只算超出的那一截。正向超出就加,负向超出就减。不过不用修正的属性还是参与前面的加权平均的,并不是直接不算了。

先把136这一轮算完

普通属性都是65,与基准64只差1,就算乘上最高的权重10,再除以5,也只有2,没有超过阈值,所以这一轮普通属性都不用额外修正。

但是右脚只有50,权重又有7.5:

属性差=50 - 64=-14,加权偏差=-14 × 7.5 ÷ 5=-21,超出的部分=-21 + 14.034 ≈ -6.966

所以如果刚才直接拿-14去比,就会以为右脚也没过阈值

接下来,把每项属性超出的部分加起来,乘以3.75,再加回原来的加权总和。这个球员只有右脚需要修正,因此新的平均属性就是:

(7915 - 6.966 × 3.75)÷ 123.5 ≈ 63.878

然后用基准减去这个新平均数,得到差值e=64-63.878≈0.122。程序根据这个差值e决定CA还要不要动,不过它的取整方式有点特别:

e≥0:e+0.5取整,取整后若为0,则强制改为1

e<0:e-0.5取整

这里的“取整”就是直接去掉小数,比如-0.639会变成0,不是-1。

我们把取整后的数暂时叫作t,后面还要用到。最终t为正就减1CA,为负就加1CA,为0就结束。t只是用来判断方向的,即便算出来是5,也只减1CA,不是减5。

这一轮的0.122加上0.5,得到0.622,去掉小数是0,再被强制改成1,所以CA要减1,从136变成135。

这里也挺别扭,不能把它理解成“误差小于0.5就结束”,因为正负两边处理不一样,甚至差值正好是0,也会被改成1(光看这一段,确实会觉得正数直接减1不就行了,为啥还要加0.5取整这么一遭,不过后面还要拿t和上一轮比较,所以它具体是几,也还会用到)

变成135之后,右脚还要再算一次

CA变了,基准就变成:

基准=(135 ÷ 20 + 6)× 5=63.75

权重没变,所以阈值还是14.034。普通属性现在比基准高1.25,即便按权重10计算,加权偏差也只有2.5,依然没过阈值。

右脚则要重新算,不能沿用上一轮的-6.966:

加权偏差=(50 - 63.75)× 7.5 ÷ 5=-20.625

超出的部分=-20.625 + 14.034 ≈ -6.591

修正后的平均属性=(7915 - 6.591 × 3.75)÷ 123.5 ≈ 63.889

右脚还是超过阈值的,只是比上一轮少超出了一点。再用基准减去修正后的平均属性:

63.75 - 63.889 ≈ -0.139负数先减0.5,得到-0.639去掉小数,得到0

这次t终于是0了,程序就停在135。所以这里不是等到右脚不超过阈值才停,而是把右脚超出的部分也修正完,再比较两个平均数,取整后得到了0,才算结束。

如果一直算不完呢?

我们这个球员两轮就算完了,不过程序还会记着上一轮的t,下一轮拿来比较,处理那些前后反复变化的情况。这里不用再翻权重表了,只看刚才算出的t和上轮留下来的数。

首先,t不能无限大,程序会把它限制在一个范围内,而且越往后算,范围越小:第1—9轮是 - 5到5,第10—19轮是 - 4到4,接下来每10轮再缩小一点,到第40轮以后就只剩 - 1到1了。比如第1轮算出8,就先按5处理。

然后,只要这一轮t不是0,而且有上一轮的记录,就拿两轮的结果再比较一下。这一轮还是叫t,上一轮就叫t0,按代码顺序往下看:

  • 如果t和t0相差至少6,而且t的绝对值至少为2,就把t除以2,去掉小数。比如上一轮是3,这一轮是 - 3,相差6,这一轮就先改成 - 1。

  • 如果处理后的t,绝对值还是比t0大,就压到和t0一样大,正负号不变。比如t0是2,t是 - 4,就把t改成 - 2。

  • 如果两者恰好一正一负、大小相同,而且不是1或 - 1,就再往0缩小一点。接着上面的例子,t0是2、t是 - 2,t就再变成 - 1。

  • 如果t0是正数,而处理后的t还比t0大,代码会直接减1CA,保留上一轮记录,跳到下一轮。这一条是复现代码里保留的分支,照前面的限幅规则走,通常不会走到这里。

  • 没有走上面的跳转,而且t0是负数,就在t和t0中取较大的那个。比如t0是 - 1、t是 - 2,就保留 - 1。


这几步要按顺序看,后一步用的是前一步改过的数。正常走完之后,把这次的t记下来,再根据它的正负决定CA加1还是减1,等于0就停止。我们的前锋第一轮还没有上轮记录,第二轮直接算出0,所以都没用到这几条。

至于次数,程序的循环编号是0到100,第0轮通常用来算初始CA,后面最多再比较、调整100轮。到上限还没得到0,也会停下来,用当时的候选值继续往下算,并不是一定要算到两边相等才肯结束。如果中途候选CA掉到0或以下,还会重新算初始值,这也占用循环次数,不会因此重新获得100轮。

所以这个例子的完整过程就是:第0轮猜136,第1轮判断应该减1,变成135,第2轮判断值为0,结束。

文中小数为了方便阅读做了四舍五入,程序实际计算还得保留原来的精度和顺序。尤其涉及刚才那些取整,差一点点就可能多算一轮,不能直接拿我这里保留三位小数的数值替代。

算到这里就能发现,加权平均一样,RCA也不一定一样。平均数相同,但有的球员这项高一点、那项低一点,乘上权重后,超过阈值的部分就可能不一样,后面自然也可能算出不同的结果。

所以“某项属性涨1点,固定占多少CA”这个说法,拿来大概估一下还行,真要精确算就不能这么省事了。

3. 双脚:为什么练弱脚会占CA

刚才算了两遍右脚,大家应该已经看出来,它和普通属性一样要参与计算,而且前锋的脚法系数有7.5,还真不低。其他地方都不动,只改右脚,再分别算一遍:

右脚内部值 最终RCA
25 125
50 135
75 142
100 151

普通属性同样全13,左脚100、右脚50的时候是135,双脚都100就到了151,差了16点。只盯着普通属性面板,还真看不出来这16点去哪了。

不过不能因此记成“双脚就是多占16CA”,这只是我们这个球员的结果。脚法是跟着其他属性一起加权、一起修正的,换个人或者换个位置,算出来的差值也可能变。

前面表里写“弱势脚系数”比较好理解,但程序实际判断的是:左脚100、右脚不足100,就只算右脚;右脚100,就只算左脚,双脚都100也按这条走;如果两脚都不足100,那两只脚都要算。

4. 多位置:位置组合成本到底怎么算

接下来给我们这个前锋加一个中后卫位置,两个位置熟练度都设为20,其他属性不动。按前面的猜想,应该是拿前锋和中后卫的权重各算一遍,再取高的那个,但这里还有一个东西没算:位置组合成本。

这个成本要根据球员的全部位置熟练度算出来,并没有一张“前锋+中后卫收多少”的现成价格表。算下来,这个组合的成本是25,下面就看看这25是怎么来的(先别急着往135上加,这个25还不是CA)。

先看看他到底会踢哪些位置

首先,把每个位置的熟练度减去10,小于0就按0算,再全部加起来,暂时记作S:

S=Σ max(位置熟练度 - 10,0)

我们这个球员前锋20、中后卫20,其他位置都设为0,所以S=10+10=20。如果再多一个熟练度12的位置,也要加上2;10及以下就不用加。

然后看这些位置分布在哪,不过到这里门槛变了,熟练度至少15才算数。比如刚才那个熟练度12的位置,算S的时候能加2,到这里却还不算会踢这个区域(所以不是从头到尾都用同一个门槛)。

程序先把球场从后往前分成六层:

层次 包含位置
门将 GK
后卫 DL、DC、DR
后腰/翼卫 DM、WBL、WBR
中场 ML、MC、MR
攻击中场 AML、AMC、AMR
前锋 ST

会踢这一层里的任意一个位置,就算占了一层。同一层会踢三个位置也只算一层,比如左中右后卫都能踢,在这里仍然只算一层后卫。把层数记为R,我们的前锋+中后卫就是R=2。

横向也数一下,看看占了左、中、右几路,记为L:

路线 包含位置
左路 DL、WBL、ML、AML
右路 DR、WBR、MR、AMR
中路 DC、DM、MC、AMC、ST

这里门将不算任何一路,ST算中路。所以前锋和中后卫虽然隔得远,但都在中路,L还是1。

数完还会有两项减分。后腰/翼卫、中场、攻击中场这三层,只要占了至少两层,就减3;只要有左路或者右路的位置,也减3,左右都能踢还是只减3,不会减6。

前锋+中后卫碰不到这两条,就不用减。后面公式里用D中场、D边路代表这两个减数,碰到哪条,哪项就是3,没碰到就是0。

都是会踢两个位置,前锋+中后卫还要多算一点

到这里还没完,程序还会把刚才的六层重新归成四个大区:门将、后卫、中场、前锋。其中后腰/翼卫、中场、攻击中场这三层,在这里都归到中场里(是的,前面分开数,到这里又合起来数了一次)。

先数一共占了几个大区,记为N。前锋+中后卫占两个,前锋+前腰也是两个,但接下来还有三条处理,按这个顺序来:

  • 会踢门将,而且还会踢其他大区,N再加2。

  • 同时会踢后卫和前锋,N至少按3算,已经大于3就不用改。

  • 同时会踢后腰/翼卫层和攻击中场层,N至少按2算,已经达到2也不用改。


这里仍然只看熟练度至少15的位置。比如后腰和前腰本来都属于中场,N只有1,但第三条会把它提到2。

我们的前锋+中后卫则碰到了第二条,明明只占两个大区,计算时N却要用3。前锋+前腰没有碰到这三条,N还是2。

然后用N算一笔额外成本,记为K:

N小于2,K=0N至少为2,K=N² ×(N+1)

这样,前锋+中后卫的K就是3²×4=36,前锋+前腰却只有2²×3=12。两个组合的差距主要就在这里。

涉及门将时差别还会更大,例如门将+前锋,两个大区再加2,N就到了4。至于为什么要这样定,只能说代码里是这么算的,开发者当时怎么想的我就不知道了。

把前面的数加起来,25就出来了

前面虽然数了好几遍,最后合起来只有这条式子:

V=S+3 ×(R+L)- D中场 - D边路+K

把我们的前锋+中后卫代进去,S是20,R是2,L是1,两项减分都是0,K是36:

V=20+3 ×(2+1)- 0 - 0+36=65

最后再处理一下范围:V低于40就按40,高于140就按140,然后减去40,得到位置组合成本P。

所以V不超过40,P就是0;V在40到140之间,P就是V减40;再往上,P最多也只有100。

我们这里的V是65,因此:

P=65 - 40=25

这就是25的来历。用同样的方法,只有前锋的时候,S=10,R=1,L=1,N=1所以K=0,V=10+3×(1+1)=16,没过40,P就是0。

换成前锋+前腰,S还是20,占两层、中路一路,两项减分也都是0(这里只占了攻击中场一层,还不满足“中间三层占至少两层”)。但N是2,K只有12,所以:

V=20+3 ×(2+1)+12=41

P=41 - 40=1

再换一个能用到减分的组合:左后卫DL20+左翼卫WBL20+左前卫ML20。三个位置各贡献10,所以S=30;占了后卫、后腰/翼卫、中场三层,但都在左路,所以R=3,L=1。

这次后腰/翼卫和中场都占了,可以减3;又因为有左路,再减3。大区则只有后卫和中场两个,N=2,K=12,算下来就是:

V=30+3 ×(3+1)- 3 - 3+12=48

P=48 - 40=8

这样就能看出来,会踢三个位置也不一定比会踢两个位置成本高,要看具体是哪几个位置。熟练度也一样,位置名字没变,但熟练度变了,前面的S、层数和大区判断都有可能跟着变。

算出来的25,怎么放回CA公式里?

前面说过,这25不能直接加到CA上。它先除以3,去掉小数,再和“本轮候选CA除以4、去掉小数”比较,取较小的那个,记为C:

C=min(P ÷ 3的整数部分,候选CA ÷ 4的整数部分)

比如我们第一轮猜的是136,P是25,那么25÷3取整数是8,136÷4是34,取小的,C就是8。

接下来,把C塞进前面的基准公式:

基准=[(候选CA - C)÷ 20 + 6]× 5

只有前锋时P是0,C也是0,就还是之前那条公式。加上中后卫后,第一轮基准就变成:

[(136 - 8)÷ 20 + 6]× 5=62

原来拿属性和64比,现在变成和62比,普通属性、右脚的偏差都得重算,后面超过阈值的部分、CA加1还是减1,也就跟着变了。每一轮都要用当时的候选CA重新算C,只是我们这个例子算下来,C一直是8。

最终,把前锋和中后卫分别算完,会得到下面的结果。普通属性仍然全13、左脚100、右脚50,列出的位置熟练度都是20,其他位置为0:

位置配置 位置组合成本P 前锋RCA另一位置RCA 最终RCA
ST 0 135 - 135
ST+AMC 1 135 134 135
ST+DC 25 142 144 144

加一个中后卫,连前锋这一项都从135变成了142,因为

前锋计算时也带着这笔位置成本。最后从142和144里选高的,才得到144。

至于前锋+前腰,虽然算出了1点位置成本,但1除以3去掉小数就成了0,C也就还是0,所以这笔成本没有改变前锋的结果。前腰另算出来是134,还没有前锋高,最后照样取135。

所以我开头“每个位置算一次,取最高值”的猜想,方向是对的,但每个位置并不是单独拿出来算。球员会踢的其他位置,也通过这笔成本参与了计算。

5. 最后再看位置熟练度,选出最高的RCA

前面一直把位置熟练度设成20,所以还少讲了一步:如果这个位置没那么熟呢?

算这个位置的时候,权重还是照上表那一列用,不会因为熟练度低就先把权重打折。等候选CA算出来,再按实际熟练度乘下面的比例:

熟练度
保留比例
熟练度
保留比例
18-20
100%
10
80%
17
99%
9
72%
16
98%
8
64%
15
96%
7
56%
14
94%
6
40%
13
92%
5
24%
12
88%
4
8%
11
84%
2-3
1%

还是拿只有前锋的那个球员,熟练度从20改成15,位置成本算下来仍然是0,所以前面还是得到135。到这里再乘96%,得到129.6,取整就是130(这里是加0.5再去掉小数,别和前面误差那套取整搞混了)。

只要是熟练度至少2的有效位置,程序都会这样算一遍,结果低于1就按1,高于200就按200。全部算完,选最高的那个,这才是最后的RCA。前锋+中后卫那一组,就是从142和144里选144。

如果两个位置算出同一个数,还会看熟练度、脚法等来决定选哪个位置,不过既然数值一样,也就不影响最后的RCA了。

到这里才算把开头的猜想走完,确实是每个位置算完取最高值,但光是这个“算完”,就经过了属性加权、双脚、位置组合、属性分布修正,最后还要按熟练度折减。

得到这个计算公式之后在python中复现只需要短短的几十行,但是却不得不惊叹这样的计算方式到底是怎么想出来的,而这只是FM庞大计算体系的冰山一角,也是如此才造就了让诸位教练痴迷其中的独特魅力(不得不说我一个新手教练都觉得FM26的UI是真够臭的,但是入坑太晚,FM24已经下架了,只能捏着鼻子忍受,也是十分感谢各位皮肤制作者,也是因为有皮肤才让我没有在一开始就放弃)。

后记

而RCA与CA之间,其实刚刚开档的情况下都是相同的,也几乎可以认定为静态计算球员CA的完整公式了,只有涉及到球员成长时,就可能有所不同,这也是这次探索最有意思的地方。AI在探寻CA与RCA的关系时,自动探索了FM中CA成长的相关机制,居然能与我之前在爆棚刷到的训练是如何分配属性的帖子相互验证,这确实是非常惊喜和有趣的事。

而对于FM27,因为pre-game editor还没有出来,只能在游戏运行时从内存中提取相关字段验证,实测下来权重表并没有变化,根据现有的公式从球员属性计算CA也保持了FM26中的零误差(并没有穷举全部球员,而是计算了200位单位置球员和500位多位置球员)

并不知道我的讲解各位教练能不能看懂,毕竟看AI解释多了,我感觉自己写的文档都一股AI味了,这也是我为啥会选择穿插各种啰嗦的注解的原因,感觉这样能让我回归人味,要不然我就要过拟合了,哈哈哈哈。

如果后续有时间,我会继续写一下AI逆向CA成长机制的帖子,那里的计算逻辑同样很绕。


权重表格

权重表格
发表于 2026-11-4 12:29 | 显示全部楼层
深度好文 爆棚有你更精彩~  仔细拜读学习一下
发表于 2026-11-4 13:02 | 显示全部楼层
先留言 再慢慢看
发表于 2026-11-4 14:27 | 显示全部楼层
不行了,我要把你这片文章丢给AI,让他告诉我你在说什么。
发表于 2026-11-4 15:24 | 显示全部楼层
纯技术贴啊 有时间慢慢看
发表于 2026-11-4 15:26 | 显示全部楼层
纯技术贴啊 有时间慢慢看
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|Archiver|爆棚小组 PlayGM论坛

GMT+8, 2026-11-5 15:36 , Processed in 0.067689 second(s), 19 queries , Gzip On.

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表