08 / 11 · 9 分钟
基础
用代码生成方块网格
到目前为止的项目
Assets/
Scenes/
Arena.unity
FloorBlocks (parent)
Scripts/
GridSpawner.cs
Prefabs/
P_Cube
你已经有的这一课新增
手动一个个摆满 100 个方块,一个下午就没了。两层嵌套循环加一句 Instantiate,一帧就搞定。
动态图解
x 往横走,z 往屏幕里走,每个格子掉下一个 cube。
网格生成脚本
GridSpawner.cs
using UnityEngine;
public class GridSpawner : MonoBehaviour
{
[SerializeField] private GameObject blockPrefab;
[SerializeField] private int columns = 6; // along X
[SerializeField] private int rows = 6;
[SerializeField] private float spacing = 1.5f; // metres between blocks
[SerializeField] private Transform parent;
void Start()
{
BuildGrid();
}
void BuildGrid()
{
// centre the grid on this object
float offsetX = (columns - 1) * spacing * 0.5f;
float offsetZ = (rows - 1) * spacing * 0.5f;
for (int x = 0; x < columns; x++)
{
for (int z = 0; z < rows; z++)
{
Vector3 pos = new Vector3(
x * spacing - offsetX,
0.5f, // half the cube height
z * spacing - offsetZ);
GameObject block = Instantiate(blockPrefab, pos, Quaternion.identity, parent);
block.name = $"Block_{x}_{z}"; // readable in the Hierarchy
}
}
}
}- 1
新建一个空 GameObject,命名 Spawner,放在 0, 0, 0。
- 2
给它挂上 GridSpawner.cs,再把 P_Cube 拖进 Block Prefab 槽位。
- 3
再建一个空物体叫 Blocks,拖进 Parent 槽位 —— 生成出来的 cube 全都挂在它下面。
- 4
Play 一点,36 个 cube 出现在地板正中。
把这段计算一次弄懂
x * spacing 把循环计数 0,1,2… 换算成米:0、1.5、3……
减去 offsetX 会把整个网格往左挪自身宽度的一半,于是它居中,而不是从原点开始排。
Instantiate 的第四个参数是父 Transform。传了它,Hierarchy 就不会变成 36 行散落的对象。
值得一试的几个变体
inside the inner loop
// 1 — random colour per block
block.GetComponent<Renderer>().material.color =
Random.ColorHSV(0f, 1f, 0.4f, 0.7f, 0.7f, 1f);
// 2 — random height, so it reads like a city
float h = Random.Range(0.5f, 4f);
block.transform.localScale = new Vector3(1f, h, 1f);
block.transform.position = new Vector3(pos.x, h * 0.5f, pos.z);
// 3 — a wave, using the distance from the centre
float d = new Vector2(x - columns * 0.5f, z - rows * 0.5f).magnitude;
block.transform.position += Vector3.up * Mathf.Sin(d) * 0.6f;清掉网格
C# 脚本
public void ClearGrid()
{
// backwards: still right if this ever becomes DestroyImmediate
for (int i = parent.childCount - 1; i >= 0; i--)
Destroy(parent.GetChild(i).gameObject);
}