【游戏开发算法每日一记】使用随机prime算法生成错综复杂效果的迷宫(C#,C++和Unity版)

news2024/11/25 10:08:07

在这里插入图片描述


👨‍💻个人主页:@元宇宙-秩沅

👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍💻 本文由 秩沅 原创

👨‍💻 收录于专栏:Unity基础实战

🅰️



文章目录

    • 🅰️
    • 前言
    • 🎶(==1==)简单的prime算法——十字检测
    • c#版本的十字Prim
    • c++版本的十字Prim
    • Unity版本的十字Prim
    • 🎶(==2==)prime算法生成的效果
    • 🅰️


前言


🎶(1简单的prime算法——十字检测


在这里插入图片描述

在这里插入图片描述

  • 1.首先全部判定为墙,最外的为路包裹墙(类似于防止数组越界
    在这里插入图片描述
  • 2.红色为它的检测范围(假设检测点在如图所示的位置)———(可先忽略此步骤)

——————在这里插入图片描述

  • 3.该检测点(紫色)需要在起点的旁边或者外墙旁边,已保证它可以生成主路线而不是死迷宫
    在这里插入图片描述
    在这里插入图片描述
  • 4.生成后是这样的,没有出口,它不会自动打破墙
    在这里插入图片描述
  • 5,所以需要我们自己检测一波打出一个出口

在这里插入图片描述

  • 运行结果
    在这里插入图片描述

c#版本的十字Prim


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace algorithm
{
    /// <summary>
    /// 该Prom算法,初始化时全部是墙
    /// </summary>
    class PrimOfAlgorithm
    {

        public const int max = 40;
        int[,] Maze = new int[max  , max ];  //默认全为0 ,全为墙
        Random random = new Random();
        //X和Y方向的队列
        List<int> X = new List<int>();
        List<int> Y = new List<int>();

        /// <summary>
        /// 生成迷宫
        /// </summary>
        public  void CreatMap()
        {
            //设置迷宫进口
            Maze[2, 1] = 1;
         
        
            //将最外围设置为路,包裹最外层的的墙,防止出界
            for (int i = 0; i < max; i++)
            {
                Maze[i ,0]= 1;
                Maze[i, max - 1] = 1;
                Maze[0, i] = 1;
                Maze[max - 1, i] = 1;  
            }

            //设置一个坐标.该检测点需要在起点的旁边,或者旁边是外围路

            X.Add (2);
            Y.Add (2);

            while( Y.Count > 0)
            {
               
                int index = random.Next(0, X.Count - 1); //随机性则有错综复杂的效果
            
                int xPosition=  X[index];
                int yPosition = Y[index];

                //判断上下左右是否有路
                int count = 0;
               
                for (int i = xPosition - 1; i <= xPosition + 1; i++) //左右位置
                {
                    for (int j = yPosition - 1; j <= yPosition + 1; j++) //上下位置
                    {
                        //判断它是不是十字检测中的点,和判断它是否为路
                        if (Math.Abs(xPosition - i) + Math.Abs(yPosition - j) == 1 && Maze[i,j] > 0) 
                         {
                            ++count; //路++  
                         }
                    }
                }

                //如果十字检测的路标记少于或等于1条?(为甚不直接小于1呢,因为它要保证生成一条主路)
                if (count <= 1)
                {
                    //将此刻的位置变成路
                    Maze[xPosition, yPosition] = 1;

                    for (int i = xPosition - 1; i <= xPosition + 1; i++)
                    {
                        for (int j = yPosition - 1; j <= yPosition + 1; j++)
                        {
                            //判断它是不是十字检测中的点并且是墙
                            if (Math.Abs(xPosition - i) + Math.Abs(yPosition - j) == 1 && Maze[i, j] == 0)
                            {
                                //把十字检测到的墙放入XY墙列表
                                X.Add(i);
                                Y.Add(j);
                            }
                        }

                    }
                }
           
                //删除列表中已经变成路的点
                X.RemoveAt(0 + index );
                Y.RemoveAt(0 + index ); //记住不能是Remove
                              
            }

            //设置迷宫出口(出口不可能是四个底脚)
            for (int i = max - 3; i >= 0; i--)
            {
                if (Maze[i, max - 3] == 1)
                {
                    Maze[i, max - 2] = 1;
                    break;
                }
            }
            //画迷宫
            for (int i = 0; i < max; i++)
            {
                for (int j = 0; j < max; j++)
                {
                    if (Maze[i, j] == 1)
                        Console.Write("  ");
                    else
                        Console.Write("囚");
                }
                Console.WriteLine();
            }

        }


        static void Main(string[] args)
        {
            PrimOfAlgorithm aa = new PrimOfAlgorithm();
         
             aa.CreatMap();
           
        }
    }


    
}


c++版本的十字Prim



#include <iostream>
#include<vector>
#include <windows.h>
using namespace std;
static const int L = 44;
void CreateMaze();
int main()
{
	CreateMaze();
}
 void CreateMaze() {
	int Maze[L][L] = { 0 };
 

	vector<int> X;
	vector<int> Y;

	//最外围设置为路,可以有效的保护里面一层墙体,并防止挖出界
	for (int i = 0; i < L; i++) {
		Maze[i][0] = 1;
		Maze[0][i] = 1;
		Maze[L - 1][i] = 1;
		Maze[i][L - 1] = 1;
	}

	//设置迷宫进口
	Maze[2][1] = 1;
	
	//任取初始值
	X.push_back(2);
	Y.push_back(2);
 
	//当墙队列为空时结束循环
	while (X.size()) {
		//在墙队列中随机取一点
		int r = rand() % X.size();
		int x = X[r];
		int y = Y[r];
 
		//判读上下左右四个方向是否为路
		int count = 0;
		for (int i = x - 1; i < x + 2; i++) {	
			for (int j = y - 1; j < y + 2; j++) {
				if (abs(x - i) + abs(y - j) == 1 && Maze[i][j] > 0) {
					++count;
				}
			}
		}
 
		if (count <= 1) {

			Maze[x][y] = 1;

			
			//在墙队列中插入新的墙
			for (int i = x - 1; i < x + 2; i++) {
				for (int j = y - 1; j < y + 2; j++) {
					
					if (abs(x - i) + abs(y - j) == 1 && Maze[i][j] == 0) {
						X.push_back(i);
						Y.push_back(j);
					}
				}
			}
		}
 
		//删除当前墙
		X.erase(X.begin() + r);
		Y.erase(Y.begin() + r);
	}
 
	//设置出口 (从最下往上面判断)
	for (int i = L - 3; i >= 0; i--) {
		if (Maze[i][L - 3] == 1) {
			Maze[i][L - 2] = 1;
			break;
		}
	}
 
	//画迷宫
	for (int i = 0; i < L; i++){
		for (int j = 0; j < L; j++) {
			if (Maze[i][j] == 1) printf("  ");
			else printf("囚");
		}
		printf("\n");
	}

	
}

Unity版本的十字Prim


在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目:      
//___________功能:  生成迷宫
//___________创建者:_____秩沅_____
//_____________________________________
//-------------------------------------
public class Muze : MonoBehaviour
{
    const int max = 40;
    //建立迷宫数组
    private int[,] mauz = new int [max ,max ];

    //墙列表
    private List<int > X = new List<int>();
    private List<int>  Y = new List<int>();

    //待加载资源
    private GameObject m_prefab_tile;
    private GameObject m_prefab_wall;

    private void Awake()
    {
        //资源加载
        m_prefab_tile = Resources.Load<GameObject>("prefabs/tile_white");
        m_prefab_wall = Resources.Load<GameObject>("prefabs/cube_bread");
    }

    void Start()
    {
        //初始坐标
        CreatMazu(new Vector2(2,1));
    }

    /// <summary>
    /// 生成迷宫
    /// </summary>
    public void CreatMazu( Vector2  position)
    {
        
          //step1.设置外墙
          for (int i = 0; i < max ; i++)
          {
            mauz[0, i] = 1;
            mauz[i, 0] = 1;
            mauz[i, max - 1] = 1;
            mauz[max - 1, i] = 1;
          }

          //step2.将初始位置放入队列当中
          X.Add((int )position.x);
          Y.Add((int )position.y);
        
        mauz[(int )position.x, (int )position.y] = 1; //它为起点
    
        while(X.Count > 0) //当列表里面有值的时候,也代表有墙的时候
        {
            //step3:从列表中取判定点
            int index = Random.Range(0, X.Count - 1); //从墙队列里面随机取一个下标
            int xPosition = X[index];
            int yPosition = Y[index];

            int count = 0;  //路的数量

            //step4:道路判定
            for (int i = xPosition - 1; i <= xPosition + 1; i++)
            {
                for (int j = yPosition - 1; j <= yPosition + 1; j++)
                {
                    if (Mathf.Abs(xPosition - i) + Mathf.Abs(yPosition - j) == 1 && mauz[i, j] > 0)
                    {
                        count++;
                    }
                }
            }

            //step5:变成路,添加墙
            if (count <= 1)
            {
                mauz[xPosition, yPosition] = 1; //变成路

                for (int i = xPosition - 1; i <= xPosition + 1; i++)
                {
                    for (int j = yPosition - 1; j <= yPosition + 1; j++)
                    {
                        if (Mathf.Abs(xPosition - i) + Mathf.Abs(yPosition - j) == 1 && mauz[i, j] == 0)
                        {
                            X.Add(i);
                            Y.Add(j);
                        }
                    }
                }
            }

            //step6:移除列表里面的墙
            X.RemoveAt(0 + index);
            Y.RemoveAt(0 + index);

        }

  
           //step7:检测一下设置出口
          for (int i = max - 3 ; i  > 0 ; i-- )
          {
              if(mauz[i,max - 3 ] == 1 )
              {
                mauz[i, max - 2] = 1;
                break;
              }
          }

         //step8:加载迷宫
          for (int i = 0; i < max ; i++)
          {
              for (int j = 0; j < max ; j++)
               {
                  if(mauz[i,j] == 0 )
                  {
                    GameObject ob =  Instantiate(m_prefab_wall,new Vector3(i * 0.254f, 0 , j * 0.254f),Quaternion.identity );
                    ob.transform.SetParent(transform);
                  }                
                }
          }
    }
}


🎶(2prime算法生成的效果


迷宫相对比较自然,但迷宫的分岔路会比较多,适合生成错综复杂的地图效果,主路不是特别明显

  • 初始化大地图,0代表墙,1代表道路,墙为地图边缘包裹

  • 靠近地图边缘随机选取状态为1的道路点,作为出生点a

  • 然后将 a 点周围所有的墙体点标记为待检测点,加入到待检测集合

  • 从待检测集合随机取一个点 b ,判断顺着它方向的下一个点 c,是否是道路

  • 如果是,则将这个待检测点墙体打通,将其移出待检测集合;将下一个点 c作为新的起点,重新执行第3步

  • 如果不是就把这个待检测点移出待检测集合,重新作为墙体点
    不断重复,直到待检测集合全部检查过,重新为空
    在这里插入图片描述

🅰️


⭐【Unityc#专题篇】之c#进阶篇】

⭐【Unityc#专题篇】之c#核心篇】

⭐【Unityc#专题篇】之c#基础篇】

⭐【Unity-c#专题篇】之c#入门篇】

【Unityc#专题篇】—进阶章题单实践练习

⭐【Unityc#专题篇】—基础章题单实践练习

【Unityc#专题篇】—核心章题单实践练习


你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!


在这里插入图片描述


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

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

相关文章

RT-Thread系列10——ETH网口设备

文章目录 1. ETH测试第一步&#xff1a;cubemx配置。第二步&#xff1a;board.h配置。第三步&#xff1a;rtthread settings配置第四步&#xff1a;以太网复位引脚设置第五步&#xff1a;修改rtthread源码第六步&#xff1a;修改 cubemx 生成的 main 函数第七步&#xff1a;编译…

【MATLAB源码-第76期】基于matlab的OCDM系统在AWGN信道下理论误码率和实际误码率对比仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 正交线性调频分频复用&#xff08;OCDM&#xff0c;Orthogonal Chirp Division Multiplexing&#xff09;是一种无线通信技术&#xff0c;它基于啁啾信号的原理。啁啾信号是一种频率随时间变化的信号&#xff0c;通常频率是线…

Ant Design Vue Select下拉框内容显示不全问题解决

默认情况下&#xff0c;当下拉框的内容长度过长时&#xff0c;会被折叠&#xff0c;这比较影响用户体验&#xff0c;查了下文档&#xff0c;看到有一个属性可以解决这个问题&#xff1a; 没设置的下拉效果&#xff1a; 设置完之后&#xff1a;dropdownMatchSelectWidth{false}&…

在Qt设计师(Qt Designer )控件面板加入自定义控件

目录 1. 问题的提出 2. 本次开发环境说明 3. 具体实现 4. 注意的问题 5. 参考链接 1. 问题的提出 在Qt开发中&#xff0c;经常利用Qt设计师&#xff08;Qt Designer &#xff09;把界面设计好&#xff0c;将界面放到ui文件中&#xff0c;将逻辑处理放到cpp文件中&#xff…

记录第一次利用CVE-2023-33246漏洞实现RocketMQ宿主机远程代码执行的兴奋

我依然记得自己第一次发现xss漏洞时候的兴奋: 我也记得自己第一次发现sql输入时候的快乐: 直到最近我终于收获了人生的第一个远程代码执行漏洞的利用&#xff08;RCE:remote code execute&#xff09;&#xff0c;虽然这个漏洞的危害远超过了前两个&#xff0c;但是快乐不如前…

基于非对称纳什谈判的多微网电能共享运行优化策略(附带MATLAB程序)

基于非对称纳什谈判的多微网电能共享运行优化策略MATLAB程序 参考文献&#xff1a; 《基于非对称纳什谈判的多微网电能共享运行优化策略》——吴锦领 资源地址&#xff1a; 基于非对称纳什谈判的多微网电能共享运行优化策略MATLAB程序 MATLAB代码&#xff1a;基于非对称纳什…

微信小程序:tabbar、事件绑定、数据绑定、模块化、模板语法、尺寸单位

目录 1. tabbar 1.1 什么是tabbar 1.2 配置tabbar 2. 事件绑定 2.1 准备表单 2.2 事件绑定 2.3 冒泡事件及非冒泡事件 3. 数据绑定 3.1 官方文档 4. 关于模块化 5. 模板语法 6. 尺寸单位 1. tabbar 1.1 什么是tabbar 下图中标记出来的部分即为tabbar&#xff1a…

2023年华为杯数学建模E题——代码复盘(第一问)

2023年华为杯数学建模E题 代码复盘 写在最前面目录问题1a计算时间间隔思路说明代码输出结果 插值求解思路代码输出结果 绘图绘制3D图&#xff08;待修改&#xff09; 问题1b数据预处理思路代码 模型训练思路代码输出结果网格调参代码输出结果 写在最前面 超开心又有点遗憾 结果…

matlab二维曲面散点图插值方法

在 MATLAB 中&#xff0c;你可以使用以下函数进行二维曲面散点插值&#xff1a; griddata: 该函数可以在散点数据上进行二维插值&#xff0c;生成平滑的曲面。它支持多种插值方法&#xff0c;包括三次样条插值、最近邻插值、线性插值和自然邻近法插值。 scatteredInterpolant:…

《RT-DETR魔术师》专栏介绍 CSDN独家改进创新实战 专栏目录

RT-DETR魔术师专栏介绍&#xff1a; https://blog.csdn.net/m0_63774211/category_12497375.html ✨✨✨魔改创新RT-DETR &#x1f680;&#x1f680;&#x1f680;引入前沿顶会创新&#xff08;CVPR2023&#xff0c;ICCV2023等&#xff09;&#xff0c;助力RT-DETR &#…

专题知识点-二叉树-(非常有意义的一篇文章)

这里写目录标题 二叉树的基础知识知识点一(二叉树性质 )树与二叉树的相互转换二叉树的遍历层次优先遍历树的深度和广度优先遍历中序线索二叉树二叉树相关遍历代码顺序存储和链式存储二叉树的遍历二叉树的相关例题左右两边表达式求值求树的深度找数找第k个数二叉树非递归遍历代码…

微信小程序 生命周期方法 页面路由 开发示例 自定义全局数据 链接跳转

目录 1. 生命周期方法 2. 页面路由 3. 开发示例 3.1 自定义全局数据 3.2 链接跳转 1. 生命周期方法 打开app.js Page生命周期函数 下面的Page生命周期图与上面的Page生命周期函数进行对比便于理解&#xff1a; 视图线程和应用服务线程会同时运行&#xff0c;应用服务线程…

微信个人号api接口开发

请求URL&#xff1a; http://域名地址/sendFile 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明wId是string登录实例标识wcId是string接收…

【保姆级教程】Linux安装JDK8

本文以centos7为例&#xff0c;一步一步进行jdk1.8的安装。 1. 下载安装 官网下载链接&#xff1a; https://www.oracle.com/cn/java/technologies/downloads/#java8 上传jdk的压缩包到服务器的/usr/local目录下 在当前目录解压jdk压缩包&#xff0c;如果是其它版本&#xf…

Nessus漏洞扫描工具

Nessus 1、官网下载安装包2、centos7 安装Nessus3、启动Nessus4、网页访问88435、离线激活工具6、其他问题7、漏洞扫描使用 Nessus 是全世界最多人使用的系统漏洞扫描与分析软件。总共有超过75,000个机构使用Nessus 作为扫描该机构电脑系统的软件。 1、官网下载安装包 官网下载…

【Linux】Ubuntu16.04下完美安装python高版本及对应版本的pip

Ubuntu16.04下完美安装python高版本及对应版本的pip 方法一:直接用命令安装python3.6&#xff08;但我没安装成功&#xff09; 好像是因为Ubuntu16.04的软件仓库&#xff08;源&#xff09;中python的最高版本就是python3.5&#xff0c;所以无法直接用apt来安装 #方法一 sudo…

【开源】基于Vue.js的校园失物招领管理系统的设计和实现

目录 一、摘要1.1 项目介绍1.2 项目详细录屏 二、研究内容2.1 招领管理模块2.2 寻物管理模块2.3 系统公告模块2.4 感谢留言模块 三、界面展示3.1 登录注册3.2 招领模块3.3 寻物模块3.4 公告模块3.5 感谢留言模块3.6 系统基础模块 四、免责说明 一、摘要 1.1 项目介绍 基于Vue…

【软考篇】中级软件设计师 第二部分(一)

中级软件设计师 第二部分&#xff08;一&#xff09; 八. 层次化结构8.1 局部性原理8.2 体系8.3 分类8.3.1 存取方式8.3.2 工作方式 8.4 Cache8.4.1 例题 8.5 地址映像 九. 主存编址9.1 例题一 十. 可靠性10.1 串联系统和并联系统 十一. 网络安全11.1 保密性11.2 完整性&#x…

金财数科无代码开发平台:轻松实现电商、CRM、广告推广系统的集成连接

连接与集成&#xff1a;挖掘电商平台的潜力 金财数科是一家领先的信息技术公司&#xff0c;专注于利用前沿技术如互联网、人工智能、大数据和区块链等&#xff0c;为传统财税信息化方案和产品提供升级改造&#xff0c;并打造新一代智能财税SaaS平台。我们的目标是帮助企业通过…

Python接口测试框架选择之pytest+yaml+Allure!

一、为什么选择pytest&#xff1f; pytest完全兼容python自带的unittest pytest让单元测试更简单&#xff0c;能很好的管理测试用例。 对于实现接口测试的复杂场景&#xff0c;pytest的fixture、PDB等高阶用法都能实现需求。 入门简单&#xff0c;对于代码基础薄弱的团队人…