Unity绘制六边形体

这篇具有很好参考价值的文章主要介绍了Unity绘制六边形体。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

现在steam上面有很多下棋类/经营类的游戏都是用六边形的地形,比较美观而且实用,去年在版本末期我也自己尝试做了一个绘制六边体的demo,一年没接触unity竟然都要忘光了,赶紧在这边记录一下。
想cv代码可以直接拉到代码章节

功能

能够动态生成一系列可以“挖空中心”的六边形。指定innerWidth为0也可以生成实心的六边体。
Unity绘制六边形体,unity,图形渲染
Unity绘制六边形体,unity,图形渲染
能够生成平铺/直铺的六边形群,调整之间距离
Unity绘制六边形体,unity,图形渲染Unity绘制六边形体,unity,图形渲染Unity绘制六边形体,unity,图形渲染

绘制思路

将绘制一个六边形看成六个下面这种等腰体,绕中心旋转60度之后合并成一个。
Unity绘制六边形体,unity,图形渲染
Unity绘制六边形体,unity,图形渲染
一个这种等腰体又可以看成绘制四个面:上面的等腰梯形,内测的长方形,下面的等腰梯形,外侧的长方形,两边无需绘制,因为合并之后不会显示出来。
所以只需要通过三角函数计算出我们所需的所有点->拼出一个面->合成一个等腰体->合成一个六边体。

组件

我们需要一个MeshFilter来设置mesh,一个MeshRenderer来设置mesh的材质。同时需要对mesh所需的内置成员变量有些了解。
Unity绘制六边形体,unity,图形渲染

        m_meshFilter = GetComponent<MeshFilter>();
        m_meshRenderer = GetComponent<MeshRenderer>();

        m_mesh = new Mesh();
        m_mesh.name = "HexMesh";

        m_meshFilter.mesh = m_mesh;
        m_meshRenderer.material = m_material;
		
		//最终数据传入
		m_mesh.vertices = verticles.ToArray();
        m_mesh.triangles = tris.ToArray();
        m_mesh.uv = uvs.ToArray();
        m_mesh.RecalculateNormals();

具体计算

绘制某个点

根据前面需要绘制的等腰梯形,设A是梯形长边的点,B是梯形短边的点,易得平面内某个点的计算方式
Unity绘制六边形体,unity,图形渲染
定义一个CreatePoint接口,根据width和y轴高度height来生成某个点的三维向量,(注意unity下生成图中y轴实际上是三维空间的z轴)

  private Vector3 CreatePoint(float distance, float height, float angle)
    {
        float rad = angle * Mathf.Deg2Rad; //Mathf接收的参数需要是弧度制
        return new Vector3(distance * Mathf.Cos(rad), height, distance * Mathf.Sin(rad));
    }

生成面所需的数据

上文提到的等腰体四个不同面实际上都是四个顶点组成的,并且都是两个点组成的平行的线段,所以我们可以提供一个接口,只需指定高度和半径,就可以画出这四种不同的面,同时存在上下和内外两侧面的朝向是相反的,所以提供reverse接口来进行反向。

    /// <summary>
    /// 上下底面的单独一个等腰梯形
    /// </summary>
    /// <param name="innerRad">内径</param>
    /// <param name="outerRad">外径</param>
    /// <param name="heightA">外高</param>
    /// <param name="heightB">内高</param>
    /// <param name="point">顺序</param>
    /// <param name="reverse">连接方向</param>
    /// <returns></returns>
    private Face CreateFace(float innerRad, float outerRad, float heightA, float heightB, int point, bool reverse = false)
    {
        float angle1 = point * 60;
        float angle2 = angle1 + 60;
        if (!isFlat){ //竖着排布,初始角度是-30
            angle1 -= 30;
            angle2 -= 30;
        }
        List<Vector3> verticals = new List<Vector3>();
        //.......C.
        //..B.......
        //..........
        //...A......D
        verticals.Add(CreatePoint(innerRad, heightA, angle1));
        verticals.Add(CreatePoint(innerRad, heightA, angle2));
        verticals.Add(CreatePoint(outerRad, heightB, angle2));
        verticals.Add(CreatePoint(outerRad, heightB, angle1));
        List<int> tris = new List<int> { 0, 1, 2, 2, 3, 0};
        List<Vector2> uv = new List<Vector2> { new Vector2(0, 0),new Vector2(1,0),new Vector2(1,1),new Vector2(0,1) };
        //vertical顺序颠倒,就会按照顺时针绘制。
        if(reverse)
        {
            verticals.Reverse();
        }
        return new Face(verticals, tris, uv);
    }

