Unity绘制六边形体

news2024/11/19 17:34:52

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

功能

能够动态生成一系列可以“挖空中心”的六边形。指定innerWidth为0也可以生成实心的六边体。
在这里插入图片描述
在这里插入图片描述
能够生成平铺/直铺的六边形群,调整之间距离
在这里插入图片描述在这里插入图片描述在这里插入图片描述

绘制思路

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

组件

我们需要一个MeshFilter来设置mesh,一个MeshRenderer来设置mesh的材质。同时需要对mesh所需的内置成员变量有些了解。
在这里插入图片描述

        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是梯形短边的点,易得平面内某个点的计算方式
在这里插入图片描述
定义一个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();
    }

排布

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

纵向排布

在这里插入图片描述
前面我们生成面的时候发现有个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°的偏移

具体计算就初中级别的数学,就不一步步画图了
在这里插入图片描述

横向排布

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

在这里插入图片描述
万事具备,我们只需要计算每一行每列的点即可生成蜂窝了。

    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的物体

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));
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1478634.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32串口通信(发送与接收数据)

文章目录 前言一、介绍部分通信接口术语解释 串口通信简介硬件电路电平标准串口参数串口时序USART简介USART框图USRAT基本结构数据帧起始位检测波特率发生器CH340G 二、实例部分使用串口发送数据接线图代码实现重定向printf需要勾上Use MicroLIB中文不乱码方法 串口的发送与接收…

OS三大内存分配策略

三种内存分配策略 1.firstfit bestfit worsefit firstfit firstfit : 按地址排序的空间列表 首先碰到第一个内存块&#xff0c;如果可用&#xff0c;那么直接占用 第一个内存块 bestfit bestfit :相对与首次&#xff0c;有特点&#xff0c;对于内存块的差值比较小&#xf…

【Linux】入门篇-Linux的历史及发展历程(linux小型化成为安卓竟然有一段那么有趣的历史!!!)

目录 1.硬件的发展&#xff1a;1946年2月14日&#xff0c;人类历史上第一个计算机---埃尼阿克&#xff1a;为战争而生 1.1计算机的诞生-----为了战争&#xff08;军工阶段&#xff09; 研发的原因 时间就是胜利 冯诺依曼 战争的作用 1.2 硅谷模式&#xff08;时代背景&a…

docker save 命令 docker load 命令 快速复制容器

docker save 命令 docker load 命令 1、docker save 命令2、docker load 命令 1、docker save 命令 docker save 命令用于在系统上把正在使用的某个容器镜像 导出成容器镜像文件保存下载&#xff0c;以便在其他系统上导入这个容器镜像文件 以便快速在其他服务器上启动相同的容…

数据结构------栈(Stack)和队列(Queue)

也是好久没写博客了&#xff0c;那今天就回归一下&#xff0c;写一篇数据结构的博客吧。今天要写的是栈和队列&#xff0c;也是数据结构中比较基础的知识。那么下面开始今天要写的博客了。 目录 栈&#xff08;Stack&#xff09; 队列&#xff08;Queue&#xff09; 喜欢就点…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Row容器组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Row容器组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Row组件 沿水平方向布局容器。 子组件 可以包含子组件。 接口 Row(value?…

腾讯云又双叕降价,云服务器配置优惠价格表2024新版报价

腾讯云服务器多少钱一年&#xff1f;62元一年起&#xff0c;2核2G3M配置&#xff0c;腾讯云2核4G5M轻量应用服务器218元一年、756元3年&#xff0c;4核16G12M服务器32元1个月、312元一年&#xff0c;8核32G22M服务器115元1个月、345元3个月&#xff0c;腾讯云服务器网txyfwq.co…

YAML管理接口框架配置的最佳实践

管理接口框架配置是构建强大的接口测试框架的关键一环。良好的配置管理可以提高测试效率、可维护性和可扩展性。在本文中&#xff0c;我们将重点介绍使用YAML&#xff08;YAML Ain’t Markup Language&#xff09;来管理接口框架配置的最佳实践&#xff0c;并通过实例演示其用法…

Linux使用C语言实现通过互斥锁限制对共享资源的访问

