塔防游戏中的网格制作小教程
在大多数塔防游戏里,当玩家进行单位建造操作时,可建造区域会显示出网格。玩家选择创建某个单位后,将鼠标移至特定网格,该网格会进入选中状态,随后玩家就能在这个格子里创建单位。今天,我研究了一个塔防插件,并把其中的网格部分分离出来,制作了这个小教程,分享给大家。
开始前的Unity知识储备
在正式开始制作之前,我们先了解一些Unity中的关键知识:
- 单位大小关系:在Unity里,
Plane的单位大小是Cube的十倍。 - 网格绘制方法:在
Plane上贴上带有透明通道的图片,然后通过设置纹理的偏移量和缩放量来绘制网格。 - 网格判断方式:通过射线来判断当前所处的网格,示例代码如下:
Ray ray = Camera.main.ScreenPointToRay (mousePos); RaycastHit hit;
在Unity中制作网格的步骤
1. 创建游戏对象并设置纹理参数
新建一个Plane和一个Cube,为Plane贴上名为grid.psd的图片。这里我们要制作一个6×6的网格,依据前面提到的知识,将缩放量和偏移量分别设置为(0.5,0.5)和(6.0,6.0)。
2. 设置游戏对象位置
将Plane和Cube的位置都设置为(0,0,0)。
3. 确定Plane的大小
我们以1.5倍的Cube单位长度作为一个网格的边长,所以Plane的大小为 1.5×6/10,也就是以0.9为单位长度的正方形。
4. 调整摄像机位置
把摄像机调整到合适的位置,以确保能清晰看到网格。
5. 编写代码
以下是以注释方式详细讲解的代码:
using UnityEngine;
using System.Collections;
public class GridTest : MonoBehaviour
{
public GameObject indicator2; // cube作为被选中网格的标识
public GameObject ground; // plane
private float _gridSize = 1.5f; // 网格的大小,以cube的单位长度为标准
void Start ()
{
// 可在Start方法中添加初始化逻辑
}
void Update ()
{
SetIndicator (Input.mousePosition);
}
void SetIndicator (Vector3 mousePos)
{
// 从鼠标位置发射一条射线
Ray ray = Camera.main.ScreenPointToRay (mousePos);
RaycastHit hit;
if (Physics.Raycast (ray, out hit, Mathf.Infinity)) {
Transform basePlane = ground.transform;
// 通过大小来判断行数和列数是奇数还是偶数
float remainderX = GetWorldScale (basePlane).x * 10 / _gridSize % 2;
float remainderZ = GetWorldScale (basePlane).z * 10 / _gridSize % 2;
// 获取射线碰撞点到ground的一个旋转量
Quaternion rot = Quaternion.LookRotation (hit.point - basePlane.position);
// 碰撞点到ground的距离
float dist = Vector3.Distance (hit.point, basePlane.position);
Debug.Log ("dist:" + dist);
// 以ground为坐标原点为坐标系,通过三角函数计算出碰撞点在坐标系中的坐标
float distX = Mathf.Sin ((rot.eulerAngles.y - basePlane.rotation.eulerAngles.y) * Mathf.Deg2Rad) * dist;
Debug.Log ("distX:" + distX);
float distZ = Mathf.Cos ((rot.eulerAngles.y - basePlane.rotation.eulerAngles.y) * Mathf.Deg2Rad) * dist;
Debug.Log ("distZ:" + distZ);
// 判断碰撞点在ground为原点的坐标系中的哪一象限
float signX = distX / Mathf.Abs (distX);
Debug.Log ("signX:" + signX);
float signZ = distZ / Mathf.Abs (distZ);
// 获取在ground为原点的坐标系中的单位坐标
float numX = Mathf.Round ((distX + (remainderX - 1) * (signX * _gridSize / 2)) / _gridSize);
float numZ = Mathf.Round ((distZ + (remainderZ - 1) * (signZ * _gridSize / 2)) / _gridSize);
// 计算出在坐标轴中的偏移量
float offsetX = -(remainderX - 1) * signX * _gridSize / 2;
float offsetZ = -(remainderZ - 1) * signZ * _gridSize / 2;
// 调整坐标系
Vector3 p = basePlane.TransformDirection (new Vector3 (numX, 0, numZ) * _gridSize);
Debug.Log ("p :" + p);
p += basePlane.TransformDirection (new Vector3 (offsetX, 0, offsetZ));
Debug.Log ("p1 :" + p);
// 设置位置
Vector3 pos = p + basePlane.position;
indicator2.transform.position = pos;
indicator2.transform.rotation = basePlane.rotation;
}
}
public Vector3 GetWorldScale (Transform transform)
{
Vector3 worldScale = transform.localScale;
Transform parent = transform.parent;
while (parent != null) {
worldScale = Vector3.Scale (worldScale, parent.localScale);
parent = parent.parent;
}
return worldScale;
}
}
6. 运行测试
把上述脚本拖到相机上,将Plane赋值给Ground,Cube赋值给indicator2,然后运行游戏,所需的效果就会呈现出来。
通过以上步骤,你就能在Unity中实现塔防游戏里的网格制作了。希望这个教程对你有所帮助!