这里有一些关于mesh的基础知识,首先是三个顶点能够组成一个面,从上往下看如果点之间是逆时针顺序的话,就是面向我们的。这里我们添加了四个点。tirs指定其顺序,每三个一组将会连成一个面,uvs代表是渲染的时候的uv坐标,这里如果六边体有规范的话,就需要根据需求设置对应的uv值,这里就不关注这个了。

      List<int> tris = new List<int> { 0, 1, 2, 2, 3, 0};
       List<Vector2> uv = new List<Vector2> { new Vector2(0, 0),new Vector2(1,0),new Vector2(1,1),new Vector2(0,1) };
public struct Face
{
    //顶点位置数组
    public List<Vector3> verticles { get; private set; }
    //三角形顶点索引数组,按给定的顺序连接顶点,为顺时针三个一组的顺序
    public List<int> triangles { get; private set; }
    public List<Vector2> uvs { get; private set; }

    public Face(List<Vector3> verticles, List<int> triangles, List<Vector2> uvs)
    {
        this.verticles = verticles;
        this.triangles = triangles;
        this.uvs = uvs;
    }
}

这样能够生产出一个面,接下来我们批量生产所需的面,只需要不断让角度偏移60度(忘记了可以去看上面计算A点坐标),重复刚才的步骤,将所有的面的数据都生成

 private void DrawFaces()
    {
        m_faces = new List<Face>();

        //上表面
        for(int point = 0; point < 6; point ++)
        {
            m_faces.Add(CreateFace(innerWidth, outerWidth, height / 2, height / 2, point));
        }
        //下表面
        for (int point = 0; point < 6; point++)
        {
            m_faces.Add(CreateFace(innerWidth, outerWidth,- height / 2, -height / 2, point,true));
        }
        //侧面
        for (int point = 0; point < 6; point++)
        {
            m_faces.Add(CreateFace(outerWidth, outerWidth, height / 2, -height / 2, point));
        }
        //里侧面
        for (int point = 0; point < 6; point++)
        {
            m_faces.Add(CreateFace(innerWidth, innerWidth, height / 2, -height / 2, point,true));
        }
    }

组装

刚才我们将数据填入Face,但是Face是不能直接使用的,我们要将刚才生成的顶点信息,uv信息,三角形信息等一次灌入Mesh中,
Mesh提供了成员变量来接收这些数据。
顶点和uv直接添加就可以,注意三角形数据需要根据顶点数据来加下标。

    private void CombineFaces()
    {
        List<Vector3> verticles = new List<Vector3>();
        List<int> tris = new List<int>();
        List<Vector2> uvs = new List<Vector2>();

        for(int i = 0; i < m_faces.Count; i++)
        {
            verticles.AddRange(m_faces[i].verticles); //AddRange方法可以把list中所有数据从头到尾添加到新的list
            uvs.AddRange(m_faces[i].uvs);

            //注意:这里需要依次指定指定所有顶点在最终mesh的三角形顺序,由于每个face里面包括四个顶点,每次+4
            int offset = (4 * i);
            foreach(int triangle in m_faces[i].triangles)
            {
                tris.Add(triangle + offset);
            }
        }

        m_mesh.vertices = verticles.ToArray();
        m_mesh.triangles = tris.ToArray();
        m_mesh.uv = uvs.ToArray();
        m_mesh.RecalculateNormals();
    }

排布

要让游戏能玩,肯定需要一系列整齐布局的六边形,所以我们需要一个动态创建六边形的管理器。

纵向排布

