接上一回https://jinjis.cn/index.php/archives/unityzuo-yi-ge-jian-dan-de-yun-shu-dai.html
物体可以在运输带上移动了,但是运输带还得一个一个安放,效率比较低下,下面实现一下建造传输带的功能
建造部分参考了这篇文章
用Unity盖房子(一):《勇者斗恶龙:建造者2》游戏功能的猜想
首先我们的传输带是1m的立方体,它的中心在0.5的位置,所以如果要在平面上进行建造,需要从鼠标发射一条射线,而射线碰撞点的坐标转换为0.5的倍数
public static Vector3 FromWorldPositionToCubePosition (Vector3 position) {
Vector3 resut = Vector3.zero;
resut.x = position.x > 0 ? (int) position.x * 1f + 0.5f : (int) position.x * 1f - 0.5f;
resut.y = position.y > 0 ? (int) position.y * 1f + 0.5f : (int) position.y * 1f - 0.5f;
resut.z = position.z > 0 ? (int) position.z * 1f + 0.5f : (int) position.z * 1f - 0.5f;
return resut;
}
然后就是发射射线并生成传输带了
先生成一个cube用来显示安放位置,点击左键再实例化传输带
void Update () {
if (GetMouseRayPoint (out addCubePos)) {
cube.transform.position = addCubePos;
if (Input.GetMouseButtonDown (0)) {
Instantiate (wheelPb, addCubePos, wheelPb.transform.rotation);
}
}
}
bool GetMouseRayPoint (out Vector3 pos) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast (ray, out hitInfo)) {
pos = FromWorldPositionToCubePosition (hitInfo.point - ray.direction * 0.001f);
return true;
}
pos = Vector3.zero;
return false;
}
完整代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Builder : MonoBehaviour {
// Start is called before the first frame update
private Vector3 addCubePos;
public GameObject cube;
public GameObject wheelPb;
void Start () {
}
void Update () {
if (GetMouseRayPoint (out addCubePos)) {
cube.transform.position = addCubePos;
if (Input.GetMouseButtonDown (0)) {
Instantiate (wheelPb, addCubePos, wheelPb.transform.rotation);
}
}
}
bool GetMouseRayPoint (out Vector3 pos) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast (ray, out hitInfo)) {
pos = FromWorldPositionToCubePosition (hitInfo.point - ray.direction * 0.001f);
return true;
}
pos = Vector3.zero;
return false;
}
public static Vector3 FromWorldPositionToCubePosition (Vector3 position) {
Vector3 resut = Vector3.zero;
resut.x = position.x > 0 ? (int) position.x * 1f + 0.5f : (int) position.x * 1f - 0.5f;
resut.y = position.y > 0 ? (int) position.y * 1f + 0.5f : (int) position.y * 1f - 0.5f;
resut.z = position.z > 0 ? (int) position.z * 1f + 0.5f : (int) position.z * 1f - 0.5f;
return resut;
}
}
建造效果
但是这样还是只能一个一个点击来建造,所以再写一个根据点击两点生成直线传输带的效果
暂时只考虑同一水平高度的情况下
void Update () {
if (GetMouseRayPoint (out addCubePos)) {
cube.transform.position = addCubePos;
if (Input.GetMouseButtonDown (0)) {
if (lastCubePos != Vector3.zero) {
List<Vector3> addCubesPos = GetAddCubesPos (lastCubePos, addCubePos);
foreach (var pos in addCubesPos) {
Instantiate (wheelPb, pos, wheelPb.transform.rotation);
}
}
else {
Instantiate (wheelPb, addCubePos, wheelPb.transform.rotation);
}
lastCubePos = addCubePos;
}
}
}
List<Vector3> GetAddCubesPos (Vector3 startPos, Vector3 endPos) {
List<Vector3> cubesPos = new List<Vector3>();
int xLength = (int) (endPos.x - startPos.x);
int zLength = (int) (endPos.z - startPos.z);
Vector3 currentPos;
if (xLength != 0) {
int xDir = xLength / Mathf.Abs (xLength);
currentPos = startPos;
for (int i = 0; i != xLength; i += xDir) {
currentPos += Vector3.right * xDir;
cubesPos.Add (currentPos);
}
startPos = currentPos;
}
if (zLength != 0) {
int zDir = zLength / Mathf.Abs (zLength);
currentPos = startPos;
for (int i = 0; i != zLength; i += zDir) {
currentPos += Vector3.forward * zDir;
cubesPos.Add (currentPos);
}
}
return cubesPos;
}
直线建造效果
增加预览效果
void Update () {
if (GetMouseRayPoint (out addCubePos)) {
cube.transform.position = addCubePos;
List<Vector3> addCubesPos = new List<Vector3> ();
if (lastCubePos != Vector3.zero) {
addCubesPos = GetAddCubesPos (lastCubePos, addCubePos);
}
if (Input.GetMouseButtonDown (0)) {
if (lastCubePos != Vector3.zero) {
foreach (var pos in addCubesPos) {
Instantiate (wheelPb, pos, wheelPb.transform.rotation);
}
}
else {
Instantiate (wheelPb, addCubePos, wheelPb.transform.rotation);
}
lastCubePos = addCubePos;
}
}
}
List<Vector3> GetAddCubesPos (Vector3 startPos, Vector3 endPos) {
foreach (var item in cubes) {
Destroy (item);
}
cubes.Clear ();
List<Vector3> cubesPos = new List<Vector3> ();
int xLength = (int) (endPos.x - startPos.x);
int zLength = (int) (endPos.z - startPos.z);
Vector3 currentPos;
if (xLength != 0) {
int xDir = xLength / Mathf.Abs (xLength);
currentPos = startPos;
for (int i = 0; i != xLength; i += xDir) {
currentPos += Vector3.right * xDir;
cubesPos.Add (currentPos);
}
startPos = currentPos;
}
if (zLength != 0) {
int zDir = zLength / Mathf.Abs (zLength);
currentPos = startPos;
for (int i = 0; i != zLength; i += zDir) {
currentPos += Vector3.forward * zDir;
cubesPos.Add (currentPos);
}
}
foreach (var pos in cubesPos) {
cubes.Add (Instantiate (cube, pos, cube.transform.rotation));
}
return cubesPos;
}
再给生成的运输带绑定移动路径
void Update () {
if (GetMouseRayPoint (out addCubePos)) {
cube.transform.position = addCubePos;
List<Vector3> addCubesPos = new List<Vector3> ();
if (lastCubePos != Vector3.zero) {
addCubesPos = GetAddCubesPos (lastCubePos, addCubePos);
}
if (Input.GetMouseButtonDown (0)) {
if (lastCubePos != Vector3.zero) {
//如果是连接两点 记录各个传输点
List<GameObject> wheels = new List<GameObject> ();
wheels.Add (lastNode);
foreach (var pos in addCubesPos) {
wheels.Add (Instantiate (wheelPb, pos, wheelPb.transform.rotation));
}
//将两点直接路径绑定
for (int i = 0; i < wheels.Count - 1; i++) {
wheels[i].GetComponent<Wheel> ().paths.Add (wheels[i].transform);
wheels[i].GetComponent<Wheel> ().paths.Add (wheels[i + 1].transform);
}
lastNode = wheels[wheels.Count - 1];
}
else {
//记录最后一个/上一个安放的点
lastNode = Instantiate (wheelPb, addCubePos, wheelPb.transform.rotation);
}
lastCubePos = addCubePos;
}
}
}
运输物体的效果
但是这样区分度不够高,所以我找到了这篇文章,将预览的方块变成线框
使用后的效果