基于包围萝卜地图制作
在游戏开发中,很多的时候需要进行动态绘制地图以及格子的样式、我们通常是 使用for循环等等进行绘制、
首先是捋一下思路、我们既然是画格子的话首先有几个问题,怎么画?画在哪儿?画多大…这些都是问题?那么接下来一步一步解决;
首先我们需要拿到地图、格子的宽高才能对其进行操作。由于作者这里是有一张背景板的,且铺满了整个相机的渲染,所以就是直接计算整个 Camera 的宽高,接下来就是使用比例进行计算,左下角就是一个三维向量Vector3(0,0,0),Vector3其实是一个结构体类型的类,右上角的话就是一个Vector(1,1,1)
再往下面走就是将整个视口坐标转换为世界坐标系,Camera.main.ViewportToWorldPoint(leftDown);
这边的话使用到了一个视口坐标转世界坐标系 API,设计到了3D数学,需要注意的一点就是,Unity 标记其中主相机 Camera 的Tag 必须设置为 Camera,因为作者这里出现了空指针的情况。。。
有了这些数据之后我们就能够得到 地图以及格子的宽高了,
OK,这些都完成了以后我们相当于拿到了内部一手数据、接下来就是进行画线工作了。这边的话使用到了一个这样的函数,OnDrawGizmos():在每一帧都进行调用。
接下来就是画出行数以及列数
行数:首先是拿到格子以及地图的大小信息,然后使用 for 循环,从 0 开始、结束的时候为总共的行数,注意的一点是要包含总共的行数,如果不包含的话那么最后一行的线条是没有办法进行显示出来的。循环体里面的就是从哪里开始到哪里结束。使用两个 Vector3 记录起始点 以及 终点、
起始位置的 x 轴 = - 地图宽 / 2
y 轴 = -地图高 / 2 + y(循环变量) * 格子高
终点位置 x轴 = 地图宽 / 2
y 轴 = -地图的宽 / 2 + 总行数 * 格子的高
然后就是 使用一个 Gizmos.DrawLine(startPos,endPos)传入两个参数 开始进行画线。
列数:依然使用一个for 循环,从 0开始,最大值为总列数,每次进行自增,需要注意的是要包含总共的列数,如果不包含的话那么最后一列的线条是没有办法进行显示出来的
起始位置的 x 轴 = - 地图宽 / 2 + 格子的宽度 * x(循环变量)
y轴 = 地图高 / 2
终点位置 x 轴 = - 地图宽 / 2 + x(循环变量) * 格子宽
y轴 = -地图的高 / 2
然后就是 使用一个 Gizmos.DrawLine() 开始进行画线。
OK这些都完成了以后就是生成地图预制件了,首先是拿到地图、格子的宽高。然后嵌套 for 循环,行数为最大行数、列数为最大列数,然后就是生成格子对象,并且设置属性,设置属性这里有一个问题,就是如果你直接将所有的预制件都设置的一个游戏物体下面的话,整个物体都会堆起来,这样明显就不是想要的效果了,所以需要一个方法,返回一个新的位置
预制件的起始位置 x 轴为: x(行数循环体) * 格子的宽度 - 地图宽 / 2 + 格子宽 / 2
y轴为:y(列数循环体)* 格子的高度 - 地图高 / 2 + 格子高 / 2
然后在Awake()方法中进行调用即可:
//==========================
// - FileName: MapMaker.cs
// - Created: true.
// - CreateTime: 2020/03/16 14:27:09
// - Email: 1670328571@qq.com
// - Region: China WUHAN
// - Description: 地图格子的拼写
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapMaker : MonoBehaviour
{
//开关属性、画线开关
public bool drawLine;
//地图宽
private float mapWidth;
//高
private float mapHeight;
//格子宽
private float gridWidth;
//格子高
private float gridHeight;
//行数
public const int yRow = 8;
//列数
public const int xColumn = 12;
//塔的添加点
public GameObject gridGo;
//在游戏中不是单例、在工具中才是单例
private static MapMaker _instance;
public static MapMaker Instance
{
get
{
return _instance;
}
}
private void Awake()
{
_instance = this;
InitMap();
}
//初始化地图
public void InitMap()
{
CalculateSize();
//生成格子
for (int x = 0; x < xColumn; x++)
{
for (int y = 0; y < yRow; y++)
{
//生成格子对象
GameObject itemGo = Instantiate(gridGo, transform.position, transform.rotation);
//设置属性
itemGo.transform.position = CorretPositon(x * gridWidth, y * gridHeight);
itemGo.transform.SetParent(transform);
}
}
}
//纠正预制件的起始位置
public Vector3 CorretPositon(float x,float y)
{
return new Vector3(x - mapWidth / 2 + gridWidth / 2, y- mapHeight / 2 + gridHeight / 2);
}
//计算地图格子的宽高
private void CalculateSize()
{
//左下角
Vector3 leftDown = new Vector3(0, 0);
//右上角
Vector3 rightUp = new Vector3(1, 1);
//视口坐标转世界坐标 、 左下角的世界坐标
Vector3 posOne = Camera.main.ViewportToWorldPoint(leftDown);
//右上角
Vector3 posTwo = Camera.main.ViewportToWorldPoint(rightUp);
//地图宽
mapWidth = posTwo.x - posOne.x;
Debug.Log("地图的宽度" + mapWidth);
//地图高
mapHeight = posTwo.y - posOne.y;
//格子的宽
gridWidth = mapWidth / xColumn;
//格子高
gridHeight = mapHeight / yRow;
}
//画格子
private void OnDrawGizmos()
{
Debug.Log("开始画格子");
//画线
if (drawLine)
{
//计算格子的大小
CalculateSize();
//格子的颜色
Gizmos.color = Color.green;
//画出行数 这里的值应该是要等于行数的
for (int y = 0; y <= yRow; y++)
{
//起始位置
Vector3 startPos = new Vector3(-mapWidth / 2, -mapHeight / 2 + y * gridHeight);
//终点坐标
Vector3 endPos = new Vector3(mapWidth / 2, -mapHeight / 2 + y * gridHeight);
//画线
Gizmos.DrawLine(startPos, endPos);
}
//画列
for (int x = 0; x <= xColumn; x++)
{
Vector3 startPos = new Vector3(-mapWidth / 2 + gridWidth * x, mapHeight / 2);
Vector3 endPos = new Vector3(-mapWidth / 2 + x * gridWidth, -mapHeight / 2);
Gizmos.DrawLine(startPos, endPos);
}
}
else
{
return;
}
}
}
最后看下效果