Unity绘制六边形体,unity,图形渲染
前面我们生成面的时候发现有个isFlat变量,这个变量就是控制了第一个面的生成角度,所以横向的时候能保证六边形是横着的。

    private Face CreateFace(float innerRad, float outerRad, float heightA, float heightB, int point, bool reverse = false)
    {
        float angle1 = point * 60;
        float angle2 = angle1 + 60;
        if (!isFlat){ //竖着排布,初始角度是-30
            angle1 -= 30;
            angle2 -= 30;
        }
        ......

问题是如何计算出每个六边形的中心点在哪。这里用三角函数也非常容易看出来
下面是六边体“直立“”情况下,设两个六边形之间间隔为d,六边形中心到外顶点的距离为L
可以发现Y轴方向每个六边形之间距离为(L * cos(30°) * 2 + d)* sin60°
X轴方向每个六边形之间距离为(L*(cos(30°)*2 + d)
同时注意距离偶数行的X轴要添加一个(L * cos(30°) * 2 + d)*sin30°的偏移

具体计算就初中级别的数学,就不一步步画图了
Unity绘制六边形体,unity,图形渲染

横向排布

同理横向布局也很好计算
可以发现Y轴方向每个六边形之间距离为(L * cos(30°) * 2 + d)
X轴方向每个六边形之间距离为(L*(cos(30°)*2 + d) *sin60°
同时注意距离偶数行的Y轴要添加一个(L * cos(30°) * 2 + d)*sin30°的偏移

Unity绘制六边形体,unity,图形渲染
万事具备,我们只需要计算每一行每列的点即可生成蜂窝了。

    public void SetInterval()
    {
        centerDistance = outterWidth * 2 * Mathf.Sin(60 * Mathf.Deg2Rad) + interval;
    }
	 private void UpdateGrid(GameObject[][] girds)
 {
     if (girds.Length <= 0) return;
     bool shouldOffset = false;
     for (int j = 0; j < heightCount; j++)
     {
         if (!isFlat)
         {
             shouldOffset = j % 2 != 0;
         }
         for (int i = 0; i < widthCount; i++)
         {
             if (isFlat)
             {
                 shouldOffset = i % 2 != 0;
             }
             HexagonRenderer render = girds[i][j].GetComponent<HexagonRenderer>();
             //计算六边形位置
             Vector3 pos = Getpos(i, j, shouldOffset);
             Debug.Log(pos);
             render.SetAtrributes(innerWidth, outterWidth, height, pos, matrial, isFlat);
             render.DrawMesh();
         }
     }
 }

 private Vector3 Getpos(int i, int j, bool shouldOffset)
 {
     float angle60 = 60 * Mathf.Deg2Rad;
     float angle30 = 30 * Mathf.Deg2Rad;
     if (isFlat)
     {
         if (shouldOffset)
         {
             return new Vector3(i * centerDistance * Mathf.Sin(angle60) , transform.position.y, j * centerDistance +centerDistance * Mathf.Sin(angle30));
         }
         else
         {
             return new Vector3(i * centerDistance * Mathf.Sin(angle60), transform.position.y, j * centerDistance);
         }
     }
     else
     {
         if (shouldOffset)
         {
             return new Vector3(i * centerDistance + centerDistance * Mathf.Sin(angle30), transform.position.y, j * centerDistance * Mathf.Sin(angle60));
         }
         else
         {
             return new Vector3(i * centerDistance, transform.position.y, j * centerDistance * Mathf.Sin(angle60));
         }
     }

 }

完整代码

在场景中创建一个空物体,将GenerateMap.cs挂载在其身上即可,将会自动生成一系列身上挂载HexagonRenderer.cs的物体文章来源地址https://www.toymoban.com/news/detail-840335.html

GenerateMap.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GenerateMap : MonoBehaviour
{
    [Header("Grid Settings")]
    public int widthCount;
    public int heightCount;

    [Header("Layout Settings")]
    public float innerWidth;
    public float outterWidth;
    public float height;
    public bool isFlat;
    public Material matrial;
    /// <summary>
    /// 六边形之间的间隔
    /// </summary>
    public float interval;
    private float centerDistance;


    /// <summary>
    /// 存储所有的六边形
    /// </summary>
    private GameObject[][] girds;
    private bool hasGenerate = false;
    public void Start()
    {
        girds = new GameObject[widthCount][];
        for (int i = 0; i < girds.Length; i++)
        {
            girds[i] = new GameObject[heightCount];
        }
        SetInterval();
        GenerateGrid();
        LayoutGrid();
    }

    public void SetInterval()
    {
        centerDistance = outterWidth * 2 * Mathf.Sin(60 * Mathf.Deg2Rad) + interval;
    }
    /// <summary>
    /// 设置六边形布局,从左下角生成
    /// </summary>
    private void LayoutGrid()
    {
        UpdateGrid(girds);
    }

    private void GenerateGrid()
    {
        if (hasGenerate == true) return;
        for (int j = 0; j < heightCount; j++)
        {
            for (int i = 0; i < widthCount; i++)
            {
                GameObject single = new GameObject($"HEX:({i},{j})", typeof(HexagonRenderer)); //$代表string.format
                girds[i][j] = single;
                single.transform.SetParent(transform, true);
            }
        }
        hasGenerate = true;
    }

    private void UpdateGrid(GameObject[][] girds)
    {
        if (girds.Length <= 0) return;
        bool shouldOffset = false;
        for (int j = 0; j < heightCount; j++)
        {
            if (!isFlat)
            {
                shouldOffset = j % 2 != 0;
            }
            for (int i = 0; i < widthCount; i++)
            {
                if (isFlat)
                {
                    shouldOffset = i % 2 != 0;
                }
                HexagonRenderer render = girds[i][j].GetComponent<HexagonRenderer>();
                //计算六边形位置
                Vector3 pos = Getpos(i, j, shouldOffset);
                Debug.Log(pos);
                render.SetAtrributes(innerWidth, outterWidth, height, pos, matrial, isFlat);
                render.DrawMesh();
            }
        }
    }

    private Vector3 Getpos(int i, int j, bool shouldOffset)
    {
        float angle60 = 60 * Mathf.Deg2Rad;
        float angle30 = 30 * Mathf.Deg2Rad;
        if (isFlat)
        {
            if (shouldOffset)
            {
                return new Vector3(i * centerDistance * Mathf.Sin(angle60) , transform.position.y, j * centerDistance +centerDistance * Mathf.Sin(angle30));
            }
            else
            {
                return new Vector3(i * centerDistance * Mathf.Sin(angle60), transform.position.y, j * centerDistance);
            }
        }
        else
        {
            if (shouldOffset)
            {
                return new Vector3(i * centerDistance + centerDistance * Mathf.Sin(angle30), transform.position.y, j * centerDistance * Mathf.Sin(angle60));
            }
            else
            {
                return new Vector3(i * centerDistance, transform.position.y, j * centerDistance * Mathf.Sin(angle60));
            }
        }

    }
}

HexagonRenderer.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public struct Face
{
    //顶点位置数组
    public List<Vector3> verticles { get; private set; }
    //三角形顶点索引数组,按给定的顺序连接顶点,为顺时针三个一组的顺序
    public List<int> triangles { get; private set; }
    public List<Vector2> uvs { get; private set; }

    public Face(List<Vector3> verticles, List<int> triangles, List<Vector2> uvs)
    {
        this.verticles = verticles;
        this.triangles = triangles;
        this.uvs = uvs;
    }
}
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]

public class HexagonRenderer : MonoBehaviour
{
    private Mesh m_mesh;
    private MeshFilter m_meshFilter;
    private MeshRenderer m_meshRenderer;

    private List<Face> m_faces;

    private bool isFlat = true;

    public Material m_material;
    public float innerWidth;
    public float outerWidth;
    public float height;
    private void Awake()
    {
        m_meshFilter = GetComponent<MeshFilter>();
        m_meshRenderer = GetComponent<MeshRenderer>();

        m_mesh = new Mesh();
        m_mesh.name = "HexMesh";

        m_meshFilter.mesh = m_mesh;
        m_meshRenderer.material = m_material;
    }
    public void SetAtrributes(float innerWidth, float outerWidth, float height, Vector3 position, Material material, bool isFlat)
    {
        this.innerWidth = innerWidth;
        this.outerWidth = outerWidth;
        this.isFlat = isFlat;
        this.height = height;
        transform.position = position;
        m_material = material;
        m_meshRenderer.material = m_material;

        DrawMesh();
    }
    private void OnEnable()
    {
        DrawMesh();
    }

    //渲染整个六边形体
    public void DrawMesh()
    {
        DrawFaces();
        CombineFaces();
    }

    private void OnValidate()
    {
    }

    private void DrawFaces()
    {
        m_faces = new List<Face>();

        //上表面
        for (int point = 0; point < 6; point++)
        {
            m_faces.Add(CreateFace(innerWidth, outerWidth, height / 2, height / 2, point));
        }
        //下表面
        for (int point = 0; point < 6; point++)
        {
            m_faces.Add(CreateFace(innerWidth, outerWidth, -height / 2, -height / 2, point, true));
        }
        //侧面
        for (int point = 0; point < 6; point++)
        {
            m_faces.Add(CreateFace(outerWidth, outerWidth, height / 2, -height / 2, point));
        }
        //里侧面
        for (int point = 0; point < 6; point++)
        {
            m_faces.Add(CreateFace(innerWidth, innerWidth, height / 2, -height / 2, point, true));
        }
    }
    private void CombineFaces()
    {
        List<Vector3> verticles = new List<Vector3>();
        List<int> tris = new List<int>();
        List<Vector2> uvs = new List<Vector2>();

        for (int i = 0; i < m_faces.Count; i++)
        {
            verticles.AddRange(m_faces[i].verticles);AddRange方法可以把list中所有数据从头到尾添加到新的list
            uvs.AddRange(m_faces[i].uvs);

            //注意:这里需要依次指定指定所有顶点在最终mesh的三角形顺序,由于每个face里面包括四个顶点,每次+4
            int offset = (4 * i);
            foreach (int triangle in m_faces[i].triangles)
            {
                tris.Add(triangle + offset);
            }
        }

        m_mesh.vertices = verticles.ToArray();
        m_mesh.triangles = tris.ToArray();
        m_mesh.uv = uvs.ToArray();
        m_mesh.RecalculateNormals();
    }
    /// <summary>
    /// 上下底面的单独一个等腰梯形
    /// </summary>
    /// <param name="innerRad">内径</param>
    /// <param name="outerRad">外径</param>
    /// <param name="heightA">外高</param>
    /// <param name="heightB">内高</param>
    /// <param name="point">顺序</param>
    /// <param name="reverse">连接方向</param>
    /// <returns></returns>
    private Face CreateFace(float innerRad, float outerRad, float heightA, float heightB, int point, bool reverse = false)
    {
        float angle1 = point * 60;
        float angle2 = angle1 + 60;
        if (!isFlat)
        {
            angle1 -= 30;
            angle2 -= 30;
        }
        List<Vector3> verticals = new List<Vector3>();
        //.......C.
        //..B.......
        //..........
        //...A......D
        verticals.Add(CreatePoint(innerRad, heightA, angle1));
        verticals.Add(CreatePoint(innerRad, heightA, angle2));
        verticals.Add(CreatePoint(outerRad, heightB, angle2));
        verticals.Add(CreatePoint(outerRad, heightB, angle1));
        List<int> tris = new List<int> { 0, 1, 2, 2, 3, 0 };
        List<Vector2> uv = new List<Vector2> { new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1) };

        if (reverse)
        {
            verticals.Reverse();
        }
        return new Face(verticals, tris, uv);
    }
    /// <summary>
    /// 创造一个顶点
    /// </summary>
    /// <param name="distance">距离坐标原点距离</param>
    /// <param name="height">y轴高度</param>
    /// <param name="angle">和坐标轴所成夹角</param>
    /// <returns></returns>

    private Vector3 CreatePoint(float distance, float height, float angle)
    {
        float rad = angle * Mathf.Deg2Rad;
        return new Vector3(distance * Mathf.Cos(rad), height, distance * Mathf.Sin(rad));
    }
}

到了这里,关于Unity绘制六边形体的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • DDD架构为什么应该首选六边形架构?

    分层架构的一个重要原则是:每层只能与位于其下方的层发生耦合。 分层架构分两种:一种是严格分层架构,规定某层只能与直接位于其下方的层发生耦合;另一种是松散分层架构,允许任意上方层与任意下方层发生耦合。 下图是一个典型的DDD传统分层架构。 以上分层架构

    2024年02月16日
    浏览(51)
  • ❤️创意网页:如何创建一个漂亮的3D正六边形

    ✨ 博主: 命运之光   🌸 专栏: Python星辰秘典 🐳 专栏: web开发(简单好用又好看) ❤️ 专栏: Java经典程序设计 ☀️ 博主的其他文章: 点击进入博主的主页 前言: 欢迎踏入我的Web项目专栏,一段神奇而令人陶醉的数字世界! 🌌 在这里,我将带您穿越时空,揭开属于

    2024年02月16日
    浏览(48)
  • 数据分析系统中的六边形战士——奥威BI系统

    数据分析软件可以对收集的数据进行分析和报告,帮助企业获得更深入的数据洞察力,从而推动企业数字化运营决策,提高决策效率与质量。进入大数据时代,企业对数据分析软件的要求也在水涨船高,传统的数据分析软件显然已不能满足企业大数据智能可视化分析的精细化

    2024年02月16日
    浏览(35)
  • 从混乱到优雅:基于DDD的六边形架构的代码翻新指南

    趁着双十一备战封板,终于又有一些时间可以梳理一下最近的心得。 最近这半年跟同事讨论比较多的是分层架构,然后就会遇到两个触及灵魂的问题,一个是如何做好分层架构,二是DDD在架构层面该如何落地。 为了说好分层,我们需要了解架构的意义。 良好的架构是为了保

    2024年02月05日
    浏览(53)
  • QT使用QImage制作图片的四种(圆形,六边形,复古与负片)效果(测试过效果的代码)

    负片效果: 复古效果:   裁剪成圆形   裁剪成六边形:  

    2024年02月13日
    浏览(38)
  • 【Unity 3D绳索】基于图形渲染的3D绳索模拟

            前一段被要求模拟一根绳索,因为种种原因,笔者最后决定通过数学函数和Mesh模拟出一根绳索,具体的思路是首先利用Verlet函数模拟绳索的刚性,之后利用Mesh渲染圆柱体将绳索模拟出来。                  首先,利用Verlet进行逻辑上的绳索创建,具体思路参考

    2024年04月29日
    浏览(36)
  • 计算机图形学实验——利用MFC对话框实现多边形绘制与填充(扫描线填充算法)附源码

    内容概括: 利用基于对话框的MFC项目 实现鼠标点击绘制多边形 实现扫描线算法填充多边形 源码见Yushan-Ji/ComputerGraphics: ECNU2023秋 计算机图形学课程实验代码 (github.com) 通过鼠标交互输入多边形 对各种多边形进行填充,包括边界自交的情况 利用 OnLButtonDown 和 OnRButtonDown 函数,

    2024年02月04日
    浏览(70)
  • [游戏开发]Unity多边形分割为三角形_耳切法

    有个小需求是分割一下多边形,顺带记录一下。通常来说多边形的形状都比较复杂,不好进行操作,这个时候如果我们可以把一个多边形分隔为若干个三角形,回归到简单基础的形状就方便我们操作。三角形化在渲染显示中还是挺多用的。下文未列出,但涉及到的代码链接如

    2024年02月10日
    浏览(43)
  • unity3d,平面和四边形的区别是什么

    在Unity中,平面和四边形都是基础的几何形状,用于创建游戏场景中的地形、墙壁、天花板等。虽然它们都是由多个点和线构成的,但是它们之间有着一些重要的区别。 平面是由三个或更多个点组成的,这些点通常位于同一平面上。在Unity中,可以使用Mesh类来创建平面,并指

    2024年02月03日
    浏览(38)
  • [游戏开发]Unity中随机位置_在圆/椭圆/三角形/多边形/内随机一个点

    在做游戏的时候经常需要随机某一个点,而且形状各种各样,每次要随机的时候就容易忘记怎么弄了。这里总结一下各种常见形状内基础随机方式。 略~ 圆形随机一般有两种。一种是通过极坐标来随机,另一种是先正常随机矩形在判断点是否在圆形内。第二种其实使用的范围

    2024年02月12日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包