👨💻个人主页:@元宇宙-秩沅
👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!
👨💻 本文由 秩沅 原创
👨💻 收录于专栏:Unity基础实战
⭐🅰️⭐
⭐效果演示⭐
🎶(1) 添加分辨率
🎶(2)生成地图
普通矩形地图生成
菱形矩形地图生成
- 单排生成
- 双排铺满
⭐⭐
- 添加缓存池的本质其实就是资源的循环利用,减少多次CG。也就是说,当我们需要销毁一个物体的时候我们需要用到的story,但是多次的destroy,它会触发我们的CG回收,那此时我们如果说用一个列表或者是字典。形成了一个缓存池,让他临时存放,我们需要多次销毁的一个物体的话,那么它就避免了多次产生C机的回收机制。此时我们可以选择让存进去的物体失活,需要的时候再激活,把它存取出来,让就可以进行一个循环的利用。
🎶(3) 未添加缓存池之前
🎶(4) 添加缓存池后
🎶(5)缓存池 脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// 抽屉数据
/// </summary>
public class PoolData
{
//抽屉中 对象挂载的父节点
public GameObject fatherObj;
//对象的容器
public List<GameObject> poolList;
public PoolData(GameObject obj, GameObject poolObj)
{
//给我们的抽屉 创建一个父对象 并且把他作为我们pool(衣柜)对象的子物体
fatherObj = new GameObject(obj.name);
fatherObj.transform.parent = poolObj.transform;
poolList = new List<GameObject>() {};
PushObj(obj);
}
/// <summary>
/// 往抽屉里面 压都东西
/// </summary>
/// <param name="obj"></param>
public void PushObj(GameObject obj)
{
//失活 让其隐藏
//obj.SetActive(false); //可放在外部去激活
//存起来
poolList.Add(obj);
//设置父对象
obj.transform.parent = fatherObj.transform;
}
/// <summary>
/// 从抽屉里面 取东西
/// </summary>
/// <returns></returns>
public GameObject GetObj(Transform parent) //参数为需要设置的父对象
{
GameObject obj = null;
//取出第一个
obj = poolList[0];
//对物体的Y轴进行约束
obj.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezePositionY;
poolList.RemoveAt(0);
//激活 让其显示
obj.SetActive(true);
//断开了父子关系
obj.transform.SetParent(parent);
return obj;
}
}
/// <summary>
/// 缓存池模块
/// </summary>
public class PoolManager : SingleManager <PoolManager>
{
//缓存池容器 (衣柜)
public Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();
private GameObject poolObj;
/// <summary>
/// 从缓存池中拿东西
/// </summary>
/// <param name="名字"></param>
/// <param parent="挂载的父对象"></param>
/// <param position="实例化的位置"></param>
/// <param rotation="实例化的角度"></param>
/// <param callBack="委托"></param>
public void GetObj(string name, Transform parent, UnityAction<GameObject> callBack) //第三个参数为挂载的父对象
{
if(poolDic.ContainsKey(name) && poolDic[name].poolList.Count > 0)
{
callBack(poolDic[name ].GetObj(parent));
}
else
{
//同步加载
GameObject obj = GameObject.Instantiate(ResManager.GetInstance().Load<GameObject>("prefabs/" + name));
obj.name = name;
callBack(obj); //返回实例化的物品给委托
通过异步加载资源 创建对象给外部用
//ResManager .GetInstance().LoadAsync<GameObject>("prefabs/"+name, (o) =>
//{
// o.name = name;
// callBack(o);
//});
//obj = GameObject.Instantiate(Resources.Load<GameObject>(name));
//把对象名字改的和池子名字一样
//obj.name = name;
}
}
/// <summary>
/// 换暂时不用的东西给池子
/// </summary>
public void PushObj(string name, GameObject obj)
{
if (poolObj == null)
poolObj = new GameObject("Pool");
//里面有抽屉
if (poolDic.ContainsKey(name))
{
poolDic[name].PushObj(obj);
}
//里面没有抽屉
else
{
poolDic.Add(name, new PoolData(obj, poolObj));
}
}
/// <summary>
/// 清空缓存池的方法
/// 主要用在 场景切换时
/// </summary>
public void Clear()
{
poolDic.Clear();
poolObj = null;
}
}
🎶(6)简单的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);
}
}
}
}
}
🎶(7)prime算法生成的效果
迷宫相对比较自然,但迷宫的分岔路会比较多,适合生成错综复杂的地图效果,主路不是特别明显
-
初始化大地图,0代表墙,1代表道路,墙为地图边缘包裹
-
靠近地图边缘随机选取状态为1的道路点,作为出生点a
-
然后将 a 点周围所有的墙体点标记为待检测点,加入到待检测集合
-
从待检测集合随机取一个点 b ,判断顺着它方向的下一个点 c,是否是道路
-
如果是,则将这个待检测点墙体打通,将其移出待检测集合;将下一个点 c作为新的起点,重新执行第3步
-
如果不是就把这个待检测点移出待检测集合,重新作为墙体点
不断重复,直到待检测集合全部检查过,重新为空
⭐🅰️⭐
⭐🅰️⭐
⭐【Unityc#专题篇】之c#进阶篇】
⭐【Unityc#专题篇】之c#核心篇】
⭐【Unityc#专题篇】之c#基础篇】
⭐【Unity-c#专题篇】之c#入门篇】
⭐【Unityc#专题篇】—进阶章题单实践练习
⭐【Unityc#专题篇】—基础章题单实践练习
⭐【Unityc#专题篇】—核心章题单实践练习
你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!、文章来源:https://www.toymoban.com/news/detail-841550.html
文章来源地址https://www.toymoban.com/news/detail-841550.html
到了这里,关于【Unity之竖屏游戏制作】如何做一个竖屏的手机游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!