圆形内均匀分布的随机点Unity_C#_多注释

原题:怎么设计pubg的随机空投点,假如是一个圆形的小岛
首先说的常见错误答案

选取两个随机变量,一个(0-360)的随机角变量,一个(0-安全区半径)的距离变量,两个变量组合为一个新的极坐标。但该方法其实会导致,越靠近原点的地方,随机点越密集。
如下图:
在这里插入图片描述

该图拷贝自链接

正确思路

设圆的半径为R
我们需要取三个系数,首先是随机系数 t,t是(0-1)均匀分布的随机数,半径系数 r,r=sqrt(t)∗R,角度系数θ, θ=2π∗t,要注意r和θ要分别使用两个不同的随机数t来生成
那么生成的x和y规则为
x=r∗cos(θ),y=r∗sin(θ)

公式参考 连接 需要用到概率论和高等数学的知识

先放生成效果

Tips:代码中加了颜色系数,颜色越绿的,生成的越晚,也侧面反映出,点是纯随机分布的。
在这里插入图片描述

核心逻辑(后面有放完整代码)

void Awake()
    {

        Debug.Log("开始时间 "+GetTimeStamp());
        pointCount = 5000;//要生成点的数量
        resultList = new double[pointCount, 2];
        double radius = 2; //圆的半径,要生成点在该半径的圆内
        double randomValue; //0-1的随机值
        double r;//公式的r系数
        double theta; //公式的角度系数
        double x;
        double y;
        System.Random random = new System.Random();
        for (int i = 0; i < pointCount; i++)
        {
            // Tip 此处要注意! r和theta的生成要分别生成随机数,公式概念中明确说明,r和theta要互不相干
            randomValue = random.NextDouble();
            r = Math.Sqrt(randomValue) * radius;
            randomValue = random.NextDouble();
            theta = 2 * Math.PI * randomValue;
            //生成x,y坐标,
            x = r * Math.Cos(theta);
            y = r * Math.Sin(theta);
            resultList[i,0] = x;
            resultList[i, 1] = y;//* 0.5; 若要变成椭圆,将X和Y结果值乘上你想要的比例系数即可
        }
        Debug.Log("结束时间 " + GetTimeStamp());
    }
Unity内可以运行的代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//解法思路:公式来自:https://wenku.baidu.com/view/de291225aaea998fcc220ef9.html
//设半径为R
//x=r∗cos(θ)
//y=r∗sin(θ)
//t为0-1均匀分布产生的随机数,r=sqrt(t)∗R,θ=2π∗t
public class Run : MonoBehaviour {
    /// <summary>
    /// 获取时间戳
    /// </summary>
    /// <returns></returns>
    public static string GetTimeStamp()
    {
        TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
        return Convert.ToInt64(ts.TotalMilliseconds).ToString();
    }
    //存储结果列表
    public double[,] resultList;
    //要生成点的数量
    int pointCount;
    void Awake()
    {

        Debug.Log("开始时间 "+GetTimeStamp());
        pointCount = 5000;//要生成点的数量
        resultList = new double[pointCount, 2];
        double radius = 2; //圆的半径,要生成点在该半径的圆内
        double randomValue; //0-1的随机值
        double r;//公式的r系数
        double theta; //公式的角度系数
        double x;
        double y;
        System.Random random = new System.Random();
        for (int i = 0; i < pointCount; i++)
        {
            // Tip 此处要注意! r和theta的生成要分别生成随机数,公式概念中明确说明,r和theta要互不相干
            randomValue = random.NextDouble();
            r = Math.Sqrt(randomValue) * radius;
            randomValue = random.NextDouble();
            theta = 2 * Math.PI * randomValue;
            //生成x,y坐标,
            x = r * Math.Cos(theta);
            y = r * Math.Sin(theta);
            resultList[i,0] = x;
            resultList[i, 1] = y;//* 0.5; 若要变成椭圆,将X和Y结果值乘上你想要的比例系数即可
        }
        Debug.Log("结束时间 " + GetTimeStamp());
    }
  
    void OnDrawGizmos()
    {
        float colorOffset = 1f / pointCount;
        for (int i = 0; i < pointCount; i++)
        {
            Gizmos.color = new Color(colorOffset * i, 1f, 1f);
            Gizmos.DrawSphere(new Vector3((float)resultList[i, 0], (float)resultList[i, 1], 0), 0.02f);
        }
    }
}

Unity内实现的效果

加了颜色系数,颜色越绿的,生成的越晚,也侧面反映出,点是纯随机分布的。
在这里插入图片描述
加了坐标系数后的椭圆效果,y*0.5

在这里插入图片描述

简单的性能比较

除了上述方法,还有一种方法也可以达到同样的效果。
即 先在矩形内选随机点,然后判断这个点是否在圆内,如果在,则保留,如果不在则舍去。
核心代码如下:

   //存储结果列表
    public double[,] resultList;
    //要生成点的数量
    int pointCount;
    void Awake()
    {

        Debug.Log("开始时间 " + GetTimeStamp());
        pointCount = 100000;//要生成点的数量
        resultList = new double[pointCount, 2];
        double radius = 2; //要生成点半径
        double Radius = radius * 2; //要生成点半径
        double radiusPow2 = Math.Pow(radius, 2);
        double randomValue; 
        double x;
        double y;
        int tempCount = 0;
        System.Random random = new System.Random();
        while(tempCount < pointCount)
        {
            randomValue = random.NextDouble();
            x = randomValue * Radius - radius;
            randomValue = random.NextDouble();
            y = randomValue * Radius - radius;
            if (Math.Pow(x, 2) + Math.Pow(y, 2) <= radiusPow2)
            {
                resultList[tempCount, 0] = x;
                resultList[tempCount, 1] = y;
            }
            tempCount++;
        }
        Debug.Log("结束时间 " + GetTimeStamp());
    }

经比较,同样生成50000个随机点,该方法比第一种慢了5ms
第一种
在这里插入图片描述
第二种
在这里插入图片描述

如果您看到了最后,希望大佬给个赞可以嘛,想攒个人气,以后面试加个分。谢谢。

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值