淘宝上如何免费开网店,seo百度排名优化,施工企业三金压降指的是哪三金,新手有关网站建设需要看哪些书文章目录 先看看最终效果前言随机游走算法使用随机游走算法添加地板瓦片1. 新增TilemapVisualizer#xff0c;用于可视化地图2. 瓦片素材 不运行执行程序化生成地牢方法1. 先简单重构代码2. 新增Editor脚本RandomDungeonGeneratorEditor 将参数保存到可编辑脚本对象#xff0… 文章目录 先看看最终效果前言随机游走算法使用随机游走算法添加地板瓦片1. 新增TilemapVisualizer用于可视化地图2. 瓦片素材 不运行执行程序化生成地牢方法1. 先简单重构代码2. 新增Editor脚本RandomDungeonGeneratorEditor 将参数保存到可编辑脚本对象ScriptableObject1. 定义简单随机行走数据的 ScriptableObject 类2. 配置不同的地形参数3. 调用4. 效果 生成墙壁补充源码完结 先看看最终效果 前言
关于使用TileMap生成随机2D地图其实之前已经有做过类似的感兴趣可以看看 【unity实战】随机地下城生成 【unity小技巧】Unity2D TileMap柏林噪声生成随机地图
但是随着学习深入发现之前做的比较粗糙和不够全面最近又在外网看到一个程序化生成2D地牢的视频觉得不错所以写了这一篇学习笔记记录分享一下。
本项目可能比较长会分几期来讲感兴趣的可以关注一下方便获取后续内容本期主要是使用随机游走算法生成随机的地牢房间。
随机游走算法
新增
/// summary
/// 静态类包含用于二维环境的程序化生成算法。
/// /summary
public static class ProceduralGenerationAlgorithms
{/// summary/// 在二维空间中生成简单的随机行走路径。/// /summary/// param namestartPosition行走的起始位置。/param/// param namewalkLength行走步数。/param/// returns表示所走路径的 Vector2Int 的 HashSet。/returnspublic static HashSetVector2Int SimpleRandomWalk(Vector2Int startPosition, int walkLength){// 创建路径 HashSetHashSetVector2Int path new HashSetVector2Int();// 将起始位置添加到路径 HashSet 中path.Add(startPosition);// 将当前位置设置为起始位置var previousPosition startPosition;// 沿着随机方向移动将每个新位置添加到路径 HashSet 中for (int i 0; i walkLength; i){var newPosition previousPosition Direction2D.GetRandomCardinalDirection();path.Add(newPosition);previousPosition newPosition;}// 返回路径 HashSetreturn path;}
}/// summary
/// 静态类包含二维方向性工具。
/// /summary
public static class Direction2D
{/// summary/// 二维空间中基本方向的列表。/// /summarypublic static ListVector2Int cardinalDirectionsList new ListVector2Int{new Vector2Int(0,1), //上new Vector2Int(1,0), //右new Vector2Int(0, -1), // 下new Vector2Int(-1, 0) //左};/// summary/// 从列表中返回一个随机的基本方向。/// /summary/// returns表示随机基本方向的 Vector2Int。/returnspublic static Vector2Int GetRandomCardinalDirection(){return cardinalDirectionsList[UnityEngine.Random.Range(0, cardinalDirectionsList.Count)];}
}使用随机游走算法
新增SimpleRandomWalkDungeonGenerator 用于生成简单随机行走地牢的类
/// summary
/// 用于生成简单随机行走地牢的类继承自 MonoBehaviour。
/// /summary
public class SimpleRandomWalkDungeonGenerator : MonoBehaviour
{[SerializeField, Header(地牢生成的起始位置)]protected Vector2Int startPosition Vector2Int.zero;[SerializeField, Header(迭代次数)]private int iterations 10;[SerializeField, Header(每次行走的步数)]public int walkLength 10;[SerializeField, Header(每次迭代是否随机起始位置)]public bool startRandomlyEachIteration true;/// summary/// 执行程序化生成地牢的方法。/// /summarypublic void RunProceduralGeneration(){HashSetVector2Int floorPositions RunRandomWalk(); // 获取地牢地板坐标集合foreach (var position in floorPositions){Debug.Log(position); // 输出地板坐标信息}}/// summary/// 执行随机行走算法生成地牢地板坐标的方法。/// /summary/// returns地牢地板坐标的 HashSet。/returnsprotected HashSetVector2Int RunRandomWalk(){var currentPosition startPosition; // 当前位置初始化为起始位置HashSetVector2Int floorPositions new HashSetVector2Int(); // 地板坐标的 HashSetfor (int i 0; i iterations; i){var path ProceduralGenerationAlgorithms.SimpleRandomWalk(currentPosition, walkLength); // 生成随机行走路径floorPositions.UnionWith(path); // 将路径添加到地板坐标集合中if (startRandomlyEachIteration){currentPosition floorPositions.ElementAt(Random.Range(0, floorPositions.Count)); // 如果需要每次迭代随机起始位置则随机选择一个已生成的位置}}return floorPositions; // 返回地板坐标集合}
}挂载脚本 配置点击事件
效果
添加地板瓦片
1. 新增TilemapVisualizer用于可视化地图
/// summary
/// 用于可视化地图的 TilemapVisualizer 类继承自 MonoBehaviour。
/// /summary
public class TilemapVisualizer : MonoBehaviour
{[SerializeField]private Tilemap floorTilemap; // 地板瓦片地图[SerializeField]private TileBase floorTile; // 地板瓦片/// summary/// 绘制地板瓦片的方法。/// /summary/// param namefloorPositions地板位置的坐标集合。/parampublic void PaintFloorTiles(IEnumerableVector2Int floorPositions){PaintTiles(floorPositions, floorTilemap, floorTile);}/// summary/// 绘制瓦片的方法。/// /summary/// param namepositions瓦片位置的坐标集合。/param/// param nametilemap瓦片地图。/param/// param nametile要绘制的瓦片。/paramprivate void PaintTiles(IEnumerableVector2Int positions, Tilemap tilemap, TileBase tile){foreach (var position in positions){PaintSingleTile(tilemap, tile, position);}}/// summary/// 绘制单个瓦片的方法。/// /summary/// param nametilemap瓦片地图。/param/// param nametile要绘制的瓦片。/param/// param nameposition瓦片的位置坐标。/paramprivate void PaintSingleTile(Tilemap tilemap, TileBase tile, Vector2Int position){var tilePosition tilemap.WorldToCell((Vector3Int)position); // 将位置坐标转换为瓦片地图上的单元格坐标tilemap.SetTile(tilePosition, tile); // 在指定位置绘制瓦片}// 清空瓦片地图public void Clear(){floorTilemap.ClearAllTiles();}
}修改SimpleRandomWalkDungeonGenerator执行程序化生成地牢的方法
[SerializeField]
private TilemapVisualizer tilemapVisualizer;/// summary
/// 执行程序化生成地牢的方法。
/// /summary
public void RunProceduralGeneration()
{HashSetVector2Int floorPositions RunRandomWalk(); // 获取地牢地板坐标集合tilemapVisualizer.Clear();// 清空瓦片地图tilemapVisualizer.PaintFloorTiles(floorPositions);
}2. 瓦片素材
https://pixel-poem.itch.io/dungeon-assetpuck
挂载脚本配置参数
效果
不运行执行程序化生成地牢方法 每次测试都要运行程序再执行生成地图非常的麻烦我们可以实现不运行也可以执行程序化生成地牢的方法 1. 先简单重构代码
新增AbstractDungeonGenerator定义抽象地牢生成器的基类
/// summary
/// 抽象地牢生成器的基类继承自 MonoBehaviour。
/// /summary
public abstract class AbstractDungeonGenerator : MonoBehaviour
{[SerializeField, Header(瓦片可视化器)]protected TilemapVisualizer tilemapVisualizer null;[SerializeField, Header(地牢生成的起始位置)]protected Vector2Int startPosition Vector2Int.zero;/// summary/// 生成地牢的方法。/// /summarypublic void GenerateDungeon(){tilemapVisualizer.Clear(); // 清空瓦片可视化器RunProceduralGeneration(); // 执行程序化生成}/// summary/// 执行程序化生成地牢的抽象方法需要在子类中实现具体逻辑。/// /summaryprotected abstract void RunProceduralGeneration();
}修改SimpleRandomWalkDungeonGenerator
public class SimpleRandomWalkDungeonGenerator : AbstractDungeonGenerator
{//。。。// [SerializeField, Header(地牢生成的起始位置)]// protected Vector2Int startPosition Vector2Int.zero;// [SerializeField]// private TilemapVisualizer tilemapVisualizer;/// summary/// 执行程序化生成地牢的方法。/// /summaryprotected override void RunProceduralGeneration(){HashSetVector2Int floorPositions RunRandomWalk(); // 获取地牢地板坐标集合tilemapVisualizer.Clear();tilemapVisualizer.PaintFloorTiles(floorPositions);}//。。。
}修改点击事件 运行测试一切正常
2. 新增Editor脚本RandomDungeonGeneratorEditor /// summary
/// 自定义编辑器类用于 RandomDungeonGenerator。
/// /summary
[CustomEditor(typeof(AbstractDungeonGenerator), true)]
public class RandomDungeonGeneratorEditor : Editor
{private AbstractDungeonGenerator generator; // 地牢生成器对象private void Awake(){generator (AbstractDungeonGenerator)target; // 获取目标对象并转换为地牢生成器类型}/// summary/// 在 Inspector 窗口中绘制自定义的 GUI。/// /summarypublic override void OnInspectorGUI(){base.OnInspectorGUI(); // 绘制基类的默认 Inspector 界面if (GUILayout.Button(Create Dungeon)) // 创建地牢的按钮{generator.GenerateDungeon(); // 调用地牢生成器的方法生成地牢}}
}效果
将参数保存到可编辑脚本对象ScriptableObject
1. 定义简单随机行走数据的 ScriptableObject 类
新增SimpleRandomWalkSO
/// summary
/// 简单随机行走数据的 ScriptableObject 类。
/// /summary
[CreateAssetMenu(fileName SimpleRandomWalkParameters_, menuName PCG/SimpleRandomWalkData)]
public class SimpleRandomWalkSO : ScriptableObject
{[Header(迭代次数)]public int iterations 10;[Header(每次行走的步数)]public int walkLength 10;[Header(每次迭代是否随机起点)]public bool startRandomlyEachIteration true;
}2. 配置不同的地形参数
配置不同的参数
3. 调用
修改SimpleRandomWalkDungeonGenerator调用前面定义的参数
[SerializeField]
private SimpleRandomWalkSO randomWalkParameters;4. 效果
大地牢 小地牢 岛
生成墙壁
新增WallGenerator墙体生成器的静态类
/// summary
/// 墙体生成器的静态类。
/// /summary
public static class WallGenerator
{/// summary/// 创建墙体的方法。/// /summary/// param namefloorPositions地板位置的集合/param/// param nametilemapVisualizer瓦片可视化器/parampublic static void CreateWalls(HashSetVector2Int floorPositions, TilemapVisualizer tilemapVisualizer){var basicWallPositions FindWallsInDirections(floorPositions, Direction2D.cardinalDirectionsList);// 在每个墙体位置上绘制基本墙体foreach (var position in basicWallPositions){tilemapVisualizer.PaintSingleBasicWall(position);}}/// summary/// 在指定方向上查找墙体的方法。/// /summary/// param namefloorPositions地板位置的集合/param/// param namedirectionList方向列表/param/// returns墙体位置的集合/returnsprivate static HashSetVector2Int FindWallsInDirections(HashSetVector2Int floorPositions, ListVector2Int directionList){HashSetVector2Int wallPositions new HashSetVector2Int();foreach (var position in floorPositions){foreach (var direction in directionList){var neighbourPosition position direction;// 如果邻居位置不在地板位置集合中则认为是墙体位置if (!floorPositions.Contains(neighbourPosition)){wallPositions.Add(neighbourPosition);}}}return wallPositions;}
}修改TilemapVisualizer
[SerializeField, Header(墙壁瓦片地图)]
private Tilemap wallTilemap;
[SerializeField, Header(墙壁瓦片)]
private TileBase wallTop;//绘制墙壁瓦片的方法
internal void PaintSingleBasicWall(Vector2Int position)
{PaintSingleTile(wallTilemap, wallTop, position);
}修改SimpleRandomWalkDungeonGenerator
/// summary
/// 执行程序化生成地牢的方法。
/// /summary
protected override void RunProceduralGeneration()
{HashSetVector2Int floorPositions RunRandomWalk(); // 获取地牢地板坐标集合tilemapVisualizer.PaintFloorTiles(floorPositions);//绘制地板瓦片WallGenerator.CreateWalls(floorPositions, tilemapVisualizer);//创建墙体
}// 清空瓦片地图
public void Clear()
{floorTilemap.ClearAllTiles();wallTilemap.ClearAllTiles();
}配置参数 效果
补充
想要优化墙壁的显示可以选择使用rule tile绘制墙壁内容不懂得可以看我这篇文章写的比较详细【Unity小技巧】Unity2D TileMap的探究
还不懂的也可以看我后面的文章后面会讲到
源码
源码会放在本项目最后一篇
完结
赠人玫瑰手有余香如果文章内容对你有所帮助请不要吝啬你的点赞评论和关注以便我第一时间收到反馈你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法也欢迎评论私信告诉我哦
好了我是向宇https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者出于兴趣爱好于是最近才开始自习unity。如果你遇到任何问题也欢迎你评论私信找我 虽然有些问题我可能也不一定会但是我会查阅各方资料争取给出最好的建议希望可以帮助更多想学编程的人共勉~