网格建造
游戏中常见的建造方式,目前在做的游戏中需要。
但搜出来的教程比较少,我又是个英文盲,没找到合适的方法,于是瞎研究了一个,说实话也挺简单的。
整体感觉还行,演示:
教程
变量
先定义几个变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public Vector2 buildSize;
public Vector2 startPoint;
public Vector2 buildArea;
private GameObject buildObj;
private Vector3 curPosition;
private Dictionary<float, Dictionary<float, bool>> allowBuildArea = new Dictionary<float, Dictionary<float, bool>>();
private bool allowBuild = false;
|
创建网格
首先根据 可建造区域大小 和 可建造区域起始点 创建网格,放到允许建造区域字典中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| private void Start() { for (int gridX = Mathf.CeilToInt(this.startPoint.x); gridX < this.startPoint.x + this.buildArea.x; gridX++) {
for (int gridY = Mathf.CeilToInt(this.startPoint.y); gridY < this.startPoint.y + this.buildArea.y; gridY++) { if (!this.allowBuildArea.ContainsKey(gridX)) { this.allowBuildArea.Add(gridX, new Dictionary<float, bool>()); } this.allowBuildArea[gridX].Add(gridY, true); }
} }
|
建造指示器
然后是创建建造指示器,也就是红绿的方块,标识该坐标是否允许建造。
我这里是先创建一个放在左上角,其他会作为它的子级被创建。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| private void CreateBuildIndicator() { this.buildObj = GameObject.CreatePrimitive(PrimitiveType.Cube); this.buildObj.transform.localScale = new Vector3(1, 0.1f, 1); this.buildObj.layer = LayerMask.NameToLayer("Build"); buildGroup.Add(this.buildObj); SetTransparent(ScriptObjectPool<MeshRenderer>.Instance.GetComponent(this.buildObj).material);
for (int buildX = 0; buildX < this.buildSize.x; buildX++) {
for (int buildY = 0; buildY > -this.buildSize.y; buildY--) { if (buildX == 0 && buildY == 0) continue;
GameObject buildChildren = GameObject.CreatePrimitive(PrimitiveType.Cube); buildChildren.transform.SetParent(this.buildObj.transform); buildChildren.transform.localScale = Vector3.one; buildChildren.transform.position = new Vector3(buildX, this.buildObj.transform.position.y, buildY); buildChildren.layer = LayerMask.NameToLayer("Build"); SetTransparent(ScriptObjectPool<MeshRenderer>.Instance.GetComponent(buildChildren).material);
buildGroup.Add(buildChildren); } } }
|
发射射线
然后是发射射线,让建造指示器跟随鼠标
这一步可以直接在 Update() 里做,我这里是放到了一个循环计时器中
为了测试方便,我直接改成了右键创建建造指示器,左键建造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| void Update() { if (Input.GetMouseButtonDown(0) && this.allowBuild) { Build(); } if (Input.GetMouseButtonDown(1)) { if (this.buildObj != null) return; CreateBuildIndicator(); GameUtil.Instance.SetInterval((intervalID) => { if (this.buildObj == null) { GameUtil.Instance.RemoveInterval(intervalID); return; } Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit, Mathf.Infinity, ~(1 << LayerMask.NameToLayer("Build")))) { this.buildObj.transform.position = new Vector3(Mathf.Round(hit.point.x - this.buildSize.x / 2), hit.point.y + 0.1f, Mathf.Round(hit.point.z + this.buildSize.y / 2)); if (this.curPosition != this.buildObj.transform.position) { this.curPosition = this.buildObj.transform.position; OnPositionChanged(); }
}
}, 0.03f);
} }
private void OnPositionChanged() { this.allowBuild = true;
foreach (var buildBlock in buildGroup) { Vector3 position = buildBlock.transform.position; if ( this.allowBuildArea.ContainsKey(position.x) && this.allowBuildArea[position.x].ContainsKey(position.z) && this.allowBuildArea[position.x][position.z] == true ) { ScriptObjectPool<MeshRenderer>.Instance.GetComponent(buildBlock).material.color = new Color(0.1f, 1, 0.1f, 0.3f); } else { this.allowBuild = false; ScriptObjectPool<MeshRenderer>.Instance.GetComponent(buildBlock).material.color = new Color(1, 0.1f, 0.1f, 0.3f); } } }
|
左键执行的那个Build()
就只是把当前的建造指示器改个颜色放在原位,实际游戏中会创建建筑,删掉建造指示器。
OK,以上就是这个网格建造的分享,告辞。