这套枪是什么
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 🔶 整身持枪动作 手枪 / 步枪 进行中
开火与命中
服务器权威 · 枪口出发 · 准星命中左键开火 = 客户端发一个有界开火请求给服务器,服务器校验(举枪态 / 弹匣 / 冷却)→ 做 hitscan → 扣弹 + 扣血 + 收集命中点 → 一次多播让各端演出来。本机可以立刻播放枪口火光 / 后坐力以保证操作跟手,但真值由服务器定。
必须举枪才开火
枪械要先进瞄准(ADS)状态才能开火——客户端先做这个预检省一次注定被拒的 RPC,服务器再权威校验一遍。非瞄准腰射只让角色转向准星 + 追加腰射散布(近战不受此限)。
霰弹多弹丸
按 PelletsPerShot 一次打出多颗弹丸、各自带散布——霰弹近距成片、远距散开。弹种可以覆盖弹丸数(独头弹 Slug = 1 颗精准弹)。
散布 / 射程 / 冷却
都数据驱动(FirearmDefinitions):腰射散布 vs 瞄准散布、最大射程、两发间隔。服务器按这些值结算,不在代码里写死。
命中表面会反馈
弹道开 bReturnPhysicalMaterial,把打中的世界几何 + 表面材质收集成命中点数组随多播下发——打混凝土 / 金属 / 木头出不同弹着特效与声音(见 §06)。打中可受击目标不收集(敌人走血液受击反馈)。
✅ Firearm-A(36)基础开火 / 弹药消耗 / hitscan 已 PIE(2026-06-07) · 关键类 UCSCombatComponent · ACSFirearmWeaponActor
弹匣 / 弹种
每枪一个弹匣 · 换弹有窗口 · 同口径多种弹枪从"开火时直接扣背包里的子弹"升级成弹匣系统:枪里装着多少发、装的是哪种弹,单独记在每把枪上;打空要按 R 换弹,换弹要时间(是个战术窗口)。同一口径下有多种弹,属性不一样。
弹匣怎么记 / 怎么换
按枪型记弹匣
每把枪按 WeaponItemId 记 {已装填弹种 + 当前发数}(WeaponMagazines,服务器权威 + 复制 + 存档)。不引入"武器唯一实例"——同型号共用一份弹匣状态,简化系统。
换弹(R 键)
服务器校验 → 起计时器 + 多播换弹动作 → 时间到才真正把储备弹装进弹匣(换弹动画期间数值不跳)。换弹中禁开火;首次装备某枪自动上膛一次。
自动选弹(第一步)
换弹按优先级自动选取:续当前弹种 → 默认弹 → 同口径任意有储备的弹。切弹种时把旧的余弹退回背包。手动选弹(循环键 / 小菜单)是第二步。
空仓干响
弹匣空且同口径零储备时扣扳机 = 本机播干响(不发 RPC、服务器也会拒),即时反馈"已无子弹"。有储备则走服务器自动换弹。
现有弹种(同口径不同属性)
| 口径 | 弹种 | 特点(在枪械基础值上叠加) |
|---|---|---|
| 9mm (手枪) | Ammo_9mm 普通 | 基准弹,伤害 / 散布 / 后坐均为基础倍率 ×1。 |
Ammo_9mm_AP 穿甲 | 带穿甲系数(ArmorPenetration,对护甲目标更有效——抗性管线接入中)。 | |
Ammo_9mm_HP 空尖 | 软目标伤害高、穿透差的取向(命中倍率 / 散布 / 命中 Buff 可配)。 | |
| Shell (霰弹枪) | Ammo_Shell 霰弹 | 多弹丸成片,近距毁伤、远距散开。 |
Ammo_Shell_Slug 独头弹 | 覆盖弹丸数为 1(PelletCountOverride),变成一颗精准远射弹。 |
每种弹可配:伤害倍率 / 穿甲 / 弹丸数覆盖 / 散布倍率 / 后坐倍率 / 命中追加 Buff(AmmoDefinitions.csv)。服务器开火时按"弹匣里当前装的弹种"在枪械基础值上叠加。
✅ 弹匣 + 弹种 + 自动选弹 第一步已实现 ⬜ 手动选弹(循环键 / 菜单) ⬜ 穿甲接护甲抗性管线(字段已存)
改装 / 升级
按枪型升级 · 容量加法 · 换弹乘法 · 分级枪可以通过改装提升性能,升级按枪型(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)
后坐力 / 散布
柔和抬枪 + 自动回正 · 纯本地手感后坐力是平滑模型,不是瞬间硬旋转:每开一枪给镜头加一份"目标偏移"冲量,镜头平滑上抬到该目标(punch),随后目标自动回落到零(recovery)——整体效果是一次柔和的抬枪 + 回正。只在本地控制端跑(纯手感,不碰服务器权威结算)。
可调参数
每枪一组(FCSFirearmRecoilDefinition):单发垂直 / 水平冲量度数、上抬速度、回落速度、ADS 衰减比例(瞄准时后坐更小)。弹种还能再乘一个后坐倍率。
手感怎么落地
开火被服务器接受后由 ACSPlayerCharacter::ApplyFirearmRecoil 施加,角色 Tick 里平滑插值上抬 + 回正。瞄准态传入 IsAiming() 走衰减。
散布两态
腰射散布 vs 瞄准散布分开配——不瞄准时弹着散乱,瞄准后才精准,鼓励"稳住再开枪"。
不复制每帧瞄准
后坐 / 散布是本地表现,不把每帧瞄准数据复制出去——只复制持久战斗状态与确认命中,省带宽。
✅ 后坐力平滑模型已落地(随基础枪械 / 瞄准镜头)
瞄准 / 镜头
越肩 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)已实现
看:枪口 / 抛壳 / 弹着
一次多播 · 数据表驱动 · 多枪共用开火表现统一走表现配置表(FirearmPresentationDefinitions.csv,按 PresentationId join,多把枪可共用一份);弹着点按打中的表面查另一张表。服务器一次多播 (枪 ID, 弹种, 命中点数组) 下发,各端自行查表并播放表现——不在 RPC 里塞声音 / 特效路径,省带宽。
TryLoad 静默失败不报错。搬包后 CSV 路径必须手动同步。看枪口火光 + 闪光
枪口火光 VFX 挂武器 MuzzleComponent(跟随后坐 / 换弹动作);另加一个超短命 C++ 点光源(60cd / 0.06 秒定时销毁)——在黑暗收容区开枪时照亮一瞬,才有视觉反馈(粒子包本身不带灯光模块)。
看抛壳
弹壳抛出 VFX 挂武器 EjectPortComponent(机匣右侧,真实抛壳口位置在 BP_Weapon_* 里调)。
看/听弹着点
按命中表面查 SurfaceImpactEffectSets.csv(与脚步声共用同一套物理材质→表面名映射,Default 行兜底):碎屑火花特效沿法线弹 + 命中音效 + 弹孔贴花(机制已留、素材待配)。
命中要识别表面
弹道与脚步都用 bTraceComplex=true 按三角面取命中面材质——否则简单碰撞射线读不到渲染材质上的物理材质,表面识别"从未生效"(已修,记 UE_Gotchas §5.3)。
🔶 FirearmFX-A 编译通过 · 待 PIE ⬜ 弹孔贴花素材(机制已留)
听:枪声 3D 衰减
远近分离 · 按距离变小变闷 · 有方位两层叠加:远近变体池(开枪者本机听近距脆响、其他人听远处闷响)+ 3D 距离衰减(同一发声,离得越远越轻越闷、左右有方位)。变体负责音色、衰减负责音量,两者结合才能还原"远处那一枪"的效果。
听远近枪声分离
开枪者本机播近距脆响变体池、其他端播远处闷响变体池(FireLocalCuePaths / FireRemoteCuePaths),声音从枪口位置发出。
听3D 距离衰减
共享运行时衰减(CSOneShotAudio):自然衰减 + 空间化 + 远距低通(35% 距离起越远越闷,空气吸收质感);开枪者贴枪口在全响内圈、手感不变。
可闻距离(数据列)
枪声约 120m(GunshotSoundRange)· 弹着约 35m(ImpactSoundRange,逐表面可调)· 手雷爆炸约 200m(ExplosionSoundRange)。改 CSV 重生成即调。
连带修脚步
脚步声衰减资产一直没配 = 队友脚步在全图音量相同;同一套共享衰减做了兜底(FootstepMaxAudibleRange 25m),现在隔壁房间的脚步不再像贴近耳边一样响。
UAISense_Hearing,那条线让开枪招怪,见 怪物怎么发现你)。🔶 FirearmFX-B 双目标整编通过 · 待 PIE(戴耳机听近响远闷 + 方位)
动作:整身持枪姿态
独立 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)重定向已落地 · 接入中
服务器权威流
客户端请求 → 服务器结算 → 各端表现一发子弹从扣扳机到打中人,走的是这条链。客户端只发送请求 + 播放表现,扣弹 / 命中 / 扣血 / 死亡的真值全在服务器。
换弹是平行的另一条:R → TryReload → ServerReload → ReloadOnServer(校验 + 计时 + 多播换弹动作)→ CompleteReload(时间到才真正储备弹→弹匣)。后坐力则纯本地:服务器确认开火后由角色 ApplyFirearmRecoil 在本机插值抬枪。
数据表 & 怎么调
数值改哪张表(改完跑 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 · 怎么发现你。