Sain模组,相信玩离线版的没有不安装的吧。事情的起因请看情景演示:
你拿着一支八倍镜大狙,开了一局森林,趴在狙击山上,向两百米外的ai开了一枪。很不幸,没打死。
此时ai仅花了一秒钟便转头望向狙击山,竟在两百米外与你对起枪来。
不仅如此,随着枪声响起,其他ai竟然也神秘地发现了你的位置,顿时你身边的石头火花四溅!
屏幕一黑,你睁开眼睛一看,头顶下颌腋下。
我顿时陷入了深深的怀疑。
为什么?这些ai凭什么能发现我?!
于是我去github下了Sain的源代码,一个下午过去后,再次陷入了深深的怀疑。
长话短说,Sain中ai索敌的方法有两种,声音和视力。
先说声音。Sain对声音的处理逻辑,包括枪声、非枪声(说话、脚步、换弹、扔雷等等),和“子弹打中物体声”三种情况。
于是我找到了HearingInputClass.cs,这儿负责处理以上的所有声音输入。本来想找找ai到底是怎么发现我的,好家伙,一眼看到好几个bug。
bug1:近距离震聋
if (_BotDeafedTime < Time.time) { return true; }
这个方法是用来判断ai有无被近距离枪声震聋的,结果判断里的大于号写反了……导致这个机制完全失效。
bug2:非枪声处理
if (AISoundCachedEvents_Conversations.Count > 0)
{
ProcessSounds(AISoundCachedEvents, AlreadyDeafened, DeafenCoef_Convo, SoundDataToReactTo);
}
if (AISoundCachedEvents.Count > 0)
{
ProcessSounds(AISoundCachedEvents, AlreadyDeafened, DeafenCoef_Generic, SoundDataToReactTo);
}
很明显吧……复制粘贴了两次。
Sain本来是想对非枪声(说话、脚步、换弹、扔雷等等)也有反应的,设置项里也有这项。我之前一直纳闷为啥我一直F1却吸引不了ai过来,感情是根本没生效!现版本的Sain只会对枪声有反应!
怎么说呢……Sain作者的代码风格,比较,粗犷。
修复了这两个bug之后,我发现这里有一个处理子弹打中物体声的方法
float dispersion = distance / IMPACT_DISPERSION;Vector3 random = UnityEngine.Random.onUnitSphere;random.y = 0;random = random.normalized * dispersion;Vector3 estimatedPos = enemy.EnemyPosition + random;
这下看懂了。
意思就是说,如果你在两百米外马枪了,打中了ai旁边的地板,该方法会立刻返回你的精确坐标+一个随机误差(属实有点脱裤子放屁)。
也就是说,开枪的那一秒你的位置就暴露了。
然后,我又找到了HearingDispersionClass.cs,这儿负责处理枪声的模糊。结果一进来就又绷不住了。
float ratio = distanceFromLastKnown - MIN_DISTANCE_LAST_KNOWN_NO_RANDOMIZATION / MAX_DISTANCE_LASTKNOWN_REDUCE_RANDOM - MIN_DISTANCE_LAST_KNOWN_NO_RANDOMIZATION;
减法除法,没加括号!小学生级别的错误!
这儿的设计用意是“敌人已暴露位置越近,听觉定位就越精准”,当然,完全没用。
把这儿改完后,我终于发现ai怎么确定我位置的了,当然也是返回你的精确坐标+一个随机误差,这个误差会随距离扩大。大约100m之外误差会有个5、6m吧(真是脱裤子放屁)。
所以我把这儿改成了另一个随机的算法,然后大大增大了这个误差,现在的效果是:
-
0~50 米:保持原有的线性增长。
-
50~100 米:使用二次曲线使误差急剧膨胀,模拟远距离定位困难。
-
100 米以上:直接返回一个巨大误差。
中近距离ai依然定位准确,随距离拉远会越发迟钝。这样会导致如果你在100米外射中ai,他不会立刻从枪声感应到你的位置并原地与你对枪,而是会逃跑或找掩体(我真没见过两个人相隔一百米嗯对枪的,人比蚂蚁都小)。
至此,声音的部分终于改完了……心累。
但是还没完,还要修改“视觉”的部分。
说白了,声音的部分只是让ai立刻“看”向你的准确坐标,但他要发现你,还得靠视觉。于是我找到了VisionPatches.cs。
ai发现敌人的因素倒是相当复杂:综合了天气、时间、障碍物、玩家姿势、保露程度……等等,综合算出一个发现系数。
然后,ai便从眼中射出一道激光(游戏内不可见的射线),发现系数只影响你被发现需要的时间!
意味着哪怕你在两百米外只露出一块头皮,只要ai盯得够久,照样能发现你!
经典的造了把AK用来掘地的做法。
改动这块也用了我最长的时间,换成了下面的算法:
private static float CalculateDetectionProbability(float gainMod){ // gainMod ≤ 1.0 → 100% (必定发现) // 1.0 ~ 1.5 → 100%→90% // 1.5 ~ 2.5 → 90%→10% // 2.5 ~ 3.0 → 10%→1% // > 3.0 → 1% (极难发现)}
保留了原来的发现系数,把发现系数改成了发现概率。发现系数越小,ai越有可能忽视你。
测试了两把,中近距离ai的枪法依然犀利,但它们终于无法发现200m外架狙的我了。
至此,我终于能够在塔科夫中享受成为一位臭狙仔的快乐了。
综上所述,我对Sain模组改动了什么?
-
修复近距离震聋效果,枪声有可能导致ai短暂的听力削弱;
-
ai终于会对非枪声做出反应;
-
ai终于会通过记忆和枪声判断近距离的你的位置;
-
ai再也无法通过蜘蛛感应发现隐蔽在远方草丛中的你。
附上我修改的代码和编译完毕后的dll,在Build文件夹里,直接替换原版Sain即可。有兴趣的也可以改动我的编码再编译。
折腾了一天,记录一下这个过程。

![[Sain优化]去除机器人的蜘蛛感应能力和修正一些bug](https://ods5.oddba.cn/user_files/151193/screenshot/43429662_1778157912.png)








对任何版本的sain都有效嘛
解决了我觉得离线版更难的疑惑.........