首页 > 其他分享 >Episode 11

Episode 11

时间:2023-03-21 11:12:34浏览次数:38  
标签:11 Episode int mapSize Vector3 Transform new public

Map Navigation——地图烘培

MapGenerator

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class MapGenerator : MonoBehaviour
{
    public Transform tilePrefab;//瓦片预制体
    public Transform obstaclePrefab;//障碍物预制体
    public Transform navmeshMaskPrefab;//地图边界预制体
    public Transform navmeshFloor;//地图
    public Vector2 mapSize;//地图尺寸
    public Vector2 maxMapSize;//地图最大尺寸

    [Range(0f, 1f)]
    public float outlinePercent;//瓦片间隙
    [Range(0f, 1f)]
    public float obstaclePercent;//障碍物比例

    public float tileSize;

    List<Coord> allTileCoords;//所有瓦片坐标
    Queue<Coord> shuffledTileCoords;//乱序后的瓦片坐标

    public int seed = 10;
    Coord mapCentre;

    void Start()
    {
        GenerateMap();
    }

    public void GenerateMap()
    {
        //记录所有瓦片位置
        allTileCoords = new List<Coord>();
        for (int x = 0; x < mapSize.x; x++)
        {
            for (int y = 0; y < mapSize.y; y++)
            {
                allTileCoords.Add(new Coord(x, y));
            }
        }
        //乱序后的瓦片坐标存为队列
        shuffledTileCoords = new Queue<Coord> (Utility.ShuffleArray(allTileCoords.ToArray(), seed));
        mapCentre = new Coord((int)mapSize.x / 2, (int)mapSize.y / 2);

        string holderName = "Generated Map";
        if (transform.Find(holderName))
        {
            DestroyImmediate(transform.Find(holderName).gameObject);
        }

        Transform mapHolder = new GameObject(holderName).transform;//创建Generated Map集合瓦片
        mapHolder.parent = transform;//将Generated Map父对象设置为为MapGenerator

        //循环创建瓦片
        for (int x = 0; x < mapSize.x; x++)
        {
            for (int y = 0; y < mapSize.y; y++)
            {
                Vector3 tilePosition = CoordToPosition(x,y);//居中
                Transform newTile = Instantiate(tilePrefab, tilePosition, Quaternion.Euler(Vector3.right * 90)) as Transform;
                newTile.localScale = Vector3.one * (1 - outlinePercent) * tileSize;
                newTile.parent = mapHolder;//将瓦片父对象设置为Generated Map
            }
        }

        //生成障碍物
        bool[,] obstacleMap = new bool[(int)mapSize.x, (int)mapSize.y];//障碍物地图二维bool形地图

        int obstacleCount = (int)(mapSize.x * mapSize.y * obstaclePercent);//障碍物数量
        int currentObstacleCount = 0;//当前障碍物数量

        for (int i = 0; i < obstacleCount; i++)
        {
            //先默认找到的一处位置可生成障碍物
            Coord randomCoord = GetRandomCoord();//获得队列中第一个的坐标
            obstacleMap[randomCoord.x, randomCoord.y] = true;
            currentObstacleCount++;

            if (randomCoord != mapCentre && MapIsFullyAccessible(obstacleMap, currentObstacleCount))//此处位置不为中心位置且能够生成障碍物
            {
                Vector3 obstaclePosition = CoordToPosition(randomCoord.x,randomCoord.y);//坐标到实际坐标转换

                Transform newObstacle = Instantiate(obstaclePrefab, obstaclePosition + Vector3.up * 0.5f, Quaternion.identity) as Transform;
                newObstacle.parent = mapHolder;//将障碍物父对象设置为Generated Map
                newObstacle.localScale = Vector3.one * (1 - outlinePercent) * tileSize;
            }
            else
            {
                obstacleMap[randomCoord.x,randomCoord.y] = false;
                currentObstacleCount--;
            }
        }
        //生成地图边界
        Transform maskLeft = Instantiate(navmeshMaskPrefab,Vector3.left * (mapSize.x + maxMapSize.x)/4 * tileSize, Quaternion.identity) as Transform;
        maskLeft.parent = mapHolder;
        maskLeft.localScale = new Vector3 ((maxMapSize.x - mapSize.x)/2, 1, mapSize.y) * tileSize;

        Transform maskRight = Instantiate(navmeshMaskPrefab, Vector3.right * (mapSize.x + maxMapSize.x) / 4 * tileSize, Quaternion.identity) as Transform;
        maskRight.parent = mapHolder;
        maskRight.localScale = new Vector3((maxMapSize.x - mapSize.x) / 2, 1, mapSize.y) * tileSize;

        Transform maskTop = Instantiate(navmeshMaskPrefab, Vector3.forward * (mapSize.y + maxMapSize.y) / 4 * tileSize, Quaternion.identity) as Transform;
        maskTop.parent = mapHolder;
        maskTop.localScale = new Vector3(maxMapSize.x, 1, (maxMapSize.y - mapSize.y) / 2) * tileSize;

        Transform maskBottom = Instantiate(navmeshMaskPrefab, Vector3.back * (mapSize.y + maxMapSize.y) / 4 * tileSize, Quaternion.identity) as Transform;
        maskBottom.parent = mapHolder;
        maskBottom.localScale = new Vector3(maxMapSize.x, 1, (maxMapSize.y - mapSize.y) / 2) * tileSize;

        navmeshFloor.localScale = new Vector3(maxMapSize.x, maxMapSize.y) * tileSize;
    }

    bool MapIsFullyAccessible(bool[,] obstacleMap, int currentObstacleCount)//采用四邻域洪水填充算法判断是否能够生成障碍物
    {
        bool[,] mapFlags = new bool[obstacleMap.GetLength(0),obstacleMap.GetLength(1)];

        Queue<Coord> queue = new Queue<Coord>();//所有的坐标都会“筛选后”储存在这个队列中,一一检测
        queue.Enqueue(mapCentre);
        mapFlags[mapCentre.x,mapCentre.y] = true;//中心点标记为【已检测】

        int accessibleTileCount = 1;//中心点一直为可行走

        while(queue.Count > 0 )//队列大于0,就一直检测下去
        {
            Coord tile = queue.Dequeue();//当前检测的需要被移除出来

            for (int x = -1; x <= 1; x++)//检测相邻四周坐标点X轴
            {
                for (int y = -1; y <= 1; y++)//检测相邻四周坐标点Y轴
                {
                    int neighbourX = tile.x + x;
                    int neighbourY = tile.y + y;
                    if (x == 0 || y == 0)//保证上下左右四个位置,排除对角线上的坐标位置
                    {
                        //防止相邻点超出地图临界位置
                        if (neighbourX >= 0 && neighbourX < obstacleMap.GetLength(0) && neighbourY >= 0 && neighbourY < obstacleMap.GetLength(1))
                        {
                            //保证相邻点:未被检测;未有障碍物
                            if (!mapFlags[neighbourX,neighbourY] && !obstacleMap[neighbourX,neighbourY])
                            {
                                mapFlags[neighbourX, neighbourY] = true;
                                queue.Enqueue(new Coord(neighbourX,neighbourY));
                                accessibleTileCount ++;
                            }
                        }
                    }
                }
            }
        }

        int targetAccessibleTileCount = (int)(mapSize.x * mapSize.y - currentObstacleCount);
        return targetAccessibleTileCount == accessibleTileCount;
    }

    //坐标到实际坐标转换
    Vector3 CoordToPosition(int x, int y)
    {
        return new Vector3(-mapSize.x / 2f + 0.5f + x, 0, -mapSize.y / 2f + 0.5f + y) * tileSize;
    }

    public Coord GetRandomCoord()
    {
        Coord randomCoord = shuffledTileCoords.Dequeue();//移除并返回在 Queue 的开头的对象。
        shuffledTileCoords.Enqueue(randomCoord);//向 Queue 的末尾添加一个对象。
        return randomCoord;
    }

    //定义每个瓦片坐标信息
    public struct Coord 
    {
        //Coord结构体存储坐标
        public int x;
        public int y;

        public Coord(int _x, int _y)
        {
            x = _x;
            y = _y;
        }

        public static bool operator ==(Coord a, Coord b) { return a.x == b.x&& a.y == b.y; }
        public static bool operator !=(Coord a, Coord b) { return !(a == b); }
    }
}