互斥锁限制共享资源的访问 主线程中有两个线程&#xff0c;分别输出信息。 #include <stdio.h> #include <pthread.h> #include <unistd.h>int g_data0;void* fun1(void *arg) {printf("t1&#xff1a;%ld thread is create\n", (unsigned long)…

类和对象(2)——距离C++又近了一步

目录 一、构造函数 1.1声明和定义构造函数 1.2成员名和参数名 1.3构造函数的使用 1.4初始化列表 二、析构函数 2.1析构函数的概念 2.2析构函数的性质 三、拷贝构造函数 四、赋值运算符重载 4.1运算符重载 4.2赋值运算符重载 一、构造函数 我们知道&#xff0c;C中…

利用R语言进行因子分析实战(数据+代码+可视化+详细分析)

&#x1f349;CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一&#xff5c;统计学&#xff5c;干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项&#xff0c;参与研究经费10w、40w级横向 文…

C++重新入门-string容器

目录 1.包含头文件 2.创建字符串 3.获取字符串长度 4.字符串拼接 5.字符串比较 相等性比较 大小比较 使用比较函数 6.访问字符串 7.查找子串 8.字符串修改 替换子串 插入字符或子串 删除字符或子串 9.提取子串 10.总结 当谈到C中的字符串时&#xff0c;std::str…

蓝桥杯刷题3

目录: 1. 天干地支 2. 明明的随机数 3. ISBN号码 4. 缩位求和 5. 幸运数字 6. 串的处理 7. 最长递增 8. 灌溉 9. 特殊日期 10. 最大距离 1. 天干地支 import java.util.*;public class Main {public static void main(String[] args) {Scanner scan new Scanner(Sys…

spring boot集成Elasticsearch 7.16.3

环境&#xff1a;Elasticsearch 版本 7.16.3 Elasticsearch for windows下载地址 windows 若依 spring boot版本 2.6.0 pom文件添加 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch<…

Automated Testing for LLMOps 01:使用CircleCI进行持续集成CI

Automated Testing for LLMOps 这是学习https://www.deeplearning.ai/short-courses/automated-testing-llmops/ 这门课的笔记 Learn how LLM-based testing differs from traditional software testing and implement rules-based testing to assess your LLM application. …

Java实战:构建高效预报名管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

基于transform的scale属性,动态缩放整个页面,实现数据可视化大屏自适应,保持比例不变形,满足不同分辨率的需求

文章目录 一、需求背景&#xff1a;二、需求分析&#xff1a;三、选择方案&#xff1a;四、实现代码&#xff1a;五、效果预览&#xff1a;六、封装组件&#xff1a; 一、需求背景&#xff1a; 数据可视化大屏是一种将数据、信息和可视化效果集中展示在一块或多块大屏幕上的技…

GL绘制自定义线条4_使用OpenGL ES实现钢笔效果

在以前的文章里http://t.csdnimg.cn/TgCtl&#xff0c;我简述了如何使用OpenGL ES实现光滑的粗线条的绘制效果&#xff0c;在闲暇时间我把它再进一步进化&#xff0c;实现了端点长度按照压感大小实现伸缩的逻辑&#xff0c;从而实现了如下的笔锋效果&#xff1a; 书写过程中的效…

MCBPS配置成SPI

MCBPS配置成SPI 典型的SPI接口 McBSP作为SPI主机 以McBSP为主的SPI接口如图所示。当McBSP被配置为主控器时,发送输出信号(DX)被用作SPI协议的SPISIMO信号,并且接收输入信号(DR)被用作SPISOMI信号。 表列出了将McBSP配置为主控器所需的寄存器位值。下表是有关配置要求…

动环监控是什么?为什么说它是3d可视化机房的眼睛?

在信息化时代的背景下&#xff0c;数据中心机房的重要性日益凸显&#xff0c;传统的人工管理模式显然已经无法应对持续增长的机房数量和规模、日益复杂的网络、频繁更新迭代的资产硬件......搭建3d可视化机房成为了许多企事业单位的共同选择。想要搭建3d可视化机房&#xff0c;…