Unity游戏教程初步(六):迷宫算法与预制体

目录

前言

项目需求

Prim算法生成迷宫

1 算法思路介绍

2 代码示例

3 用于测试的代码

预制体(预制件)

1 定义

2 构建迷宫墙体预制体

完善工程


前言

本节我们来做迷宫生成。生成迷宫的算法其实有很多种,最简单的比如递归。而这一节我们选择prim算法生成迷宫,因为这种算法生成的迷宫较为自然,并且算法原理简易。

项目需求

使用prim算法和预制体生成迷宫。

Prim算法生成迷宫

1 算法思路介绍

本部分中的所有图示采用RPG Maker XP建立。顺便吐槽一句,现在网上流传的有关prim算法生成迷宫的算法描述(那个据说来自维基的)简直是语文不及格产物。

Prim算法与图论有关(我在article105中介绍过基本的图搜索算法和一个使用Ruby书写的搜索模版),它最开始被用于在加权连通图里搜索一个最小生成树。个人认为它还有些像用堆实现的二叉树遍历算法。其具体资料请读者自行学习,笔者在此只给出一个用于迷宫生成场景下较为通俗的描述。

我们假设在区域内有一个N*M列的迷宫。对于迷宫的每个格子,它们只有两个状态:通路/墙。在初始状态下,这个迷宫里的所有格子都是墙。设定一个的类Wall,其数据为[Vector2Int pos, Vector2Int relative],也就是其位置向量pos与其相对格子的位置向量relative(在后续步骤中会解释)。同时,我们建立一个墙的空列表M。

Unity游戏教程初步(六):迷宫算法与预制体_第1张图片

然后我们选定一个起点A,将此位置的墙移除:

Unity游戏教程初步(六):迷宫算法与预制体_第2张图片

将与起点A相邻的所有墙加入M中,其中A作为这些墙的父格子。对于一面墙而言,我们称在其父格子另一边的格子为相对格子。它们的例子如图:

Unity游戏教程初步(六):迷宫算法与预制体_第3张图片

在M中随机选择一个元素x。对于x,如果其相对格子为墙,则移除相对格子和x的墙,然后将相对格子作为父格子,将相邻墙加入列表。否则则从M中移除x。如此循环直到M中为空。

2 代码示例

我们会创建一个墙的类Wall与生成迷宫的类Maze。

Wall.cs

public class Wall //内部类Wall

{

    public Vector2Int pos; //位置向量

    public Vector2Int relative; //相对格子向量

    public Wall(Vector2Int pos,Vector2Int anc){

        this.pos=pos;

        ancToRelative(anc);

    }

    public void ancToRelative(Vector2Int ancestor){ //输入一个父格子,求出其相对格子并赋值

        this.relative=pos*2-ancestor; //int不能左乘Vector2Int(因为这里的*是Vector2Int的运算符重载)

    }

}

Maze.cs

public class Maze //内部类Maze

{

    private Vector2Int[] e={new Vector2Int(1,0),new Vector2Int(-1,0),new Vector2Int(0,1),new Vector2Int(0,-1),}; //四方向

    private int width;

    private int height; //迷宫矩阵的宽和高 默认[宽,高],Maze位置的游标在<[0..width],[0..height]>

    private Vector2Int origin; //起点

    public List M; //list

    public List W; //list

    public List maze; //最终的迷宫列表

    public Maze(int width,int height,Vector2Int origin){

        this.width=width;

        this.height=height;

        this.origin=origin;

        this.M=new List();

        this.W=new List();

        this.maze=new List();

        this.maze.Add(origin);

    }

    bool findMaze(Vector2Int pos){ //只判断此位置是否已移除墙

        if(this.maze.Contains(pos)){

            return true;

        }

        return false;

    }

