塔防游戏中的网格制作小教程

2015年03月17日 10:55 0 点赞 0 评论 更新于 2025-11-21 17:26

在大多数塔防游戏里,当玩家进行单位建造操作时,可建造区域会显示出网格。玩家选择创建某个单位后,将鼠标移至特定网格,该网格会进入选中状态,随后玩家就能在这个格子里创建单位。今天,我研究了一个塔防插件,并把其中的网格部分分离出来,制作了这个小教程,分享给大家。

开始前的Unity知识储备

在正式开始制作之前,我们先了解一些Unity中的关键知识:

  1. 单位大小关系:在Unity里,Plane的单位大小是Cube的十倍。
  2. 网格绘制方法:在Plane上贴上带有透明通道的图片,然后通过设置纹理的偏移量和缩放量来绘制网格。
  3. 网格判断方式:通过射线来判断当前所处的网格,示例代码如下:
    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. 设置游戏对象位置

PlaneCube的位置都设置为(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赋值给GroundCube赋值给indicator2,然后运行游戏,所需的效果就会呈现出来。

通过以上步骤,你就能在Unity中实现塔防游戏里的网格制作了。希望这个教程对你有所帮助!

作者信息

menghao

menghao

共发布了 3994 篇文章