UP-Viagg-io/Viagg-io/Assets/PlacmentTool/Editor/PrefabPlacementTool.cs
2025-03-24 07:53:48 +01:00

630 lines
20 KiB
C#

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public class PrefabPlacementTool : EditorWindow
{
public enum Type
{
Physical,
Place,
Decal,
}
public Type type = Type.Physical;
private Type previousType = Type.Physical; // Äîáàâèì ïåðåìåííóþ äëÿ õðàíåíèÿ ïðåäûäóùåãî ðåæèìà
public enum Mode
{
Sequential,
Random,
}
public Mode mode = Mode.Sequential;
[HideInInspector]
private List<GameObject> prefabsToPlace = new List<GameObject>();
private List<GameObject> prefabsToRemove = new List<GameObject>();
public Vector3 rotation;
public bool randomRotation;
public Vector3 randomSizeMin = new Vector3(1f, 1f, 1f);
public Vector3 randomSizeMax = new Vector3(1f, 1f, 1f);
public bool sizeProportionally = true;
public float placementHeight = 1.0f;
private int currentPrefabIndex = 0;
private int groupIndex = 1;
[HideInInspector]
private string savePath = "Assets/PlacmentTool/Prefabs/SavePrefab/"; // Íà÷àëüíîå çíà÷åíèå ïóòè ñîõðàíåíèÿ
public GameObject pointerPrefab;
public GameObject pointerPrefabHeight;
private GameObject pointerInstance;
private GameObject pointerHeightInstance;
public bool showPrefabsList = true;
private bool isPlaying = false;
void FindPointerPrefabs()
{
pointerPrefab = FindPrefabByName("PointerPrefab");
pointerPrefabHeight = FindPrefabByName("PointerHeightPrefab");
}
GameObject FindPrefabByName(string prefabName)
{
string[] guids = AssetDatabase.FindAssets(prefabName); // Èùåì ïðåôàáû ñ óêàçàííûì èìåíåì
if (guids.Length > 0)
{
string path = AssetDatabase.GUIDToAssetPath(guids[0]); // Áåðåì ïåðâûé íàéäåííûé ïðåôàá
return AssetDatabase.LoadAssetAtPath<GameObject>(path);
}
else
{
Debug.LogError("Prefab with name " + prefabName + " not found!");
return null;
}
}
private void Update()
{
if (isPlaying)
{
if (Input.GetMouseButtonDown(0))
{
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
{
DeleteObjectUnderCursor();
}
else
{
PlaceNextPrefab();
}
}
}
// Ïðîâåðêà íà èçìåíåíèå ðåæèìà
if (type != previousType)
{
if (pointerHeightInstance != null)
{
Destroy(pointerHeightInstance);
pointerHeightInstance = null;
}
previousType = type; // Îáíîâëÿåì ïðåäûäóùèé ðåæèì
}
MovePointerWithCursor();
}
void OnGUI()
{
EditorGUILayout.LabelField("Prefab Placement Tool Settings", EditorStyles.boldLabel);
type = (Type)EditorGUILayout.EnumPopup("Placement Type", type);
mode = (Mode)EditorGUILayout.EnumPopup("Placement Mode", mode);
EditorGUILayout.Space();
List<GameObject> prefabsToRemove = new List<GameObject>();
for (int i = 0; i < prefabsToPlace.Count; i++)
{
EditorGUILayout.BeginHorizontal();
prefabsToPlace[i] = (GameObject)EditorGUILayout.ObjectField("Prefab " + i, prefabsToPlace[i], typeof(GameObject), false);
if (GUILayout.Button("Remove"))
{
prefabsToRemove.Add(prefabsToPlace[i]);
}
EditorGUILayout.EndHorizontal();
}
// Óäàëåíèå ýëåìåíòîâ ïîñëå çàâåðøåíèÿ îòðèñîâêè èíòåðôåéñà
foreach (var prefab in prefabsToRemove)
{
prefabsToPlace.Remove(prefab);
}
prefabsToRemove.Clear();
if (GUILayout.Button("Add Prefab"))
{
prefabsToPlace.Add(null);
}
GUILayout.Space(20);
// Ïåðåíåñëè êíîïêó "Clear List" íèæå ñïèñêà ïðåôàáîâ
if (GUILayout.Button("Clear List"))
{
prefabsToPlace.Clear();
}
EditorGUILayout.Space();
rotation = EditorGUILayout.Vector3Field("Rotation", rotation);
randomRotation = EditorGUILayout.Toggle("Random Rotation", randomRotation);
EditorGUILayout.Space();
sizeProportionally = EditorGUILayout.Toggle("Size Proportionally", sizeProportionally);
if (sizeProportionally)
{
float minSize = EditorGUILayout.FloatField("Random Size Min", randomSizeMin.x);
randomSizeMin = new Vector3(minSize, minSize, minSize);
float maxSize = EditorGUILayout.FloatField("Random Size Max", randomSizeMax.x);
randomSizeMax = new Vector3(maxSize, maxSize, maxSize);
}
else
{
randomSizeMin = EditorGUILayout.Vector3Field("Random Size Min", randomSizeMin);
randomSizeMax = EditorGUILayout.Vector3Field("Random Size Max", randomSizeMax);
}
GUILayout.Space(10);
if (GUILayout.Button("Clear Objects"))
{
ClearObjects();
}
GUILayout.Space(20);
if (GUILayout.Button("Group Objects"))
{
GroupObjects();
}
if (GUILayout.Button("Save Grouped Prefab"))
{
SavePrefabs();
}
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
GUILayout.Space(10);
EditorGUILayout.Space();
GUILayout.Label("Save Path", EditorStyles.boldLabel);
GUILayout.BeginHorizontal();
savePath = EditorGUILayout.TextField(savePath);
if (GUILayout.Button("Select Folder", GUILayout.Width(100)))
{
string selectedPath = EditorUtility.OpenFolderPanel("Select Save Folder", "", "");
if (!string.IsNullOrEmpty(selectedPath))
{
// Åñëè âûáðàíà ïàïêà, îáíîâëÿåì savePath
savePath = "Assets" + selectedPath.Replace(Application.dataPath, "") + "/";
}
}
GUILayout.EndHorizontal();
placementHeight = EditorGUILayout.FloatField("Placement Height", placementHeight);
pointerPrefab = (GameObject)EditorGUILayout.ObjectField("Pointer Prefab", pointerPrefab, typeof(GameObject), false);
pointerPrefabHeight = (GameObject)EditorGUILayout.ObjectField("Pointer Prefab Height", pointerPrefabHeight, typeof(GameObject), false);
EditorGUILayout.Space();
if (!EditorApplication.isPlaying)
{
GUI.enabled = false; // Áëîêèðîâêà êíîïîê â ðåæèìå ðåäàêòèðîâàíèÿ
}
if (GUILayout.Button(isPlaying ? "Stop" : "Play"))
{
TogglePlay();
}
GUI.enabled = true; // Âîññòàíîâëåíèå àêòèâíîñòè äëÿ äðóãèõ ýëåìåíòîâ èíòåðôåéñà
}
private void OnEnable()
{
FindPointerPrefabs(); // Âûçûâàåì ìåòîä ïîèñêà ïðåôàáîâ ïðè àêòèâàöèè îêíà èíñïåêòîðà
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}
private void OnDisable()
{
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
}
private void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (state == PlayModeStateChange.ExitingPlayMode && isPlaying)
{
isPlaying = false;
HidePointer();
}
}
private void TogglePlay()
{
if (EditorApplication.isPlaying)
{
isPlaying = !isPlaying;
if (isPlaying)
{
Debug.Log("Prefab Placement Tool Playing");
CreatePointer();
}
else
{
Debug.Log("Prefab Placement Tool Stopped");
HidePointer();
}
}
else
{
Debug.LogWarning("You can only toggle play mode while in play mode.");
}
}
[MenuItem("Window/Prefab Placement Tool")]
public static void ToggleWindow()
{
GetWindow<PrefabPlacementTool>("Prefab Placement Tool");
}
void DeleteObjectUnderCursor()
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
GameObject objectToDelete = hit.collider.gameObject;
if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)))
{
if (objectToDelete.CompareTag("PlacedObject"))
{
Undo.DestroyObjectImmediate(objectToDelete);
}
}
}
}
Quaternion GenerateRandomRotation(Vector3 maxRotation)
{
if (randomRotation)
{
return Quaternion.Euler(
Random.Range(0f, maxRotation.x),
Random.Range(0f, maxRotation.y),
Random.Range(0f, maxRotation.z)
);
}
else
{
return Quaternion.Euler(maxRotation);
}
}
void PlaceNextPrefab()
{
if (prefabsToPlace.Count == 0)
{
Debug.LogWarning("List of prefabs to place is empty.");
return;
}
GameObject prefabToInstantiate = null;
if (mode == Mode.Sequential)
{
if (currentPrefabIndex >= prefabsToPlace.Count)
{
currentPrefabIndex = 0; // Return to the beginning of the list
}
prefabToInstantiate = prefabsToPlace[currentPrefabIndex];
currentPrefabIndex++;
}
else if (mode == Mode.Random)
{
int randomIndex = Random.Range(0, prefabsToPlace.Count);
prefabToInstantiate = prefabsToPlace[randomIndex];
}
if (prefabToInstantiate != null)
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
Vector3 spawnPosition = hit.point;
Quaternion spawnRotation = GenerateRandomRotation(rotation);
Vector3 GenerateRandomScale(Vector3 min, Vector3 max)
{
if (sizeProportionally)
{
float randomSize = Random.Range(min.x, max.x);
return new Vector3(randomSize, randomSize, randomSize);
}
else
{
return new Vector3(
Random.Range(min.x, max.x),
Random.Range(min.y, max.y),
Random.Range(min.z, max.z)
);
}
}
if (type == Type.Place || type == Type.Decal || type == Type.Physical)
{
Vector3 randomScale = GenerateRandomScale(randomSizeMin, randomSizeMax);
if (type == Type.Place)
{
spawnPosition.y += 0.1f;
GameObject newObject = Instantiate(prefabToInstantiate, spawnPosition, spawnRotation);
newObject.tag = "PlacedObject";
newObject.transform.localScale = randomScale;
Rigidbody createdRB = newObject.GetComponent<Rigidbody>();
if (createdRB == null)
{
createdRB = newObject.AddComponent<Rigidbody>();
createdRB.mass = 1f; // Set high mass
createdRB.drag = 20f; // Set movement resistance
createdRB.angularDrag = 10f; // Set rotation resistance
}
}
else if (type == Type.Decal)
{
Vector3 decalSpawnPosition = hit.point + hit.normal * 0.001f;
Quaternion decalSpawnRotation = spawnRotation;
GameObject newDecalObject = Instantiate(prefabToInstantiate, decalSpawnPosition, decalSpawnRotation);
newDecalObject.tag = "PlacedObject";
newDecalObject.transform.localScale = randomScale;
}
else if (type == Type.Physical)
{
spawnPosition.y += placementHeight;
GameObject newPhysicalObject = (GameObject)PrefabUtility.InstantiatePrefab(prefabToInstantiate);
newPhysicalObject.transform.position = spawnPosition;
newPhysicalObject.transform.rotation = spawnRotation;
newPhysicalObject.tag = "PlacedObject";
newPhysicalObject.transform.localScale = randomScale;
Rigidbody createdPhysicalRB = newPhysicalObject.GetComponent<Rigidbody>();
if (createdPhysicalRB == null)
{
createdPhysicalRB = newPhysicalObject.AddComponent<Rigidbody>();
}
Vector3 randomPhysicalScale = GenerateRandomScale(randomSizeMin, randomSizeMax);
newPhysicalObject.transform.localScale = randomPhysicalScale;
createdPhysicalRB.mass = 40 * (newPhysicalObject.transform.localScale.x * newPhysicalObject.transform.localScale.y * newPhysicalObject.transform.localScale.z);
}
}
}
}
}
void MovePointerWithCursor()
{
if (isPlaying)
{
if (pointerInstance == null && pointerPrefab != null)
{
// Instantiate the pointerPrefab if it hasn't been instantiated yet
pointerInstance = Instantiate(pointerPrefab);
}
// Check if the pointerInstance exists and the mouse position is valid
if (pointerInstance != null && Camera.main != null)
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
// Update the position of the pointer prefab to match the cursor's position
pointerInstance.transform.position = hit.point;
}
}
if (type == Type.Physical)
{
if (pointerPrefabHeight != null)
{
if (pointerHeightInstance == null)
{
// Instantiate the pointerPrefabHeight if it hasn't been instantiated yet
pointerHeightInstance = Instantiate(pointerPrefabHeight);
}
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
// Set the position of the pointerPrefabHeight to the height above the hit point
Vector3 heightPosition = hit.point + Vector3.up * placementHeight;
pointerHeightInstance.transform.position = heightPosition;
}
}
}
}
}
public void GroupObjects()
{
// Ñîçäàåì ïóñòîé GameObject, êîòîðûé áóäåò ñëóæèòü êîðíåâûì äëÿ ãðóïïèðîâêè îáúåêòîâ
GameObject groupRoot = new GameObject("GroupedObjects_" + Random.Range(1000, 9999)); // Ãåíåðèðóåì ñëó÷àéíîå çíà÷åíèå â äèàïàçîíå îò 1000 äî 9999
// Äîáàâëÿåì ìàðêåð GroupedObjectMarker ê êîðíåâîìó îáúåêòó, ÷òîáû åãî ìîæíî áûëî ëåãêî îïîçíàòü
GroupedObjectMarker marker = groupRoot.AddComponent<GroupedObjectMarker>();
// Íàõîäèì âñå îáúåêòû ñ òåãîì "PlacedObject" è äåëàåì èõ äî÷åðíèìè îáúåêòàìè êîðíåâîãî îáúåêòà
GameObject[] allObjects = GameObject.FindGameObjectsWithTag("PlacedObject");
foreach (GameObject obj in allObjects)
{
// Ïðîâåðÿåì, ÷òî îáúåêò íå ÿâëÿåòñÿ äî÷åðíèì îáúåêòîì äðóãîé ãðóïïû
if (obj.transform.parent == null || obj.transform.parent.GetComponent<GroupedObjectMarker>() == null)
{
obj.transform.parent = groupRoot.transform;
}
}
}
public void SavePrefabs()
{
// Find all objects with the GroupedObjectMarker script attached
GroupedObjectMarker[] groupedObjects = FindObjectsOfType<GroupedObjectMarker>();
foreach (GroupedObjectMarker marker in groupedObjects)
{
// Get the root object
Transform root = marker.transform;
// Get the original name of the root GameObject
string originalName = root.gameObject.name;
// Create a list to hold references to the placed objects within this group
List<GameObject> objectsToSave = new List<GameObject>();
// Find all children of the current group root
foreach (Transform child in root)
{
objectsToSave.Add(child.gameObject);
}
// Modify objects before saving as prefabs
foreach (GameObject obj in objectsToSave)
{
// Enable colliders
Collider[] colliders = obj.GetComponentsInChildren<Collider>();
foreach (Collider _coll in colliders)
{
_coll.enabled = true;
}
// Remove MeshCollider components
MeshCollider[] meshColliders = obj.GetComponentsInChildren<MeshCollider>();
foreach (MeshCollider meshColl in meshColliders)
{
DestroyImmediate(meshColl);
}
// Remove Rigidbody components
Rigidbody[] rigidbodies = obj.GetComponentsInChildren<Rigidbody>();
foreach (Rigidbody rb in rigidbodies)
{
DestroyImmediate(rb);
}
}
// Remove the GroupedObjectMarker component before saving as a prefab
DestroyImmediate(marker);
// Create a prefab containing the modified objects within this group with the original name
GameObject prefab = PrefabUtility.SaveAsPrefabAsset(root.gameObject, savePath + originalName + ".prefab");
if (prefab == null)
{
Debug.Log("Folder not Found");
}
else
{
Debug.Log("Prefab saved at: " + savePath + originalName + ".prefab");
// Restore the GroupedObjectMarker component after saving the prefab (optional)
root.gameObject.AddComponent<GroupedObjectMarker>();
}
}
}
void CreatePointer()
{
if (pointerPrefab != null)
{
pointerInstance = Instantiate(pointerPrefab);
if (type == Type.Physical && pointerPrefabHeight != null)
{
pointerHeightInstance = Instantiate(pointerPrefabHeight);
}
}
}
void HidePointer()
{
if (pointerInstance != null)
{
Destroy(pointerInstance);
pointerInstance = null;
}
if (pointerHeightInstance != null)
{
Destroy(pointerHeightInstance);
pointerHeightInstance = null;
}
}
public class GroupedObjectMarker : MonoBehaviour
{
// Ïóñòîé ìàðêåð äëÿ îáîçíà÷åíèÿ ãðóïïèðîâàííûõ îáúåêòîâ
}
public void ClearObjects()
{
GameObject[] placedObjects = GameObject.FindGameObjectsWithTag("PlacedObject");
foreach (GameObject obj in placedObjects)
{
Destroy(obj);
}
}
}