    bool borderExam(Vector2Int pos){ //边界检查

        if(pos.x>=0 &&pos.x=0 &&pos.y

在生成迷宫时,声明一个Maze类的实例并且调用其exec方法,就可得到一个迷宫。

3 用于测试的代码

此代码在Start方法内调用,可以在控制台生成一份迷宫示意图。

 string a="";

        Maze maze=new Maze(30,20,new Vector2Int(0,0));

        maze.exec();

        for(int i=0;i<30;i++){

            for(int j=0;j<20;j++){

                if(maze.maze.Contains(new Vector2Int(i,j))){

                    a=a+"-";

                }

                else{

                    a=a+"#";

                }

            }

            a=a+"\n";

        }

        print(a);

预制体(预制件)

-本节相关内容请读者参考:

-预制件 - Unity 手册,《预制件》

-Object-Instantiate - Unity 脚本 API,《Object.Instantiate

1 定义

预制体(英文为prefab,在unity手册中被称为预制件)可以看做是一个文件化的游戏对象,一个已经构建好了的样板。如果从编程的角度进行类比,预制体可以被看成一个用于派生类的基类,或者是一个单纯的被复制对象。预制体以实体文件(.prefab)的形式存在于unity中,并可以在有需要时动态加载进游戏场景。

预制体通常被应用于如下两个场景中:一,被经常使用的游戏对象(比如森林场景中的一棵树);二,在场景被加载时不应当存在于场景中的游戏对象(比如说闯关游戏中的通关画面)。

2 构建迷宫墙体预制体

首先确认预制体的形状和大小。由于迷宫的场地是正方形的,我们采用以正方形为底的四棱柱作为预制体的形状,则底边长设定为scale1单位,高度为scale2单位。

创建一个Cube,调整其大小和位置直到满足上文中的条件。然后,重命名Cube为prefab,选中prefab并将其拖动到Project选项卡下的游戏资源文件夹内部,可以看到出现了一个同名文件,即为预制体。

Unity游戏教程初步(六):迷宫算法与预制体_第4张图片

将预制体文件拖动到Hierarchy选项卡下,可以看到预制体又出现在场景中了。需要注意的是,如果要编辑预制体文件本身,请点击预制体右边的“>”,在场景中直接编辑的不是预制体,而只是其的一个副本。预制体在场景中以蓝色显示。

Unity游戏教程初步(六):迷宫算法与预制体_第5张图片

完善工程

将目的区域的大小调整到与球体相同的水平,也就是scale0.1大小(顺便要调整变色和音效生效的区域)。

创建一个空游戏对象MazeController,搭载用于生成迷宫的脚本MazeController.cs。

敲代码。

MazeController.cs

using System.Collections;

using System.Collections.Generic;

using System.Text;

using System.Threading.Tasks;

using UnityEngine;

using Random=UnityEngine.Random;

public class Wall //内部类Wall

{

    public Vector2Int pos; //位置向量

    public Vector2Int relative; //相对格子向量

    public Wall(Vector2Int pos,Vector2Int anc){

        this.pos=pos;

        ancToRelative(anc);

    }

    public void ancToRelative(Vector2Int ancestor){ //输入一个父格子,求出其相对格子并赋值

        this.relative=pos*2-ancestor; //int不能左乘Vector2Int(因为这里的*是Vector2Int的运算符重载)

    }

}

public class Maze //内部类Maze

{

    private Vector2Int[] e={new Vector2Int(1,0),new Vector2Int(-1,0),new Vector2Int(0,1),new Vector2Int(0,-1),}; //四方向

    private int width;

    private int height; //迷宫矩阵的宽和高 默认[宽,高],Maze位置的游标在<[0..width],[0..height]>

    private Vector2Int origin; //起点

    public List M; //list

    public List W; //list

    public List maze; //最终的迷宫列表

    public Maze(int width,int height,Vector2Int origin){

        this.width=width;

        this.height=height;

        this.origin=origin;

        this.M=new List();

        this.W=new List();

        this.maze=new List();

        this.maze.Add(origin);

    }

    bool findMaze(Vector2Int pos){ //只判断此位置是否已移除墙

        if(this.maze.Contains(pos)){

            return true;

        }

        return false;

    }

    bool borderExam(Vector2Int pos){ //边界检查

        if(pos.x>=0 &&pos.x=0 &&pos.y

运行游戏,如图所示:

Unity游戏教程初步(六):迷宫算法与预制体_第6张图片

你可能感兴趣的:(算法与加密,unity,算法,游戏引擎,prim)