算式表¶
本檔角色:所有核心算式的權威 source of truth。 涵蓋物理(動力 / 熱 / 磁 / 損耗)、武器技能、經濟、信譽、評分。
0. 命名約定¶
- 變數:snake_case;常數:UPPER_SNAKE_CASE
- 時間步長:
dt(秒);物理引擎 fixed 60Hz →dt = 1/60 ≈ 0.0166 - 單位:質量 g、長度 mm 或 m(標註)、力 N、效果能量 J、電池容量 mJ、功率 W/mW、溫度 °C;衝撞 stress 鏈用 mJ(§7)
- 量化分域:經濟 =
bigint(§12–§15);信譽 / 評分 / 仲裁權重 = 整數(X100 量化 / 查表,§16–§19);物理 =f32(wasm 統一 build)
1. 質量與體積¶
volume_cm³ = volume_m³ × 1_000_000 // 幾何積分的 canonical 外部單位為 m³
mass_grams = volume_cm³ × density_g_per_cm³ // density 權威單位 = g/cm³(材質表 §1)
整車驗證(車輛組裝.md):
VEHICLE_TOTAL_MASS_MIN_GRAMS ≤ Σ part.mass_grams ≤ VEHICLE_TOTAL_MASS_MAX_GRAMS
max_part / min_part ≤ VEHICLE_PART_MASS_RATIO_MAX
整車限制值只由 零件與共用介面.md §7.1 定義;本節只保留聚合算式。
2. 駕駛動力¶
輸出功率 = motor 吸收上限與 battery 依 SOC 線性降額後的可供輸出取小:
soc = remaining_energy_q / initial_energy_q
available_output_mw = floor(configured_output_mw × remaining_energy_q / initial_energy_q)
drive_input_mw = min(motor.auto_input_mw, available_output_mw)
actual_power_w = drive_input_mw / 1000
actual_supply_power_w = drive_input_mw / 1000
remaining_energy_q 使用 1/60 mJ quantum;固定 60Hz 下,供應 P mW 一幀恰扣 P quantum。
作者設定與資料卡使用 configured_output_w;進入決定性解算前固定換算
configured_output_mw = configured_output_w × 1000,後續取小與扣能一律使用 mW。
只要 motor/battery 存活且自走命令有效,駕駛先扣 drive_input_mw,即使已達極速、失去牽引、
卡牆或輪胎全壞也不省電。全 SOC 無 knee/reserve/固定停車線;低 SOC 可保有非零能量,但可供
功率可能已不足以克服質量、坡度與滾阻。
衍生扭力 / 速度(給上層運動模擬):
motor.derived_torque_nm = actual_power_w × torque_ratio / 100 × K_TORQUE_FROM_W
motor.derived_top_speed_mps = actual_power_w × (100 - torque_ratio) / 100 × K_SPEED_FROM_W
surface_grip = min(active grip_loss / sticky grip_modifier,無命中為 1)
surface_top_speed_mps = motor.derived_top_speed_mps × surface_grip
torque_impulse_ns = (motor.derived_torque_nm / wheel_radius_m) × dt × surface_grip
top_speed_impulse_ns = total_mass_kg × max(0, surface_top_speed_mps - forward_speed_mps)
drive_impulse_ns = min(torque_impulse_ns, top_speed_impulse_ns)
contact_friction_ij = Average(tire_collider_i.material.friction, surface_collider_j.material.friction)
traction_share_ns_i = Σ_j(normal_impulse_ns_ij × contact_friction_ij)
linear_share_ns_i = min(drive_impulse_ns / original_driven_tire_count, traction_share_ns_i)
angular_impulse_nms_i = linear_share_ns_i × tire_radius_m_i
wheel_speed_limit_rad_s_i = surface_top_speed_mps / tire_radius_m_i
rr_pair_ij = tire_collider_i.material.rolling_resistance × surface_collider_j.material.rolling_resistance
rolling_impulse_ns_i = K_ROLLING_RESISTANCE × Σ_j(rr_pair_ij × normal_impulse_ns_ij)
rolling_impulse_ns_i = min(rolling_impulse_ns_i, impulse_to_zero_relative_rolling_speed_i)
top_speed_impulse_ns 是該幀可增加的最大前向動量:起步仍使用完整扭矩,但接近極速時只補足
剩餘 Δv,不得因 fixed timestep 在最後一幀跨越地表可達極速。drive_impulse_ns 永遠以安裝時
原始 driven tire 數分母切份,只把各份交給未損壞 tire,故標準四輪依序剩 100/75/50/25/0%;
不得把損壞輪份額重分配。每顆 tire 沿 chassis-side Mount local +X 的 Revolute 軸取得角衝量,primary
body 同時取得等量反向反作用角衝量,車體線性前進只由輪胎接觸摩擦產生。實際單輪份額再受
本幀真實 contact manifold 的 normal impulse 與雙方材質 Average 合成上限約束;無接觸可空轉,
但不得直接推 primary body。rolling impulse 沿 wheel_axis × contact_normal 的實際滾動方向反向
作用,最多降至相對速度零,不得反向加速。接觸依 canonical collider key 穩定累加。
已達 wheel_speed_limit_rad_s_i 的輪胎不再取得驅動。broken tire/roller 的 collider、獨立 body 與 Revolute 於幀末退出物理,primary body 依剩餘完好零件重算質量、local COM 與慣量;
tire 全損壞時推進為 0。grip_modifier 同時縮放可傳遞扭矩與地表可達前向速度,sticky 仍另外套用材質表的每幀
速度衰減。正式公版首次扭矩校準見
D-20260807-02,Revolute 接觸拓樸見
D-20260807-03,損壞鏈見
D-20260811-06 與取代舊係數切換模型的
D-20260814-05。
駕駛耗電(固定幀整數帳、不得透支):
granted_drive_q = min(remaining_energy_q, drive_input_mw)
remaining_energy_q -= granted_drive_q
HUD 同時顯示儲存 SOC 與 available_output_mw / configured_output_mw;當
available_output_mw < motor.auto_input_mw 顯示「輸出受限」,實際失速由既有 stall/進度回饋呈現。
3. 武器 / 技能動能(不過 motor)¶
⚠️ 武器/技能預算只與 battery 的低 SOC
available_output_mw有關,不過 motor。駕駛先結帳,之後依已簽 canonical input event 順序結帳;兩路不互相削減滿額瞬時效果,只共用剩餘能量帳。
skill_power_budget_mw = floor(available_output_mw × allocation_pct / 100)
effect_energy_j = skill_power_budget_mw × effect_frames / (60 × 1000)
battery_cost_q = skill_power_budget_mw × cost_frames
allocation_pct 是 1–100 整數百分比,計算時除以 100,不依全槽總和正規化;總和低於 100 可刻意
低配。Event 的 effect_frames=60(1 秒效果預算),cost_frames 由各 Event protocol 常數獨立指定;
Hold 的 effect/cost 都是當幀 1 frame。若剩餘能量不足,granted/requested 同比例縮放效果與成本,
禁止透支。passive weapon 不耗能。launch 只有 projectile 確實成功 release 時,才以
LAUNCH_FIRE_INTERVAL_MS 對應幀數同時結算效果、電池成本與熱;冷卻中、空彈或 release 失敗皆為 0。
| Skill 類型 | 觸發行為 | dt |
|---|---|---|
| Event 單發 | boost / brake / jump / slam | 1.0(等效 1 秒衝擊) |
| Hold 持續 | swerve_left / swerve_right / stabilize / weapon | 當幀實際 dt |
技能效果分發(各 K 常數待 playtest 校準;VEHICLE_X / VEHICLE_Y / VEHICLE_Z = 車輛 local 單位向量 = 前向 / 左向 / 上向,對應 runtime GLB 軸 −Z / −X / +Y,見 零件與共用介面.md §5 軸向速查):
| Skill | 效果 |
|---|---|
boost |
+VEHICLE_X × applied_energy × K_BOOST 線性衝量 |
brake |
-VEHICLE_X × applied_energy × K_BRAKE |
swerve_left |
+VEHICLE_Y × applied_energy × K_SWERVE |
swerve_right |
-VEHICLE_Y × applied_energy × K_SWERVE |
jump |
+VEHICLE_Z × applied_energy × K_JUMP |
slam |
-VEHICLE_Z × applied_energy × K_SLAM |
stabilize |
角阻尼 += applied_energy × K_STABILIZE |
weapon |
分發給武器機制(active 觸發;passive 占槽常駐) |
武器 general actuator 轉速(零件與共用介面.md §3.7;energy-driven、共用功率分配):
P = available_output_w × allocation_pct / 100 // 該武器功率預算
ωᵢ = P × K_WEAPON_ROTOR_SPEED × ( speed_weightᵢ / Σ speed_weight )
- 各 actuator 分同一份 P(共用 chip
weapon槽);speed_weight預設 1 → 均分1/N。 - 加 actuator → Σ 變大 → 各自變慢(總功率守恆);耗能 / 發熱不隨 actuator 數或分配變(仍 ∝
applied_energy、只由allocation_pct決定)。 - 鏈條 payload:基座轉速同上式;尾段
Chain_Segment走物理 joint 擺動、不吃此式。 - 單轉子(N=1)= 滿速
P × K_WEAPON_ROTOR_SPEED(連帶釘死舊單轉子揮速)。
runtime 不使用不可讀回驗證的 Rapier joint motor。每幀以 actuator 軸上的相對角速度/有界目標角求 Δω,再以兩端 body 的 world inverse inertia 求 torque impulse;payload 與 primary chassis 接收等量反向角衝量。max_angle_deg = 360 追目標角速度;小於 360° 時,以 snapshot 內 phase 配合 sin/linear 求 [-max/2,+max/2] 目標角。未 Hold 或斷電不再注入 torque,但既有慣性與 joint 碰撞仍照物理續行。鏈條只直接驅動第一節,後續節點由 authored Revolute/Spherical joint 傳力;Rapier 0.19.3 會把 JointData.spherical canonicalize 為等價的 Generic joint 表示。
被動武器加持(passive 專屬;三因子、僅及武器零件自身):
massReductionPctX100 = allocation_pct × passive_weight_split_pct × K_PASSIVE_EFFECT_MAX_PCT / 100
resistPctX100 = allocation_pct × (100 − passive_weight_split_pct) × K_PASSIVE_EFFECT_MAX_PCT / 100
// bigint 整除截斷;X100 整數(K=30 時值域 0–3000 = 0–30.00%)
effective_mass_g(武器) = mass_g × (10000 − massReductionPctX100) / 10000
fatigue 累積(武器) ×= (10000 − resistPctX100) / 10000
熱流入(武器) ×= (10000 − resistPctX100) / 10000 // thermal_limit 本身不變(升溫變慢、閾值語意不動)
- 三因子:
allocation_pct(chip 上鏈鎖死 = 總量)×passive_weight_split_pct(組裝層分配 0–100、減重 vs 抗性,車輛組裝.md §3.5)×K_PASSIVE_EFFECT_MAX_PCT(上限常數 30、初估)。 - 靜態係數:組裝 / 車輛實例化時套用一次,非 runtime 變動(不踩「runtime 改 mass」紅線);有效質量進入整車總質量 / 質量比 / 重心 / 慣量計算(GLB extras 的
mass_g原始值不動);全 peer 同式 =deterministic。 - 僅及 passive 武器零件自身:chip / motor / battery 熱模型與其他零件耐久零改動(chip 閾值殺手鐧不稀釋);抗性只改自身承受、不改對外輸出。
- 二階 tradeoff(物理自然湧現):壓減重 = 更快但撞角動量變小;壓抗性 = 耐打但重。
晶片與電池的技能廢熱以實際電池成本分帳:
chip_heat_j = battery_cost_j × K_CHIP_SKILL_WASTE_HEAT
battery_heat_j = battery_cost_j × K_BATTERY_SKILL_WASTE_HEAT
殺手鐧判定(單一閾值)不在積分前以 J 直接比較 °C;本次 chip 廢熱先與所有來源一同進 §6.2,再用積分結果判定:
if chip.thermalLimitC !== null and chip.T_next > chip.thermalLimitC:
chip.broken = true // 所有技能立即失效但能基本駕駛
// 該次觸發仍以「正常強度」執行(無 ×bonus 加成)
effect_energy_j、battery_cost_j、chip heat 與 battery heat 是四個不同帳目;不得再以效果能量直接
扣 mAh 或直接加溫。
4. 武器反作用力¶
武器動作(general_push / general_actuated / launch)對 chassis 質心產生反向衝量:
reaction_impulse = -action_direction × applied_energy × K_REACTION
chassis.apply_impulse_at_center_of_mass(reaction_impulse)
action_direction:武器 Axis empty +Z 軸(loadout knob 後)K_REACTION初估 0.002 N·s/J;輸入為實際獲准的effect_energy_j(依真實接觸摩擦重校,見calibration.md §18),待 playtest- action 側(對目標的前推)遞送:上式為 chassis recoil 側。對目標的前推(沿 +
action_direction)——general_actuated由轉子 / 鏈條 mesh、launch由子彈 body 經 Rapier contact 自然遞送(無需額外施力);唯general_push無自運動 mesh → 引擎對接觸中的目標直接施加等大反向衝量+action_direction × applied_energy × K_REACTION(與 chassis recoil 成 action-reaction 對,見 零件與共用介面.md §3.7) - 多 actuator(零件與共用介面.md §3.7):共用同一份
applied_energy→ 淨反作用力仍 = 上式 weapon-level(沿Axis、各 actuator 的 share 加總即全量、不需逐 actuator 拆向;同既有單轉子的線性簡化、不模擬轉向 recoil 抵銷);鏈條尾段甩動的反作用走 joint 自然處理
launch 的每枚 projectile 在 world 建立時即依 authored child pose、convex 形狀、材質與質量配置為 dynamic body,先以 fixed joint 持彈。每次開火只按 child index 移除下一枚 hold joint,沿 mounted Axis +Z 施 impulse 並對 chassis 施等量 recoil;不得在開火時建立替代球體或增加總質量。已發射 projectile 永久留場,且不再參與該車的 teleport/freeze/scale/deploy 查詢。
magnet 不需此函數(Rapier contact pair 物理自然處理)。
5. 磁力(真實物理:1/r² + N 極方向)¶
5.1 統一磁源 schema¶
設計原則(enum 三選一 + 身分/強度分離):
- 一個材質的
magnetism_role三選一:source(主動磁源)/passive(被動鐵磁)/none(無磁性);型別系統強制互斥(見 材質表.md §8) - 主動磁源的強度由建模物件 Root Extras
magnet_source_strength_n決定(不在材質層) - 物件「成為磁鐵」條件:含
magnetism_role: source材質 sub-mesh 且 Root Extrasstrength_n > 0 - 場地磁源於 Stage 2 pre-bake 為 Root Extras
auto_magnet_sources(清單[{ node, pos, strength_n, n_pole }],每個source材質 mesh node 一項、strength_n取該 node 自身 extras,見 場地.md §8.6);runtime 直接讀、免掃 mesh
| 來源 | strength_n | n_pole_direction |
|---|---|---|
| 武器 magnet | 動態 available_output_w × allocation_pct / 100 × K_MAGNET_FORCE(即 §3 的功率預算 P × K;持續場強、去 dt——場強非能量;不依賴材質) |
Axis empty +Z 軸 |
| 場地物件 / 部件磁源 | 靜態 Root Extras magnet_source_strength_n(0–10 N)+ sub-mesh 材質 magnetism_role: source |
sub-mesh 面積加權平均法向(pre-bake 入 extras;退化〔近球對稱、平均趨零〕→ fallback node +Z,材質表.md §8.3) |
5.2 磁源 → 鐵磁物體(無方向)¶
delta = target_submesh.center - source.position
direction = -delta.normalize() // 朝磁源
force_mag = source.strength_n
× target_submesh.material.magnetic_susceptibility
× K_MAGNET_PERMEABILITY_M2 / (r²)
force = direction × force_mag
- 純吸引(無 polarity 開關)
- 1/r² 真實衰減(無自訂
radius上限);r單位 = m(尺度由K_MAGNET_PERMEABILITY_M2吸收) r < 0.01 m截斷:不施力(視為已接觸、防 1/r² 近貼爆量——接觸交由碰撞解算)- 施力點 = 剛體質心:力以整體 impulse 施於 body(
applyImpulseWorld、不產生磁力扭矩);sub-mesh 僅決定受力大小與方向(delta取 sub-mesh 中心) - Newton 3rd:
force施於 target body 的同時−force施於 source body——場力是引擎手動施加、不會自動產生反作用(§4 的「Rapier 自然處理」僅指接觸碰撞);場地 fixed / kinematic 磁源施了也不動、天然無影響;武器磁鐵吸目標時自身同受反向拉力(重車吸輕車 vs 輕車吸重車結果不同——戰術差異) - 多材質零件:每 sub-mesh 各自計算(鋼骨被吸 / 橡膠不受力 → 零件被拉得不對稱)
- vehicle target 依
vehicleId → partIndex → canonical collider key排序;Track Entity target 依entityIndex → canonical collider key排序。每個 passive sub-mesh 以其實際 collider 世界中心計算方向,但聚合後的 impulse 仍只施於兩側剛體 COM,不產生 torque;fixed/kinematic Track Entity 本身不移動,動態磁源仍承受反作用力 - 公式僅對
target_submesh.material.magnetism_role === 'passive'的 sub-mesh 套用;其他 role 對應magnetic_susceptibility: null,直接 force = 0(不進入公式,避免 null × number = NaN)
5.3 磁源 ↔ 磁源(兩 N 極已知)¶
theta = a.n_pole_direction · b.n_pole_direction // [-1, 1]
coupling = -theta // N 對 N(互指、θ<0)→ coupling>0=沿 +delta 遠離=斥;同指向(N-S 串列、θ>0)→ coupling<0=吸
force_mag = a.strength_n × b.strength_n × coupling
× K_MAGNET_PERMEABILITY_M2 / (r²)
delta = b.position - a.position
force = delta.normalize() × force_mag // 施於 b;−force 施於 a(Newton 3rd,同 §5.2)
- 同極相斥、異極相吸(真實物理);兩源各受
±force(10mm 截斷 / 施力點質心同 §5.2) - 玩家可主動讓 N 對 N 反制場地磁吸
owner比對:不對自身生效
6. 熱模型(per-part 單一能量域)¶
6.1 Manifest 烘焙量¶
C_part = Σ(mass_kg_i × specific_heat_i) // J/°C
H_air = Σ(exposed_area_m2_i × K_THERMAL_AMBIENT_W_PER_M2_C × conductivity_factor_i) // W/°C
thermalLimitC = min(all non-null sub-mesh thermal_limit)
conductivity_factor_i = 0.25 + 0.75 × min(k_i, THERMAL_CONDUCTIVITY_FACTOR_CAP_W_PER_M_C) / THERMAL_CONDUCTIVITY_FACTOR_CAP_W_PER_M_C。同一 part 內,三角面所有頂點與
中心都嚴格位於另一水密 region 內才從 exposed_area 排除;碰觸邊界或部分相交不猜裁切面積。
跨 part 裝配遮蔽在單資產 manifest 無法得知,本版不扣除。Canonical current PhysicsManifest 直接保存
heatCapacityJPerC、ambientConductanceWPerC、thermalLimitC;runtime 不讀 auto_*、不重算。
6.2 backward Euler 單次積分¶
每幀所有來源先進 per-part ledger:瞬時能量 E(J)、持續功率 Q(W)、空氣熱導 H_air
與接觸固定熱庫 (H_j, T_surface_j)。最後每個 part 只解算一次:
T_next = (C×T + E + dt×(Q + H_air×T_air + Σ(H_j×T_surface_j)))
/ (C + dt×(H_air + ΣH_j))
T_next = clamp(T_next, MIN_TEMPERATURE_C, MAX_TEMPERATURE_C)
T_air 與固定地表熱庫溫度都取場地 weather.temperature。此隱式式在任意合法 dt/熱導下
保持有限、單調且不越過固定熱庫;除初始化、restore 與本式外,禁止直接寫 temperature +=。
過熱破壞(無 graceful degradation):
if part.thermalLimitC !== null and T_next > part.thermalLimitC:
part.broken = true
跳過條件:建模屬性不可破壞 / part.thermalLimitC === null(manifest pre-bake 結果:所有 sub-mesh 皆 null)→ 跳過過熱檢查(見 材質表.md §10)。
6.3 各 part 類別的 heat_in 源¶
| Part | ledger heat source |
|---|---|
| chassis / body / weapon | 無自身發熱;仍接收 ambient、burn/freeze 與外部接觸來源 |
| tire / roller | 同上,另接收 solid surface 導熱與 abs(tangential_impulse × tangential_slip_speed) × K_THERMAL_SLIP |
| motor | K_MOTOR_HEAT × actual_power_w(W) |
| battery | K_BATTERY_PASSIVE × actual_supply_power_w(W)+battery_cost_j × K_BATTERY_SKILL_WASTE_HEAT(J) |
| chip(晶片) | battery_cost_j × K_CHIP_SKILL_WASTE_HEAT(J) |
6.4 流體 deploy 對溫度影響¶
burn/freeze 的 authored temperature_delta_per_sec 先乘該 part 的 C 轉為 W 再進 ledger。
burn 正熱量受 passive weapon thermal resist 折抵;freeze 負熱量不折抵。freeze 仍是純冷卻,
不引入低溫降效。chip 本次 skill 若把投影溫度推過閾值,該次仍完整執行,統一積分後才 broken。
6.5 tire/roller 與 solid surface 接觸熱¶
effusivity_factor = quantized_sqrt(thermal_conductivity × density_kg_m3 × specific_heat)
pair_factor = 2 × factor_part × factor_surface / (factor_part + factor_surface)
H_contact = K_THERMAL_CONTACT × pair_factor × baked_contact_area_m2 × normal_impulse_ns
slip_energy_j = K_THERMAL_SLIP × abs(tangential_impulse_ns × tangential_slip_speed_mps)
只使用實際 contact manifold;surface 是不耗竭固定熱庫。fluid sensor 不走此式。
7. 衝撞 Fatigue(耐受度因子族)¶
對稱套用 attacker / target(Newton 3rd law),每邊由碰撞事件的 collider handle 取得自己實際
接觸 sub-mesh 材質;車輛與 destructible Track Entity 都不得退回 materials[0]:
vA_point = vA_com + ωA × (contact_point - comA)
vB_point = vB_com + ωB × (contact_point - comB)
v_close = max(0, dot(vA_point - vB_point, normal_A_to_B))
m_effective_normal = 1 / (
n·(invMassA + invMassB)·n
+ (rA×n)·worldInvInertiaA·(rA×n)
+ (rB×n)·worldInvInertiaB·(rB×n)
)
impact_energy_J = 0.5 × m_effective_normal × v_close²
local_normal = quantize(inverse(collider_world_rotation) × world_contact_normal)
contact_area_m² = max(
IMPACT_CONTACT_AREA_MIN_M2,
abs(nx) × area(sign(nx) ? right : left)
+ abs(ny) × area(sign(ny) ? top : bottom)
+ abs(nz) × area(sign(nz) ? back : front)
)
stress_MPa = impact_energy_J / (contact_area_m² × K_IMPACT_DEPTH_M) / 1_000_000
// 單位鏈:J / (m² × m) = Pa,再除 1,000,000 得 MPa——與 yield_strength / ultimate_strength(MPa,材質表)直接可比
// K_IMPACT_DEPTH_M = 等效變形深度(0.001m 初估、待 playtest,calibration.md §18)
if stress > yield_strength:
entity.fatigue += stress / ultimate_strength
if stress > ultimate_strength × K_STRESS_BURST_FACTOR: // 1.5,calibration.md §18
entity.broken = true // 一擊重傷
elif entity.fatigue ≥ 1.0:
entity.broken = true // 累積疲勞破壞
if entity.broken:
entity.fatigue = min(entity.fatigue, 1.0) // broken 後凍結
以上撞擊運動量使用 solver 前依 body handle 保存的 COM pose、線速度、角速度、effective inverse mass
與 world inverse inertia;固定體 inverse 值為 0。接觸點、速度與有效質量中間量以
IMPACT_KINEMATICS_QUANTIZATION_PER_UNIT 量化。collision-start 在 solver 後送達而沒有可用
manifold 時,以 solver 前 collider 位姿及 IMPACT_CONTACT_QUERY_MARGIN_FRAMES 重建接觸;若
Rapier manifold 法線與 solver 前相對接觸點速度的 closing 分量小於
IMPACT_NORMAL_MIN_CLOSING_MPS,以該相對速度方向作確定性退化法線。兩者皆無可信結果才
fail closed;不得回退 collider 中心、質心速度或 owner 整車質量近似。
持續 solid 接觸另由 solver ledger 計算剪切:
if tangent_slip_speed ≥ SHEAR_DAMAGE_MIN_SLIP_MPS:
shear_energy_J = K_SHEAR_DAMAGE_TRANSFER
× abs(tangent_impulse_Ns)
× tangent_slip_speed_mps
法向撞擊與剪切能量交給同一接觸面積/材質 stress 路徑。tire/roller 對固定場地已有專用
rolling/slip wear ledger,不再套一般剪切 fatigue。武器不按名稱或類型加成:鈍器、尖端、刀刃、
揮刀與旋轉鋸的差異只來自幾何面積、材質、質量/慣量、ω×r 與真實 solver 接觸。
六向面積來自同一個實際接觸 collider proxy 的 current PhysicsManifest 烘焙值。contact pair 先依
canonical collider key 固定 A/B;A 使用朝向 B 的 manifold normal,B 使用反向 normal,各自轉回
collider local。法線以 IMPACT_NORMAL_QUANTIZATION_PER_UNIT 量化,固定 X→Y→Z 加總;不採最大軸
硬切、不做 L1 再正規化,也不得退回整顆零件或點雲 AABB。
跳過條件與可破壞性決策:見 材質表.md §10(建模屬性決定可破壞性,材質僅提供強度數值)。
8. Acid 腐蝕¶
// K_ACID 見 [calibration.md §18](程式參數/calibration.md)(與 abs ultimate=50 配對約 0.05 fatigue/sec)
if not is_fluid and ultimate > 0:
part.fatigue += K_ACID / ultimate × dt
if part.fatigue ≥ 1.0: part.broken = true
材質敏感:abs 衰得快、titanium 慢。每個 distinct zone/part 每 fixed step 最多套用一次;若同一
zone 同時交疊該 part 多個 collider,從實際交疊者選 ultimate_strength 最低的有效固體材質,並以
canonical collider key 解同值,避免 compound collider 重複計傷又保留弱表面語意。
9. 輪胎摩擦磨耗(併入 fatigue)¶
// 每個有效 tire collider region × solid surface contact,依 canonical collider key 累加
rolling_energy_j = abs(rolling_impulse_ns × rolling_speed_mps)
slip_energy_j = abs(tangential_impulse_ns × tangential_slip_speed_mps)
wear_energy_j = rolling_energy_j + K_TIRE_SLIP_WEAR_MULTIPLIER × slip_energy_j
wear_capacity_j = K_TIRE_WEAR_CAPACITY × material_region_volume_m3
× ultimate_strength_mpa × 1,000,000
thermal_ratio = clamp((tire.temperature - T_air) / (tire.thermalLimitC - T_air), 0, 1)
thermal_wear = 1 + K_TIRE_THERMAL_WEAR_MAX × thermal_ratio × thermal_ratio
tire.fatigue += thermal_wear × wear_energy_j / wear_capacity_j
if tire.fatigue ≥ 1.0: tire.broken = true
只有實際 solid contact 且 rolling/slip speed 至少 MIN_TIRE_WEAR_SPEED_MPS 才記帳;無接觸、
靜止或 sensor/fluid 接觸為 0。故極速巡航、滑行與下坡仍有 rolling wear,空轉/側滑/鎖死拖行
另有放大的 slip wear。wear_capacity_j 逐實際 collider region 烘焙,內部輪轂不得替胎面增加容量;
非有限/非正體積或 ultimate strength 必須 fail closed。無有效熱限時 thermal_ratio=0;
T_air >= tire.thermalLimitC 時取 1。tire.temperature > tire.thermalLimitC 仍直接 broken;broken 後停止磨耗,
respawn 不清 fatigue,新回合才重設。損壞後 Grip 行為見零件與場景.md §tire。
10. 場地物理¶
10.1 場地 Entity destructible¶
可破壞性決策見 材質表.md §10。場地 entity 標 destructible: true(需 physics: "default")時,沿用 §7 衝撞 fatigue 算式:
if entity.fatigue ≥ 1.0 or stress > ultimate_strength × K_STRESS_BURST_FACTOR: // 1.5,calibration.md §18
entity.broken = true
entity.breakFrame = currentFrame
disable(entity.intact_body, entity.intact_colliders, entity.intact_visual)
// 同幀停止 move/conveyor/entity-local magnets;不把 intact body 改成 Dynamic,避免雙重質量
// 不建立/啟用 fragment body、collider、sensor、damage 或路障
visualFragments = reconstruct(entityIndex, breakFrame, descriptorVersion, currentFrame)
world 只預配置 intact body/collider。fatigue、broken、breakFrame 進 current SavedState、restore validation 與 checksum;逐片 active/spawn/expiry/fade/pose/velocity 不進共識。currentFrame - breakFrame 超過 VISUAL_FRAGMENT_LIFETIME_MS 對應幀數時不重建,淡出使用共用 presentation 參數。
10.2 天氣 patch 混合計算(rain / snow 動態地表)¶
雨/雪 patch 影響車輛與地表互動,採 混合計算(multiplier 而非 override):
patch 內 friction = 原材質 friction × patch_friction_modifier
patch 內 rolling_resistance = 原材質 rolling_resistance × patch_rolling_modifier
預設係數(依 weather.type 自動帶入,創作者可調,schema 見 場地.md §8.3):
| 參數 | rain 預設 | snow 預設 | 範圍 |
|---|---|---|---|
patch_friction_modifier |
0.65 | 0.5 | 0.3–0.9 |
patch_rolling_modifier |
1.5 | 2.0 | 1.0–2.5(>1 = 拖感變重) |
Patch deterministic spawn:
seed = SHA-256(matchId ‖ NUL ‖ roundIndex ‖ NUL ‖ track_manifest_digest) 的前 32 bits(LE)
counter = (spawn_ordinal, born_frame, attempt_index),每次固定最多 8 次候選
位置:重力平面的 typed auto_exposure grid 內均勻取樣,採沿重力方向第一個靜態 solid 表面
數量:≤ WEATHER_PATCH_COUNT_MAX(50,protocol.md §3)/ 場
生命週期:spawn_rate 使用整數 accumulator;lifetime 預烘成整數 frame;rate > 0 時 frame 0 先生成
遮蔽:橋面/屋頂可生成;其下方與隧道由第一表面 exposure 遮蔽,不生成
設計理由(為什麼 multiplier 而非 override):物理直覺(雨水落柏油 vs 泥土 vs 沙的滑度應該不同)+ 湧現玩法(dirt + rain 自動產出「比 mud 還滑」的緊張感)。
Patch 只修改 tire/roller 與靜態 solid surface 的實際接觸:先乘 surface friction/rolling resistance,再進既定 combine/牽引/側滑/滾阻。涵蓋以切平面圓、法向距離與法向相似度判定;同類 patch 重疊只取穩定 ID 最小者一次,不連乘。基礎材質 restitution 仍生效,但 weather 不再另改 restitution。
patch 視覺 + 遮蔽一致:physics engine 維護唯一 active descriptors(位置、法向、半徑、出生/到期 frame、modifier);participant、spectator 與編輯器預覽只消費 descriptors,不另跑 RNG。scheduler accumulator、spawn ordinal 與 active descriptors 全部進 current SavedState/checksum/restore。schema 見 場地.md §8.3 / §8.6。
10.3 風力套用¶
風是獨立參數(不綁 weather.type)。body 以六個帶正負號的局部軸面積與各自壓力中心計算相對氣流;無風時移動車也有阻力:
v_point = v_body + omega × r_center_of_pressure
v_air = v_wind - v_point
F_axis = K_AERO_DRAG × drag_area_axis × v_air_axis × |v_air|
F_lift = K_AERO_LIFT × lift_factor × |F_drag_horizontal| × normalized_gravity_direction
|F_drag + F_lift| ≤ mass × |gravity| × K_AERO_MAX_WEIGHT_MULTIPLIER
其中:
weather.wind_speed_mps與量化風向組成世界座標v_wind;上限見 protocol.md §3- 每個局部軸只在
v_air_axis朝該軸正向時使用對應+axis/-axis的drag_area_m2與center_of_pressure_m - 正
lift_factor沿重力形成下壓,負值反向形成升力;lift 施於各 drag force 量值加權的壓力中心 K_AERO_DRAG = 0.6、K_AERO_LIFT = 1、K_AERO_MAX_WEIGHT_MULTIPLIER = 2是 synthetic 初值,正式資產 playtest 前只承諾公式與界限
10.4 重力與物理引擎¶
每場地有自己的重力設定(schema 見 場地.md §8.4):
gravity_vector = normalize(physics.gravity_direction) × physics.gravity_strength_m_s2
rapier_world.set_gravity(gravity_vector)
支援低重力(月球感)/ 高重力 / 反重力 / 橫向重力 / 斜向重力等創意場地。
耦合:
- 「掉出場地」三層 fallback 沿重力方向投影 AABB + 5m buffer(反方向不檢核)
- 武器 launch 投射物彈道受場地重力影響(高重力場地拋射物落得快)
- 雨/雪 patch 沿重力反向「貼地」生成
11. 車輛回合初始狀態(每回合載入新車)¶
每回合載入該回合的車(carRotation[i])+ 場地 = 全新世界;車輛以下列初始狀態開始。回合間不共享任何 runtime 狀態(fatigue / heat / 電量 / 彈藥 / 已射出 bullet)——這是「換上新車 + 新場地世界」的自然結果、非 reset 流程;每 peer 各自從同一份 GLB 載入 → 初始狀態天然一致(determinism)。
// 新車載入時的回合初始狀態
for part in vehicle.parts:
part.fatigue = 0
part.temperature = T_air // 當前場地溫度(= weather.temperature)
part.broken = false
vehicle.battery.remaining_energy_q = battery.initial_energy_q // 滿電;1 quantum = 1/60 mJ
vehicle.weapon.launch_ammo = full // 滿彈(= auto_launch_ammo 全部,建模參數/零件與共用介面.md §3.7.3)
回合內:狀態累積(fatigue↑ / heat / 電量耗 / 彈藥 Hold 連發);彈藥有限、打完即空(一回合就這麼多、用完沒了)。回合數由房間設定(可變 N)。
12. 經濟:月度派發係數¶
〔ECON-R-030〕 月度派發係數只依 softCap 與 monthMinted 的整數公式計算:
factorX100 = softCap × 100 / (softCap + monthMinted)
| monthMinted | factorX100 | 拿到比例 |
|---|---|---|
| 0 | 100 | 100% |
| softCap | 50 | 50% |
| 5×softCap | 16 | 16% |
| > 99×softCap | 0 | 整數量化 floor 到 0 → 當月鑄幣停止(等效月硬頂),防極端刷量兜底 |
13. 經濟:比賽獎金¶
〔ECON-R-031〕 比賽獎金依總名次、完賽人數、月度係數與治理參數決定:
function computeMatchPrize(rank, finisherCount, factorX100, config): bigint {
if (finisherCount < min_player_count) return 0n; // finisherCount = 完賽人數
const mult = rank_multipliers_pct[min(rank - 1, len - 1)];
return base × finisherCount × mult × factorX100 / (100n × 100n);
}
〔ECON-R-032〕 rank = 總名次(N 回合積分加總後的最終名次,見 §20.1);獎金 per-match 發一次(非每回合)。
整除截斷尾數抹零消失(不發給任何人、不累加 monthMinted、不存滯留池)— 必要性:跨 peer 共識一致。
finisherCount = 完賽人數(完成整場比賽 = N 回合、未斷線 / 未棄賽者;斷線 / 棄賽者不計、不發獎金);finisherCount < 3 → 整場 matchPrizes 與 royalties 全空(經濟 void,權威見 經濟系統.md §6.2)。
範例(8 人賽,月初係數 100,依總名次):
| 名次 | 獎金(minor units) |
|---|---|
| 1 | 400 (4.00 幣) |
| 2 | 200 (2.00) |
| 3 | 120 (1.20) |
| 4–8 | 56 (0.56) each |
高峰月(係數 50)所有獎金減半。
14. 經濟:創作回饋金¶
〔ECON-R-033〕 單一 UGC 的回饋金由評分、利基加成、月度係數與基礎額共同決定:
function computeRoyaltyForUgc(ratingX100, factorX100, config): bigint {
const ratingMultX10000 = ratingX100 × 20; // rating / 5 的 X10000 量化(ratingX100 已含 ×100、再 ×20)
const nicheMultX100 = nicheMultiplierX100(ratingX100); // 線性 clamp(見經濟系統 §7.1)
return base × ratingMultX10000 × nicheMultX100 × factorX100 / (100n × 100n × 100n × 100n);
}
維度驗算:base 50、rating 4.5(ratingMultX10000 = 9000)、niche ×2.0(200)、係數 100 → 50×9000×200×100 / 10⁸ = 90 minor(0.9 幣)。
Niche 加成(線性連續、整數量化):nicheMultX100 = clamp(ratingX100 - 250, 50, 200),rating ≤3.0 → ×0.5、4.0 → ×1.5、≥4.5 → ×2.0(權威見 經濟系統.md §7.1)。
15. 經濟:三層分潤¶
每筆 royalty 依 fork 血緣拆 70/20/10:
current_share = total × 70 / 100 // 當前創作者
parent_share = total × 20 / 100 // 直接 parent
grandparent_share = total × 10 / 100 // 祖先依深度衰減
// 缺層份額(無 parent / grandparent)與整除殘留一律歸當前創作者——原創(無血緣)作品實拿 100%(無公共池機制)
詳見 經濟系統.md § 三層分潤 + 版權.md §Fork 衍生樹。
16. 信譽分數¶
〔MOD-R-001〕
reputation = clamp(500 + Σ(加分事件) - Σ(扣分事件), 0, 1000)
純函數,由事件鏈推導。事件加減值見 信譽系統.md。
17. 信譽加權投票¶
weight = log10(reputation + 10)
〔MOD-R-010〕 整數評估(共識計算禁用浮點 log10):仲裁 tally 是全網重算驗證的共識計算,浮點 log10 跨硬體不一致(同 §19 隱式評分的理由),runtime 一律用預算整數表:
weightX100(rep) = ARBITRATION_WEIGHT_X100_TABLE[clamp(rep, 0, 1000)]
// 表 = 離線一次性生成 round(100 × log10(rep + 10))、隨 client 出貨(bit-exact);runtime 不得呼叫浮點 log10
// 通過判定全整數:Σ(pass weightX100) × 100 > Σ(有效票 weightX100) × ARBITRATION_PASS_THRESHOLD_PCT
// current = 60(= 加權通過比例 > 60%,無除法捨入;權威見 [protocol.md §5](程式參數/protocol.md))
範例:
| 信譽 | weight(weightX100) |
|---|---|
| 200(仲裁門檻) | 2.32(232) |
| 500 | 2.71(271) |
| 800 | 2.91(291) |
| 1000 | 3.00(300) |
公式全域最大差異 ~3 倍(避免大戶獨裁);仲裁面板內(皆 ≥ 200)差距 ≤ 1.29×、近似人頭。
18. UGC 評分權重(依信譽)¶
〔ECON-R-034〕 UGC 評分投票權重依投票者信譽分成 0.5、1.0、1.5 三級:
ratingWeightX100 = 50 if reputation < 200 (0.5)
= 150 if reputation > 800 (1.5)
= 100 otherwise (1.0)
19. UGC 評分(Bayesian + 隱式 fallback)¶
〔ECON-R-035〕 UGC 評分依票數選用隱式 fallback、Bayesian 拉中性或明確票均值:
if voteCount == 0:
ratingX100 = implicitRatingX100(ugcUsageCount) // 純使用量推估
elif voteCount < BAYESIAN_PRIOR_SAMPLES:
ratingX100 = (n × explicitMean + k × NEUTRAL) / (n + k) // Bayesian 拉中性
else:
ratingX100 = explicitMean
RATING_NEUTRAL_X100 與 BAYESIAN_PRIOR_SAMPLES 的值只由
protocol.md §5 定義;本節只定義算式。
〔ECON-R-036〕 隱式 fallback(整數查表):浮點 log10 跨硬體不一致會炸毀 consensus derive,故隱式評分採整數查表:
function implicitRatingX100(ugcUsageCount: number): number {
if (ugcUsageCount === 0) return 300; // 3.00
if (ugcUsageCount < 10) return 360; // 3.60
if (ugcUsageCount < 100) return 420; // 4.20
if (ugcUsageCount < 1000) return 480; // 4.80
return 480; // 封頂 4.80
}
| ugcUsageCount | ratingX100 |
|---|---|
| 0 | 300 (3.00) |
| 1-9 | 360 (3.60) |
| 10-99 | 420 (4.20) |
| 100-999 | 480 (4.80) |
| 1000+ | 480 (4.80, 封頂) |
封頂 4.80 而非 5.00:完全無評分但被多人用 = 證明有功能性但未必精緻,留給顯式評分達 5.00 的精品差異化空間。UI 顯示時加 (隱式) 標籤(信譽系統.md §3.1)。實作見 程式架構/ugc-rating.md §3.3。
20. TrueSkill(配對評分;整數定點)¶
TrueSkill 為 Microsoft 商標;本節是自製整數定點實作、僅指示性沿用演算法名稱與參數慣例(歸屬聲明見 版權.md §11.1)。
〔ECON-R-052〕 8 人 FFA 用 TrueSkill 成對近似多人更新(μ, σ 演化)。rating 屬共識 derive(MatchDerivedState、全網重算需 bit-exact)→ 全程整數定點:浮點與超越函數(Gaussian erf)禁入(同 §17 仲裁 log10 查表化先例、資料系統.md §17 不變式)。
定點表示:μ、σ 一律 X1000 整數(初始 μ=TRUESKILL_MU_INITIAL_X1000(25000)、σ=TRUESKILL_SIGMA_INITIAL_X1000(8333));β=TRUESKILL_BETA_X1000(4166)、τ=TRUESKILL_TAU_X10000(833,尺度 X10000、使用處明確換算)。所有除法 = 整數截斷、運算順序照公式書寫序(跨 peer 一致)。
每場後成對近似更新(rankings=§20.1 總名次、per-match 一次;FFA 不平手 =draw margin 0、無平手常數):
對每有序對 (i, j),i ≠ j,勝負由總名次決定(i 勝 j 時):
cSq = 2×β² + σi² + σj² // X1000² 域
c = isqrt(cSq) // 整數開根(floor)——無浮點根
t = (μi − μj) × 1000 / c // X1000、截斷
(v, w) = (TRUESKILL_V_TABLE_X1000, TRUESKILL_W_TABLE_X1000)(t) // 查表:clamp ±TRUESKILL_VW_T_CLAMP_X1000(6000)、步長 TRUESKILL_VW_T_STEP_X1000(10)(=0.01)、不插值
Δμi += σi² / c × v / 1000;Δμj −= σj² / c × v / 1000
wi 累加 w(供 σ 縮減);wj 同
每人淨值:μ' = μ + ΣΔμ / (P−1)
σ 縮減(每人一次、用平均 w̄ = Σw / (P−1);cSq = 該玩家 P−1 個配對 cSq 的整數平均(截斷)——聚合方式實作即權威):
σ'² = σ² − σ² × w̄ × σ² / (cSq × 1000) + TAU_X10000² / 100 // + τ² 動態注入(X1000² 域);中間積超 2^53 → BigInt 精確計算
σ' = isqrt(σ'²) // 自然正下界(縮減項恆 < σ²:w̄ < 1000 且 σ² < cSq)+ τ² 注入;無普適下限
σ 下限 TRUESKILL_SIGMA_MIN_X1000(6000)僅適用頻繁斷線者(disconnectCount ≥ FREQUENT_DISCONNECT_THRESHOLD 時 adjustRatingForFrequentDisconnects 托底,程式架構/matchmaking.md §1)——普適套用會使托底永為 no-op、且成熟玩家 σ 無法低於新人初值。
TRUESKILL_V_TABLE_X1000/TRUESKILL_W_TABLE_X1000= 離線生成整數查表(v(t)=φ(t)/Φ(t)、w(t)=v(t)(v(t)+t) 的 X1000 值;各 1201 筆、隨 client 出貨——同仲裁權重表模式)。粒度 0.01 的精度損失對配對評級可忽略——共識要求 =bit-exact、非高精度。- 新人 σ 大(變動快);成熟玩家 σ 小(穩定);頻繁斷線者 σ 托底 6000 不收斂(上)。
配對窗口尺度基準:displayRating = (μ − 3σ)(X1000 整數;權威 賽內機制.md §1.2);窗口比較於 displayRating ÷ 1000 的整數分域(窗口初始 ±5、每 10 秒 +5、上限 ±30——窗口常數維持整數分尺度)。
20.1 多回合積分與總名次¶
一場比賽(match)含 MATCH_ROUND_COUNT 個回合(round);每回合各自一軌、各自名次,積分加總定總名次。
回合積分(線性、整數):
roundPoints(k, P) = P − k + 1 // k = 該回合名次 1..P;P = 開賽人數(全程恆定)
totalPoints(peer) = Σ_round roundPoints(k_round, P)
- 第 1 名得
P、最後一名得1;回合名次先分①合法完賽、②未完賽存活、③未完賽失能、④未完賽退出。合法完賽依finishedAtFrame升冪;其餘各區依lapsDone降冪、routeProgressUm降冪、PeerId 字典序。routeProgressUm是 checkpoint 依序約束下、微米整數量化且單調不退的 route arc-length,抄近路不得越過下一個未點亮 checkpoint 的弧長。 - battery/motor broken 關閉輸入、驅動、技能與主動武器,但保留 chassis 物理及 checkpoint/終點判定;慣性、環境或撞擊造成的合法 swept crossing 仍可完賽。場上無未完賽存活車後才啟動單一回合級 120 幀終局窗;所有未完賽失能車線速度 < 0.05 m/s 且角速度 < 0.1 rad/s 連續 15 幀可提早結束。chassis
physicsRetired不參與滑行窗。 - 回合內失能/退役/DNF 者仍得低分並繼續下一回合(換上全新車);已合法完賽者之後失能或退出不改名次區塊。
直接致毀破壞統計:權威事件是 target vehicle part 在固定幀末首次由 broken=false 轉為
broken=true。同一 (targetVehicleId, partIndex, frame) 的有效損傷先依 source 彙整成
damageContributionQ = round(normalizedFatigueContribution × 10^9);最大者取得一件,同值依
canonical source key、event key 的 code-unit 順序。敵方車碰撞、已發射 projectile 與其 fluid zone
保留 source peer;自損、場地/環境、自然過熱與無 owner 來源可成為最大來源但不給任何玩家件數。
chassis 自身實際 broken 可計一件,chassis retirement 停用的其他 intact part 不計;不追蹤助攻或
間接推牆因果。每回合完整 roster 的非負整數結果進 current SavedState、checksum 與 required
RoundResult.destructionCounts,真正沒有破壞才是 0。
P= 開賽人數恆定;中途斷線者後續回合 DNF 佔末位,不縮減P(各回合積分基準一致)。
總名次(match 結束、totalPoints 由高到低)tiebreak:
- 總完成時間
Σ_round finishTimes(DNF 回合計該回合durationLimitSec × 1000ms)少 → 多 - 仍同 → PeerId lexicographic(決定性)
純函數(consensus-critical:簽章者各自重算驗 MatchResultEvent.ranking、防主 peer 偽造,見 程式架構/ledger-settlement.md §5):
function deriveTotalRanking(rounds: RoundResult[]): PeerId[] {
const P = rounds[0].ranking.length; // 開賽人數(各回合 ranking 含全員、DNF 佔末位)
const points = (p: PeerId) =>
rounds.reduce((s, r) => s + (P - r.ranking.indexOf(p)), 0); // Σ (P − k + 1),k = indexOf+1
const totalTime = (p: PeerId) =>
rounds.reduce((s, r) => s + (r.finishTimes.get(p) ?? 0), 0);
return [...rounds[0].ranking].sort(
(a, b) =>
points(b) - points(a) || // 積分高 → 低
totalTime(a) - totalTime(b) || // 總完成時間少 → 多
(a < b ? -1 : a > b ? 1 : 0),
); // PeerId lexicographic(決定性)
}
總名次是 §13
computeMatchPrize(rank)與 §20 TrueSkill(rankings)的唯一輸入 → 獎金 / rating / 信譽皆 per-match 結算一次。線性積分之後可改 top-heavy(暫定線性)。結構 / 結算見 程式架構/ledger-settlement.md §5MatchResultEvent/RoundResult。
21. 反複製相似度(computeFeatureSimilarity v1)¶
mesh 幾何指紋特徵向量 → 0–100 整數相似度(共識值——上傳宣告收件驗證逐對重算比對;程式架構/anti-piracy.md §3/§5.1、門檻 90/70 見 版權.md §5.3):
// 各維相對差(ppm 整數法、同 relDiff);標準化已消除平移/旋轉/縮放/鏡像
dVertex = relDiffPpm(vertexCount) // number 域
dVolume = relDiffPpm(volume) // bigint 量化域
dSurface = relDiffPpm(surfaceArea)
dAabb = AABB 三軸 relDiffPpm 取 max
dBary = 重心三軸(絕對值域)relDiffPpm 取 max
similarityX100 = max(0, 100 − floor( max(五維 ppm) / 10_000 ))
- 取 max(非加權平均):「最不像的維度決定不相似度」——真複製 = 全維都像 →sim 高 → 拒收;任一維實質大改 → 掉出 90;多維各小改 8% 的稀釋式洗白在 max 下仍 sim 92→ 照樣拒收(與 UGC機制.md §5.3 的 rigidDiff 最大分量規則同哲學)。
- pcaAxes/isMirror v1 不進式(標準化後軸已對齊、鏡像已翻正——資訊已反映在 AABB/ 重心);如需納入隨版升級。
- 版本護欄:公式綁
fingerprintVersion(v1=1)——升級時舊作品鎖原版、跨版本比對一律放行(版權.md §5.2.2),公式演化不成硬分叉。 - 全整數運算(ppm 中介、floor 量化)——跨 peer bit 一致。
22. 常數權威來源¶
本檔公式中 K_AERO_* 的值見 protocol.md §2,其餘物理/武器 K_* 常數的值與完整清單見同檔 §18(待 playtest 校準)。本檔僅使用變數名,不另列數值表(避免重複指定)。
治理 / 升版流程:物理常數變更走 client major bump,非 ConfigUpdateEvent(物理性質是規則不是 config);詳見 版本規範.md。