最近项目要整个建造系统类似背包和RTS建造系统那样的:
预制体加载一个脚本(获取类型,检测是否有别的建造物)
预制体记得加载box collider组件,然后layer设置成Prefab
using UnityEngine;
public class PrefabObject : MonoBehaviour
{
public int objectType;
public static bool CheckOverlapInLayer(GameObject gameObject)
{
Collider collider = gameObject.GetComponent<Collider>();
if (collider == null)
{
// 如果没有Collider组件,返回false
return false;
}
Collider[] colliders = Physics.OverlapBox(collider.bounds.center, collider.bounds.extents);
foreach (Collider otherCollider in colliders)
{
if (otherCollider.gameObject.layer == LayerMask.NameToLayer("Prefab"))
{
// 如果发现与指定Layer标签相符的Collider,且不是自身Collider
if (otherCollider != collider)
{
// 两个Collider重叠
return true;
}
}
}
// 两个Collider不重叠
return false;
}
}
主要逻辑脚本, 挂载在一个场景空对象上
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
using System.IO;
using System.Linq;
public class PrefabManager : MonoBehaviour
{
private List<PrefabClass> prefabList = new List<PrefabClass>();
private List<GameObject> prefabInstances = new List<GameObject>();
private GameObject currentGameObject; //想要创建的物体
private int nodeCount = 0;
public GameObject[] prefabs;
public Dropdown prefabDropdown;
public InputField nameField;
public Button createButton;
public Button deleteButton;
public Transform transform;
public Dropdown dropdown;
private void Start()
{
if (!File.Exists(Application.streamingAssetsPath + "/SaveData/prefabList.json"))
{
ForeachPrefabList(transform);
SavePrefabList();
}
LoadPrefabList();
RemoveExistingPrefabs();
RefreshPrefabList();
UpdateDropDownView();
prefabDropdown.onValueChanged.AddListener(OnPrefabSelectionChanged);
dropdown.onValueChanged.AddListener(OnSelectionChanged);
createButton.onClick.AddListener(CreatePrefab);
deleteButton.onClick.AddListener(DeletePrefab);
}
private void Update()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit raycastHit;
//需要在场景内加一层plane提供meshCollider,否则raycastHit.point会一直为0
if (Physics.Raycast(ray, out raycastHit))
{
Debug.DrawLine(ray.origin, hit.point,Color.green);//在编辑器视图中绘制射线
if (Input.GetMouseButtonDown(0)) // 左键点击
{CreatePrefab(raycastHit.point);}
}
}
private void RemoveExistingPrefabs()
{
// 使用 FindObjectsOfType 方法查找特定类型的子物体
PrefabObject[] children = GameObject.FindObjectsOfType<PrefabObject>();
// 遍历子物体,从最后一个开始销毁
for (int i = children.Length - 1; i >= 0; i--)
{
if (children[i].gameObject != gameObject)
{
Destroy(children[i].gameObject);
}
}
//记得加个这个否则如果调用transform.childCount会多一倍
transform.DetachChildren();
}
private void RefreshPrefabList()
{
foreach (var prefabClass in prefabList)
{
switch (prefabClass.type)
{
case 0:
currentGameObject = Instantiate(prefabs[0], prefabClass.vector3, prefabClass.rotation, transform);
break;
case 1:
currentGameObject = Instantiate(prefabs[1], prefabClass.vector3, prefabClass.rotation, transform);
break;
default:
break;
}
currentGameObject.name = prefabClass.name;
prefabInstances.Add(currentGameObject);
nodeCount++;
}
}
private void UpdateDropDownView()
{
//清空下下拉框数据
dropdown.options.Clear();
for (int i = 0; i < nodeCount; i++)
{
Dropdown.OptionData option = new Dropdown.OptionData();
option.text = prefabInstances[i].name;
dropdown.options.Add(option);
}
}
private void OnSelectionChanged(int value)
{
if (value >= 0 && value < prefabList.Count)
{
MouseOperation.Instance.target.position = prefabList[value].vector3;
Camera.main.transform.LookAt(prefabList[value].vector3);
}
}
private void OnPrefabSelectionChanged(int value)
{
currentGameObject = prefabs[value];
}
private void CreatePrefab(Vector3 position)
{
switch (prefabDropdown.value)
{
case 0:
currentGameObject = Instantiate(prefabs[0], position, prefabs[0].transform.localRotation, transform);
break;
case 1:
currentGameObject = Instantiate(prefabs[1], position, prefabs[1].transform.localRotation, transform);
break;
default:
break;
}
//判断是否重名和重合位置
bool containsCharacter = prefabList.Any(x => x.name == nameField.text);
if (PrefabObject.CheckOverlapInLayer(currentGameObject) || containsCharacter)
{
Destroy(currentGameObject);
}
else
{
currentGameObject.name = nameField.text;
PrefabClass prefabClass = new PrefabClass();
prefabClass.type = prefabDropdown.value;
prefabClass.name = currentGameObject.name;
prefabClass.vector3 = currentGameObject.transform.position;
prefabClass.rotation = currentGameObject.transform.rotation;
prefabList.Add(prefabClass);
prefabInstances.Add(currentGameObject);
SavePrefabList();
Dropdown.OptionData newOption = new Dropdown.OptionData(currentGameObject.name);
dropdown.options.Add(newOption);
dropdown.RefreshShownValue();
// 设置新添加选项为当前选中项
dropdown.value = dropdown.options.Count - 1;
nodeCount++;
}
}
private void DeletePrefab()
{
int selectedIndex = dropdown.value;
Destroy(prefabInstances[selectedIndex]);
dropdown.options.RemoveAt(selectedIndex);
dropdown.RefreshShownValue();
prefabInstances.RemoveAt(selectedIndex);
prefabList.RemoveAt(selectedIndex);
SavePrefabList();
nodeCount--;
}
private void SavePrefabList()
{
// 清空之前的保存文件
string json = JsonUtility.ToJson(new SerializablePrefabList(prefabList));
File.WriteAllText(Application.streamingAssetsPath + "/SaveData/prefabList.json", json);
}
private void LoadPrefabList()
{
string path = Application.streamingAssetsPath + "/SaveData/prefabList.json";
if (File.Exists(path))
{
string json = File.ReadAllText(path);
SerializablePrefabList serializedList = JsonUtility.FromJson<SerializablePrefabList>(json);
prefabList = serializedList.prefabList;
}
}
//我的场景本身存在一些预设的预制体,其实就是先存一下,别的项目不用也可以删除.
private void ForeachPrefabList(Transform parentTransform)
{
for (int i = 0; i < parentTransform.childCount; i++)
{
GameObject childGameObject = parentTransform.GetChild(i).gameObject;
PrefabClass prefabClass = new PrefabClass();
PrefabObject childScript = childGameObject.GetComponent<PrefabObject>();
prefabClass.type = childScript.objectType;
prefabClass.name = childGameObject.name;
prefabClass.vector3 = childGameObject.transform.position;
prefabClass.rotation = childGameObject.transform.rotation;
prefabList.Add(prefabClass);
prefabInstances.Add(childGameObject);
nodeCount++;
}
}
}
[System.Serializable]
public class SerializablePrefabList
{
public List<PrefabClass> prefabList;
public SerializablePrefabList(List<PrefabClass> list)
{
prefabList = list;
}
}
[System.Serializable]
public class PrefabClass
{
public int type;
public string name;
public Vector3 vector3;
public Quaternion rotation;
}