● ● ● SCP-FOUNDATION // ARMAMENT REGISTRY · 单兵枪械 · 武装记录 · ACCESS GRANTED

Foundation · Abyss Protocol — Firearm System

枪械系统 · 机制与表现图谱

这一页回答三个问题:枪能做什么(机制)你看到 / 听到 / 感受到什么(表现)数值在哪改(数据)。架构与类对类地图见 系统设计总览 · 战斗,这里是它的「玩家视角功能目录」。

对象 单兵枪械(手枪 / 霰弹枪 / 步枪) 更新 2026-06-12 数据源 Source/CoopSurvival/Weapons · Components · Data/Source/*.csv · DevelopmentUnits.md
00

这套枪是什么

anti-firearm · 关键时刻的强力解

基调是 anti-firearm(见 SD_19):枪稀缺、子弹贵、近战刀是常驻可靠底牌。枪不是主要手段,而是你压不住局面时拿出来的强力手段——一枪很响,会把远处的怪引过来(见 怪物听觉)。一切命中 / 扣弹 / 扣血都在服务器上算,客户端只负责把开火表现立刻演出来。

现有枪

手枪 Pistol(9mm · 弹匣 12 · 副武器槽)· 霰弹枪 Shotgun(霰弹 · 弹匣 6 · 多弹丸 · 主武器槽)· 步枪 Rifle(5.56 · 整身动作落地中)。枪是一行数据(FirearmDefinitions.csv),新增一把枪 = 加一行 + 配表现,不改 C++。

命中怎么算

服务器权威 hitscan(射线):子弹视觉上从枪口飞出,命中判定却落在准星——枪口出发、汇聚到准星命中点,符合传统第三人称射击的操作体验。不做 PvP 级回滚 / 反作弊重算(合作 PvE 用低成本最终确认)。

三件套深度

不是"捡起就能持续射击":弹匣(要换弹、有空仓窗口)+ 弹种(同口径多种弹,属性不同)+ 改装(按枪型升级容量 / 换弹速度)叠出取舍。

挂在 Loadout 上

长枪进主武器槽、手枪进副武器槽(按 1 / 2 键选中并举起)。装备进槽=从背包移出不占格(塔科夫式)。详见 装备 / Loadout

✅ 基础开火 / 弹药 Firearm-A 已 PIE ✅ 弹匣 / 弹种 / 改装 第一步已实现 ✅ 瞄准镜头 AimCamera-A 已 PIE 🔶 开火表现 FirearmFX-A / 声音 3D FirearmFX-B 待 PIE 🔶 整身持枪动作 手枪 / 步枪 进行中

01

开火与命中

服务器权威 · 枪口出发 · 准星命中

左键开火 = 客户端发一个有界开火请求给服务器,服务器校验(举枪态 / 弹匣 / 冷却)→ 做 hitscan → 扣弹 + 扣血 + 收集命中点 → 一次多播让各端演出来。本机可以立刻播放枪口火光 / 后坐力以保证操作跟手,但真值由服务器定。

必须举枪才开火

枪械要先进瞄准(ADS)状态才能开火——客户端先做这个预检省一次注定被拒的 RPC,服务器再权威校验一遍。非瞄准腰射只让角色转向准星 + 追加腰射散布(近战不受此限)。

霰弹多弹丸

PelletsPerShot 一次打出多颗弹丸、各自带散布——霰弹近距成片、远距散开。弹种可以覆盖弹丸数(独头弹 Slug = 1 颗精准弹)。

散布 / 射程 / 冷却

都数据驱动(FirearmDefinitions):腰射散布 vs 瞄准散布、最大射程、两发间隔。服务器按这些值结算,不在代码里写死。

命中表面会反馈

弹道开 bReturnPhysicalMaterial,把打中的世界几何 + 表面材质收集成命中点数组随多播下发——打混凝土 / 金属 / 木头出不同弹着特效与声音(见 §06)。打中可受击目标不收集(敌人走血液受击反馈)。

体感:子弹从枪口飞、却打在准星上——视觉和判定分离是有意的,第三人称相机在身后,从相机位发线会和你看到的枪口对不上。所以"枪口冒火、弹着落准星"是正确表现,不是缺陷。

✅ Firearm-A(36)基础开火 / 弹药消耗 / hitscan 已 PIE(2026-06-07) · 关键类 UCSCombatComponent · ACSFirearmWeaponActor

02

弹匣 / 弹种

每枪一个弹匣 · 换弹有窗口 · 同口径多种弹

枪从"开火时直接扣背包里的子弹"升级成弹匣系统:枪里装着多少发、装的是哪种弹,单独记在每把枪上;打空要按 R 换弹,换弹要时间(是个战术窗口)。同一口径下有多种弹,属性不一样。

弹匣怎么记 / 怎么换

按枪型记弹匣

每把枪按 WeaponItemId{已装填弹种 + 当前发数}WeaponMagazines,服务器权威 + 复制 + 存档)。不引入"武器唯一实例"——同型号共用一份弹匣状态,简化系统。

换弹(R 键)

服务器校验 → 起计时器 + 多播换弹动作 → 时间到才真正把储备弹装进弹匣(换弹动画期间数值不跳)。换弹中禁开火;首次装备某枪自动上膛一次。

自动选弹(第一步)

换弹按优先级自动选取:续当前弹种 → 默认弹 → 同口径任意有储备的弹。切弹种时把旧的余弹退回背包。手动选弹(循环键 / 小菜单)是第二步。

空仓干响

弹匣空且同口径零储备时扣扳机 = 本机播干响(不发 RPC、服务器也会拒),即时反馈"已无子弹"。有储备则走服务器自动换弹。

现有弹种(同口径不同属性)

口径弹种特点(在枪械基础值上叠加)
9mm
(手枪)
Ammo_9mm 普通基准弹,伤害 / 散布 / 后坐均为基础倍率 ×1。
Ammo_9mm_AP 穿甲穿甲系数ArmorPenetration,对护甲目标更有效——抗性管线接入中)。
Ammo_9mm_HP 空尖软目标伤害高、穿透差的取向(命中倍率 / 散布 / 命中 Buff 可配)。
Shell
(霰弹枪)
Ammo_Shell 霰弹多弹丸成片,近距毁伤、远距散开。
Ammo_Shell_Slug 独头弹覆盖弹丸数为 1PelletCountOverride),变成一颗精准远射弹。

每种弹可配:伤害倍率 / 穿甲 / 弹丸数覆盖 / 散布倍率 / 后坐倍率 / 命中追加 Buff(AmmoDefinitions.csv)。服务器开火时按"弹匣里当前装的弹种"在枪械基础值上叠加。

体感:同一把手枪,装普通弹应对普通敌人、留几发穿甲弹对付有护甲的目标——子弹本身是一层资源管理 + 取舍,不只是数字。

✅ 弹匣 + 弹种 + 自动选弹 第一步已实现 ⬜ 手动选弹(循环键 / 菜单) ⬜ 穿甲接护甲抗性管线(字段已存)

03

改装 / 升级

按枪型升级 · 容量加法 · 换弹乘法 · 分级

枪可以通过改装提升性能,升级按枪型(WeaponItemId)存,分等级累计。当前两条维度:弹匣容量(加法)和换弹速度(乘法)。加维度 / 调数值只改表,代码零改动——唯一固定的就是"容量是加、换弹是乘"两条应用公式。

两条升级维度

弹匣容量加成(累计绝对值,加到基础 MagazineSize)+ 换弹速度倍率(乘到基础 ReloadSeconds,越小越快)。有效值 = 基础 + 升级(ComputeEffectiveMagazineSize / ComputeEffectiveReloadSeconds)。

分级表

每把枪一组递增等级(WeaponUpgradeTiers.csv,Pistol / Shotgun 各 3 级)。升级路径按当前 Tier 查下一级写入。

当前如何测试

GM 面板「Weapon Upgrade / Ammo」区:Upgrade Weapon +1 / Reset Upgrade / 发射各类弹种(9mm AP·HP / Slug)。

新增维度 = 改表

想加"散布收紧""射程加成"等新升级维度:FCSWeaponUpgradeState / 表加字段 + 在有效值计算里套用,不动升级流程骨架。

✅ 数据驱动升级 + GM 入口已实现 ⬜ 接正式获取途径(改装台 / 制作,不只 GM)

04

后坐力 / 散布

柔和抬枪 + 自动回正 · 纯本地手感

后坐力是平滑模型,不是瞬间硬旋转:每开一枪给镜头加一份"目标偏移"冲量,镜头平滑上抬到该目标(punch),随后目标自动回落到零(recovery)——整体效果是一次柔和的抬枪 + 回正。只在本地控制端跑(纯手感,不碰服务器权威结算)。

可调参数

每枪一组(FCSFirearmRecoilDefinition):单发垂直 / 水平冲量度数、上抬速度、回落速度、ADS 衰减比例(瞄准时后坐更小)。弹种还能再乘一个后坐倍率。

手感怎么落地

开火被服务器接受后由 ACSPlayerCharacter::ApplyFirearmRecoil 施加,角色 Tick 里平滑插值上抬 + 回正。瞄准态传入 IsAiming() 走衰减。

散布两态

腰射散布 vs 瞄准散布分开配——不瞄准时弹着散乱,瞄准后才精准,鼓励"稳住再开枪"。

不复制每帧瞄准

后坐 / 散布是本地表现,不把每帧瞄准数据复制出去——只复制持久战斗状态与确认命中,省带宽。

✅ 后坐力平滑模型已落地(随基础枪械 / 瞄准镜头)

05

瞄准 / 镜头

越肩 ADS · FOV 收窄 · 跟手不拖影

右键进瞄 = 镜头越肩偏移 + 收窄 FOV,给一个清晰的射击视角。镜头操作体验(跟随 / 进瞄节奏)由 PlayerFeel-B 统一调校,避免"FOV 突然收窄"或准星滞后于身体。

越肩偏移

瞄准时 SpringArm 向角色右肩偏移(AimingCameraOffset),默认瞄准距离约 240、FOV 65——越肩视角便于调整、便于瞄准。

手感跟手

弹簧臂开位置延迟、不开旋转延迟(鼠标视角要跟手);瞄准态跟随速度调到接近瞬时(约 22),横向 strafe 准星不被拖在身后。

进瞄节奏

进瞄 FOV 跨度收窄(65↔78 比 65↔90 平缓),进瞄不再"FOV 骤然收窄"。

室内软碰撞

镜头臂用项目子类,撞墙 / 门框收近快、离墙推回慢——室内贴墙射击时镜头不"频繁抖动"、不穿墙露出角色内部。

✅ AimCamera-A(38)越肩瞄准已 PIE(2026-06-07) ✅ 镜头手感 PlayerFeel-B(86)已实现

06

看:枪口 / 抛壳 / 弹着

一次多播 · 数据表驱动 · 多枪共用

开火表现统一走表现配置表FirearmPresentationDefinitions.csv,按 PresentationId join,多把枪可共用一份);弹着点按打中的表面查另一张表。服务器一次多播 (枪 ID, 弹种, 命中点数组) 下发,各端自行查表并播放表现——不在 RPC 里塞声音 / 特效路径,省带宽。

🔶 单元 FirearmFX-A(87)——把"已设计未消费"的表现表接通;统一枪械开火表现的数据归属。重要教训:枪声之前从未响过——音频包归档搬位置后,CSV 里的软路径成了死链、TryLoad 静默失败不报错。搬包后 CSV 路径必须手动同步。

枪口火光 + 闪光

枪口火光 VFX 挂武器 MuzzleComponent(跟随后坐 / 换弹动作);另加一个超短命 C++ 点光源(60cd / 0.06 秒定时销毁)——在黑暗收容区开枪时照亮一瞬,才有视觉反馈(粒子包本身不带灯光模块)。

抛壳

弹壳抛出 VFX 挂武器 EjectPortComponent(机匣右侧,真实抛壳口位置在 BP_Weapon_* 里调)。

看/听弹着点

按命中表面SurfaceImpactEffectSets.csv(与脚步声共用同一套物理材质→表面名映射,Default 行兜底):碎屑火花特效沿法线弹 + 命中音效 + 弹孔贴花(机制已留、素材待配)。

命中要识别表面

弹道与脚步都用 bTraceComplex=true 按三角面取命中面材质——否则简单碰撞射线读不到渲染材质上的物理材质,表面识别"从未生效"(已修,记 UE_Gotchas §5.3)。

🔶 FirearmFX-A 编译通过 · 待 PIE ⬜ 弹孔贴花素材(机制已留)

07

听:枪声 3D 衰减

远近分离 · 按距离变小变闷 · 有方位

两层叠加:远近变体池(开枪者本机听近距脆响、其他人听远处闷响)+ 3D 距离衰减(同一发声,离得越远越轻越闷、左右有方位)。变体负责音色、衰减负责音量,两者结合才能还原"远处那一枪"的效果。

🔶 单元 FirearmFX-B(93,2026-06-12)——这一轮新做。之前枪声 / 弹着 / 爆炸都不传衰减、音频资产也没配衰减 → 全场等响(等于 2D)。补了一套共享 3D 衰减,距离走数据列。

远近枪声分离

开枪者本机播近距脆响变体池、其他端播远处闷响变体池(FireLocalCuePaths / FireRemoteCuePaths),声音从枪口位置发出。

3D 距离衰减

共享运行时衰减(CSOneShotAudio):自然衰减 + 空间化 + 远距低通(35% 距离起越远越闷,空气吸收质感);开枪者贴枪口在全响内圈、手感不变。

可闻距离(数据列)

枪声约 120mGunshotSoundRange)· 弹着约 35mImpactSoundRange,逐表面可调)· 手雷爆炸约 200mExplosionSoundRange)。改 CSV 重生成即调。

连带修脚步

脚步声衰减资产一直没配 = 队友脚步在全图音量相同;同一套共享衰减做了兜底FootstepMaxAudibleRange 25m),现在隔壁房间的脚步不再像贴近耳边一样响。

体感:戴耳机能凭听觉判断那一枪有多远、在哪个方向——漆黑环境里远处一声闷响 + 方位,就是"那边有人 / 有事"的信号。注意:这是给玩家听的表现层,和怪物用来发现你的"AI 听觉"是两套独立系统(AI 听觉走 UAISense_Hearing,那条线让开枪招怪,见 怪物怎么发现你)。

🔶 FirearmFX-B 双目标整编通过 · 待 PIE(戴耳机听近响远闷 + 方位)

08

动作:整身持枪姿态

独立 mocap 状态机 · 八向 / 瞄准 / 换弹背枪

持枪不再是"在上半身叠加一层动作",而是整身动作系统(独立 mocap 状态机)——八向走跑 / 蹲 / 跳 / 瞄准偏移 / 开火 / 换弹 / 背后取枪都用同一套军用动捕,手枪先行、步枪同架构平移。

手枪整身(Anim-Pistol-A)

Military_Pistol_01 动捕重定向到项目骨架(213 clip),整身八向 locomotion + AimOffset 瞄准 + 蹲 / 跳 + 开火 / 换弹。

步枪整身(Anim-Rifle-A)

Rifle_01(W2 军用步枪,524 clip)同流水线平移,含背后取枪 / W1↔W2 切枪过渡 / 方向急停,与手枪同标准。

为什么整身

枪械姿态影响全身重心 / 站位,纯上半身叠加会与下半身动作冲突;整身动捕一致性更好,瞄准 AimOffset 内嵌、换弹会把枪背起来。

武器表现绑哪

每把枪的握持 / 枪口 / 抛壳口位置在 BP_Weapon_* 里可视化调(预览台 M_WeaponPreview),物品数据用 EquipmentActorClassPath 链接武器 Actor,不在角色 / 战斗 C++ 里硬编码握点。

🔶 Anim-Pistol-A(83)重定向已落地 · 整身状态机接入中 🔶 Anim-Rifle-A(84)重定向已落地 · 接入中

口径:霰弹枪当前仍走旧的上半身分层动作;手枪 / 步枪的整身动作是 83 / 84 两个进行中单元,重定向(把动捕重定向到项目骨架)已完成,AnimGraph 状态机接入与战斗对接仍在进行中。
§1

服务器权威流

客户端请求 → 服务器结算 → 各端表现

一发子弹从扣扳机到打中人,走的是这条链。客户端只发送请求 + 播放表现,扣弹 / 命中 / 扣血 / 死亡的真值全在服务器

CLIENT扣扳机TryPrimaryAttack(预检举枪 / 干响)
→ SERVER RPC开火请求ServerPrimaryAttack
SERVER权威结算校验弹匣/冷却→hitscan→扣弹+扣血+收集命中点
MULTICAST下发表现(枪ID,弹种,命中点[])
ALL CLIENTS各端演出查表:枪口/抛壳/远近枪声/弹着/3D衰减

换弹是平行的另一条:RTryReloadServerReloadReloadOnServer(校验 + 计时 + 多播换弹动作)→ CompleteReload(时间到才真正储备弹→弹匣)。后坐力则纯本地:服务器确认开火后由角色 ApplyFirearmRecoil 在本机插值抬枪。

为什么这么分:合作 PvE 需要的是"操作流畅 + 防作弊 + 不穿帮"。本机立刻演表现(跟手)、服务器定真值(防作弊 / 不 desync)、多播补齐其他端(队友看得到你开枪)——三者各司其职。
§2

数据表 & 怎么调

✅ 完成 已实现并通过 PIE / 用户验收 🔶 待验证 / 进行中 代码 + 编译通过,待 PIE ⬜ 计划 / 缺口 设计有、代码无

数值改哪张表(改完跑 python Scripts\GenerateGameData.py 重生成 → 重开 PIE)

管什么
FirearmDefinitions.csv枪械基础数值:口径 / 弹匣容量 / 换弹秒数 / 伤害 / 弹丸数 / 散布 / 射程 / 冷却 / 后坐配置 / 表现 ID。
AmmoDefinitions.csv弹种:口径 / 伤害倍率 / 穿甲 / 弹丸数覆盖 / 散布倍率 / 后坐倍率 / 命中 Buff。
WeaponUpgradeTiers.csv改装分级:每把枪每级的弹匣容量加成 + 换弹速度倍率(累计绝对值)。
FirearmPresentationDefinitions.csv开火表现:枪口 / 抛壳 VFX + 本地 / 远处枪声变体池 + 干响 + 枪声可闻距离
SurfaceImpactEffectSets.csv弹着点:按表面的特效 / 音效 / 贴花 + 弹着声可闻距离Default 行兜底)。

不在 CSV 里的(在 BP / 资产上调)

  • 握持 / 枪口 / 抛壳口位置:BP_Weapon_* 上的组件位置,预览台 M_WeaponPreview 里可视化调。
  • 整身持枪动作:手枪 / 步枪的 AnimBP 状态机(重定向后的动捕 + BlendSpace 采样)。
  • 声音衰减曲线:当前是运行时按距离档位构造(CSOneShotAudio),要精调曲线可换成编辑器 ATT_* 衰减资产、调用点不变。
口径:本页是玩家视角的机制 + 表现目录,落点忠实于 Source/CoopSurvival/Weapons · Components/CSCombatComponent · Items/CSItemDataSubsystem 现状,单元状态以 DevelopmentUnits.md 为准。架构 / 类对类地图见 系统设计总览 · 战斗UE_CodeArchitecture.md;设计基调见 SD_19(武器 / anti-firearm)。开火招怪那条线见 怪物 AI · 怎么发现你