一句话总结:自瞄的第二层是「选择与克制」——视场角内才参与、按角度与血量加权排序、再用平滑系数把一步到位的转向拆成多帧,本篇把选目标的完整决策树写成代码,参数怎么调也一并给出。
上一篇解决了「该转多少度」,本篇解决「转给谁」和「怎么转」。这两件事合起来决定了一个东西:像不像人。数学谁都会写,筛选和克制的分寸才是工程里的真功夫。
先把不合格的候选人筛掉
遍历绘制系列第二篇的实体快照,一个目标要过四道门槛才有资格被瞄准:
- 活着:
m_lifeState == 0且血量大于 0 - 是敌人:
m_iTeamNum与本地玩家不同 - 在视场角内:与当前视角的夹角小于 FOV 上限
- 可见数据有效:坐标不是 (0,0,0) 这类异常值
前两条是硬条件,一条不满足直接跳过。第三条是本篇重点,第四条常被忽略:快照线程偶尔会读到半截数据,坐标全零的「幽灵目标」会让数学函数算出莫名其妙的角度,加一行判空省两小时调试。
FOV 筛选:两种算法,选一种
方法 A:屏幕空间法。复用第三篇的 W2S,把目标投影到屏幕,算它与屏幕中心的像素距离,超过 屏幕高度 × tan(FOV/2) 就丢弃。直观、好调试(画个圈就能看),但目标在屏幕外时投影会算错,需要额外的背面剔除逻辑。
方法 B:角度空间法。直接在角度域比较,不依赖投影。两个方向向量的夹角用点积公式:cos θ = (a·b) / (|a| × |b|)。代码:
float AngleBetween(const Angles& a, const Angles& b) {
float dp = cosf(a.pitch * 0.01745f) * cosf(b.pitch * 0.01745f)
* cosf(a.yaw * 0.01745f - b.yaw * 0.01745f)
+ sinf(a.pitch * 0.01745f) * sinf(b.pitch * 0.01745f);
return acosf(fmaxf(-1.0f, fminf(1.0f, dp))) * 57.2957795f;
}
我更推荐 B:不依赖屏幕分辨率,FOV 语义是纯粹的「视角锥」,参数调起来更有物理直觉。5° 的 FOV 意味着只瞄几乎正对的目标,30° 就是「甩到大概方向就算中」。
图 1:视角锥内的目标才参与评分,角距越小分越高;锥外直接出局
评分排序:角距为主,血量为辅
锥内可能同时有两三个目标,选哪个?主流做法是「角距最小优先」——离准星最近的目标,转向代价最小、动作最自然。想更激进可以加权:
struct Candidate { int index; float score; };
// score 越小越优先
float Score(float angDist, float hp, float dist) {
return angDist * 2.0f // 角距权重最高
+ (hp / 100.0f) * 10.0f // 血少的略微优先(补枪逻辑)
+ dist * 0.001f; // 距离做极弱的 tie-breaker
}
权重没有标准答案,只有场景偏好。竞技服里角距权重拉满是主流;打 bot 练习时把血量权重加上,能把残血目标优先清掉。我的建议是从纯角距开始跑,感觉不顺再一项一项加权重——三个权重一起调,你永远不知道是哪个在作妖。
平滑:把一步到位拆成多帧
选好目标,拿到了需要转的角差 delta,最原始的写法是直接把当前视角设成目标角。这个效果你必须亲手看一次才会理解为什么没人这么用:视角瞬间吸附,人跟上了锁,人一死视角弹回原位——机械感扑面而来,观感上就是「我不是我在玩」。
解法是平滑:每帧只转角差的一小部分。
// smooth = 1 时退化为锁死;越大越「人」
void ApplySmoothing(float& cur, float target, float smooth) {
float step = NormalizeAngle(target - cur) / smooth;
cur = NormalizeAngle(cur + step);
}
// 渲染循环里
ApplySmoothing(curYaw, targetAng.yaw, g_smooth); // g_smooth 取 5~8
ApplySmoothing(curPitch, targetAng.pitch, g_smooth);
smooth 取值的手感大致是:1 = 锁死,3 = 跟随很快但看得出吸附,5–8 = 多数人觉得「顺滑」的区间,15 以上基本是「慢慢飘过去」,只适合大 FOV 的娱乐模式。配合上一篇说的 30Hz 快照,快照间隔内的抖动会被平滑天然抹平,这是读画解耦的第二个红利。
参数组合的起步建议
三个参数互相纠缠,单独调容易调晕。给一组能直接跑的起点:FOV 8°、smooth 6、纯角距评分。跑顺之后按需求动:想只瞄近距离贴脸的,FOV 砍到 4°;想让优先级更偏向残血,把血量权重从 10 拉到 25。每改一个参数打十组对照,别一次改三个。
下一篇预告
选好了人、算好了平滑路径,还剩收尾的动作:把新视角写回游戏。下一篇上 WriteProcessMemory,处理引擎模块的视角偏移,顺便解决「瞄身体还是瞄头」——读骨骼矩阵拿头部世界坐标,弹道从胸口升级到爆头线。

发表评论
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。