游戏中Shotgun(喷子)发射子弹的实现
参考:https://gamedev.stackexchange.com/questions/62468/how-to-implement-a-shotgun-in-a-game
Here is a page discussing shotgun spreads, you might take a look and see what they do.
http://www.shotgun-insight.com/LEPA_Results.html
目标:实现发射的子弹 中心点附近子弹较密集,边缘较稀疏。比较符合正太分布
GPT帮助下对http://www.shotgun-insight.com/LEPA_Results.html的总结:
1. 正态分布简介
-
正态分布(Normal Distribution)在Shotgun弹丸散布的分析中起着重要作用。
-
其特点是弹丸最可能落在中心位置(均值附近),随着偏离中心的距离增加,概率逐渐降低。
-
关键统计范围:
-
±1σ(sigma):68% 的弹丸落在此范围内。
-
±2σ:95% 的弹丸落在此范围内。
-
±3σ:99.7% 的弹丸落在此范围内。
-
-
Oberfell 和 Thompson 研究发现,Shotgun的弹丸分布可很好地用正态分布模型拟合。
2. Shotgun弹丸分布的度量方式
-
Spread x/y(散布范围 x/y):
-
通过拟合正态分布计算的 σ 值,表示弹丸的散布范围。
-
例如,如果 σ = 5",则 68% 的弹丸会落在 ±5" 的范围内。
-
-
75% shot diameter(75% 弹丸直径):
-
计算包含 75% 弹丸的直径,用于衡量Shotgun的散布情况。
-
3. 命中概率计算
-
0-10"、0-20"、0-30" 命中概率:
-
计算在不同范围内至少有一颗弹丸击中目标的概率。
-
对于精确射击的玩家,中心区域(0-10")的高命中率更重要。
-
对于游戏射击,目标运动不确定性较高,可能更需要均匀覆盖整个 30" 直径范围。
-
-
中心加权计算:
-
由于Shotgun射击时通常将目标对准中心,因此应该给中心区域更高的权重。
-
加权方式:
-
中心加权和(Centre Weighted Sum):给予 0-10"、10-20" 和 20-30" 区域相等的权重。
-
中心加权正态(Centre Weighted Norm):类似于正态分布,将中心区域赋予更高权重(68%),然后逐步降低
-
-
结论:Shotgun散布的分析和优化
-
选择合适的Shotgun子弹 需要分析 σ 值、中心命中率和命中概率曲线。
-
Shotgun的散布模式可用正态分布近似建模,但真实弹丸分布会受到枪支设计、子弹类型和阻铁影响。
-
在游戏开发中,如果想要 模拟真实的Shotgun散布,可以用 正态分布随机采样 来决定弹丸的散布角度,而不是使用 均匀分布的随机角度。
实现:
高斯分布
using System; public class GaussianRandom { private static Random rand = new Random(); public static float Generate(float mean, float stdDev) { // 生成两个 (0,1] 之间的随机数 double u1 = 1.0 - rand.NextDouble(); double u2 = 1.0 - rand.NextDouble(); // Box-Muller 变换 double z = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Cos(2.0 * Math.PI * u2); return (float)(mean + z * stdDev); } }
角度生成
using System; using UnityEngine; public class ShotgunSpread : MonoBehaviour { public int pelletCount = 10; // 弹丸数量 public float spreadAngle = 10.0f; // 最大散布角度(左右各 5°) public void FireShotgun() { for (int i = 0; i < pelletCount; i++) { // 生成高斯分布的散布角度 float spreadX = GaussianRandom.Generate(0f, spreadAngle / 3f); // 水平散布 float spreadY = GaussianRandom.Generate(0f, spreadAngle / 3f); // 垂直散布 // 计算弹丸方向 Vector3 shootDirection = transform.forward; // 枪口正前方 shootDirection += transform.right * Mathf.Tan(spreadX * Mathf.Deg2Rad); // 水平方向偏移 shootDirection += transform.up * Mathf.Tan(spreadY * Mathf.Deg2Rad); // 垂直方向偏移 shootDirection.Normalize(); // 归一化 Debug.Log($"Pellet {i + 1}: Direction {shootDirection}"); } } }
Generate(float mean, float stdDev) 参数解析
这个函数是高斯随机数生成器,它使用Box-Muller 变换来生成符合**正态分布(高斯分布)**的随机数。
在 Generate(mean, stdDev) 里:
-
mean(均值):决定生成的数值围绕哪个中心点分布。 -
stdDev(标准差):决定数值的散布范围(标准差越大,数值分布越宽)。
比如:
float x1 = GaussianRandom.Generate(0f, 5f); // 生成一个围绕 0 但最大偏差约 5 的随机数 float x2 = GaussianRandom.Generate(0f, 1f); // 生成一个围绕 0 但最大偏差约 1 的随机数 float x3 = GaussianRandom.Generate(10f, 2f); // 生成一个围绕 10 但最大偏差约 2 的随机数
-
均值 (mean) 是正态分布的中心点,它决定了数据分布的对称轴。
-
在散布模型中,mean 代表弹丸散布的中心点,通常是玩家准星的正中心位置。
-
例如,如果你在游戏中射击目标,mean 就是准星的中心,而弹丸会围绕这个点散布。
2. 在散布中的作用
-
mean = 0°(或 [0, 0]):
-
表示弹丸的散布围绕准星中心对称分布。
-
例如,如果你在屏幕中央射击,mean 就是准星中心,弹丸会围绕它形成一个高斯分布的弹着点云。
-
-
mean ≠ 0°(或 [X, Y]):
-
如果想要模拟某些特殊情况(例如枪械精度不高、枪口上抬等),可以调整 mean 值,使弹丸在准星中心的某个方向偏移。
-
3. 具体示例
假设你想要实现一个 水平方向的散布模型(仅考虑水平角度,不考虑垂直角度):
-
均值 mean = 0°,标准差 σ = 5°
-
68% 的弹丸会落在 ±5° 之间
-
95% 的弹丸会落在 ±10° 之间
-
99.7% 的弹丸会落在 ±15° 之间
-
这种情况意味着,大部分弹丸会集中在准星中心(0°),但仍然有少量弹丸会射向更远的位置。
-
-
均值 mean = 2°,标准差 σ = 5°
-
这个情况意味着,弹丸的中心会比准星向右偏移 2°。
-
68% 的弹丸会落在 [-3°, 7°] 的范围内,而不是对称于 0°。
-
适用于模拟枪械偏移(比如枪口上扬)。
-
4. 在游戏中的应用
-
如果想让弹丸严格围绕准星中心散布,那么 mean 应该设为 (0,0)(准星中心)。
-
如果想模拟偏差(比如枪口上扬、射击误差),可以调整 mean 让弹丸的散布偏移。

浙公网安备 33010602011771号