游戏中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 让弹丸的散布偏移。

 

 

posted @ 2025-04-03 11:39  sun_dust_shadow  阅读(100)  评论(0)    收藏  举报