标签:11,Episode,int,mapSize,Vector3,Transform,new,public
From: https://www.cnblogs.com/Felix-Fu/p/17239253.html

相关文章

  • Episode 12
    FinishingtheMapGeneratorMapGeneratorusingSystem.Collections;usingSystem.Collections.Generic;usingUnity.VisualScripting;usingUnityEngine;publiccl......
  • Episode 08
    TileMap——地图MapGeneratorusingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassMapGenerator:MonoBehaviour{p......
  • Episode 09
    ObstaclePlacement——障碍物生成UtilityusingSystem.Collections;publicstaticclassUtility{//洗牌算法publicstaticT[]ShuffleArray<T>(T[]arra......
  • 力扣511(MySQL)-游戏玩法分析Ⅰ(简单)
    题目:活动表 Activity:写一条SQL 查询语句获取每位玩家 第一次登陆平台的日期。查询结果的格式如下所示:  解题思路:方法一:使用dense_rank()over(partitionby......
  • 113webpack
    WebpackWebpack是一个现代化的JavaScript应用程序打包工具,它可以将多个JavaScript文件、CSS、图片等资源打包成一个或多个静态资源文件,以便在网页中使用。Webpack在前端......
  • 深度学习入门9787115485588 Chapter3
    explaintheactivationfunctioninneuralnetworkwithanactualcaseanddemonstrateitinpythoncode Inaneuralnetwork,anactivationfunctionisusedt......
  • Windows 11 Update Download Error Solution - 0x80248007
    IhadthesameissueonaWindows2019virtualserverwhileperformingroutinewindowsupdates.Theinstructionswerespoton.Iran:netstopwuauservnetst......
  • 100道python基础题——(11)
    问题:编写一个程序,接受一系列逗号分隔的4位二进制数作为输入,然后检查它们是否可被5整除。可被5整除的数字将以逗号分隔的顺序打印。例:0100,0011,1010,1001那么输出应该是:10......
  • 11113344
    世界上没有一个静止不动的时刻,技术也在不断地变化,那么,作为开发者和博主,我们如何才能跟上时代的步伐?答案很简单,就是不被定义,不受限制,勇于追求自己想要成为的样子。人生当中,我......
  • [oeasy]python0112_扩展ascii_Extended_ascii_法文字符
    法文字符回忆上次内容上次回顾了字型编码的进化过程从7-seg到点阵字库终于让字母、数字、标点明确了字型小写字符占据了位置法文字符没有地方放了7-bit的ascii已......