|
@@ -0,0 +1,1566 @@
|
|
|
|
|
+using UnityEngine;
|
|
|
|
|
+using System.Collections.Generic;
|
|
|
|
|
+
|
|
|
|
|
+public class NewRoomBuilder : MonoBehaviour
|
|
|
|
|
+{
|
|
|
|
|
+ [Header("Prefabs")]
|
|
|
|
|
+ public GameObject wallPrefab;
|
|
|
|
|
+ public GameObject wallPointPrefab;
|
|
|
|
|
+ public GameObject doorOpeningPrefab;
|
|
|
|
|
+
|
|
|
|
|
+ [Header("Settings")]
|
|
|
|
|
+ public float wallHeight = 3f;
|
|
|
|
|
+ public float wallThickness = 0.2f;
|
|
|
|
|
+ public float doorWidth = 1.5f;
|
|
|
|
|
+ public float doorHeight = 2.5f;
|
|
|
|
|
+ public float snapDistance = 1f; // Distance for snapping to existing points
|
|
|
|
|
+
|
|
|
|
|
+ private Camera playerCamera;
|
|
|
|
|
+ private BuildingUIController.BuildingMode currentMode = BuildingUIController.BuildingMode.Normal;
|
|
|
|
|
+
|
|
|
|
|
+ // Wall creation state
|
|
|
|
|
+ private bool isCreatingWall = false;
|
|
|
|
|
+ private Vector3 wallStartPoint;
|
|
|
|
|
+ private GameObject previewWall;
|
|
|
|
|
+ private LineRenderer previewLine;
|
|
|
|
|
+
|
|
|
|
|
+ // Available angles (in degrees)
|
|
|
|
|
+ private readonly float[] snapAngles = { 0f, 45f, 90f, 135f, 180f, 225f, 270f, 315f };
|
|
|
|
|
+
|
|
|
|
|
+ // Wall storage
|
|
|
|
|
+ private List<GameObject> walls = new List<GameObject>();
|
|
|
|
|
+
|
|
|
|
|
+ // Door preview
|
|
|
|
|
+ private GameObject doorPreview;
|
|
|
|
|
+ private GameObject hoveredWall;
|
|
|
|
|
+
|
|
|
|
|
+ // Snap indicators
|
|
|
|
|
+ private GameObject snapIndicator;
|
|
|
|
|
+ private GameObject currentSnapPoint;
|
|
|
|
|
+
|
|
|
|
|
+ private void Start()
|
|
|
|
|
+ {
|
|
|
|
|
+ // Try multiple ways to find the camera
|
|
|
|
|
+ playerCamera = Camera.main;
|
|
|
|
|
+ if (playerCamera == null)
|
|
|
|
|
+ {
|
|
|
|
|
+ playerCamera = FindFirstObjectByType<Camera>();
|
|
|
|
|
+ Debug.LogWarning($"Camera.main was null, found camera: {playerCamera?.name ?? "NONE"}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (playerCamera == null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.LogError("No camera found! Wall detection will not work.");
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Using camera: {playerCamera.name} at {playerCamera.transform.position}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ CreatePreviewLine();
|
|
|
|
|
+ CreateDoorPreview();
|
|
|
|
|
+ CreateSnapIndicator();
|
|
|
|
|
+
|
|
|
|
|
+ // Ensure we have prefabs
|
|
|
|
|
+ EnsurePrefabsExist();
|
|
|
|
|
+
|
|
|
|
|
+ // Fix any existing walls that might not be tagged properly
|
|
|
|
|
+ FixExistingWallTags();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void FixExistingWallTags()
|
|
|
|
|
+ {
|
|
|
|
|
+ // First, look for walls that are already properly tagged (from InitialRoomSetup)
|
|
|
|
|
+ GameObject[] existingWalls = GameObject.FindGameObjectsWithTag("Wall");
|
|
|
|
|
+ Debug.Log($"Found {existingWalls.Length} objects already tagged as 'Wall'");
|
|
|
|
|
+
|
|
|
|
|
+ foreach (GameObject wall in existingWalls)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!walls.Contains(wall))
|
|
|
|
|
+ {
|
|
|
|
|
+ walls.Add(wall);
|
|
|
|
|
+ Debug.Log($"Added existing tagged wall to tracking: {wall.name} - Scale: {wall.transform.localScale}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // If we found properly tagged walls, we're done
|
|
|
|
|
+ if (existingWalls.Length > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Successfully found and added {existingWalls.Length} pre-tagged walls from InitialRoomSetup");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Fallback: Look for objects that should be walls but aren't tagged yet
|
|
|
|
|
+ GameObject[] allObjects = FindObjectsByType<GameObject>(FindObjectsSortMode.None);
|
|
|
|
|
+ int fixedWalls = 0;
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"No pre-tagged walls found. Scanning {allObjects.Length} objects for potential walls...");
|
|
|
|
|
+
|
|
|
|
|
+ foreach (GameObject obj in allObjects)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Skip door components and other non-wall objects
|
|
|
|
|
+ if (obj.name.Contains("Post") || obj.name.Contains("Beam") || obj.name.Contains("Door") ||
|
|
|
|
|
+ obj.name.Contains("Mat") || obj.name.Contains("Entrance") || obj.name.Contains("Frame"))
|
|
|
|
|
+ {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Look for specific wall naming patterns from InitialRoomSetup
|
|
|
|
|
+ bool isInitialRoomWall = obj.name.Contains("North Wall") || obj.name.Contains("South Wall") ||
|
|
|
|
|
+ obj.name.Contains("East Wall") || obj.name.Contains("West Wall");
|
|
|
|
|
+
|
|
|
|
|
+ // Also check for other wall patterns
|
|
|
|
|
+ bool isWallObject = obj.name.Contains("Wall") ||
|
|
|
|
|
+ obj.name.Contains("wall") ||
|
|
|
|
|
+ obj.name.StartsWith("Room") ||
|
|
|
|
|
+ obj.name.Contains("Interior");
|
|
|
|
|
+
|
|
|
|
|
+ if ((isInitialRoomWall || isWallObject) && !obj.CompareTag("Wall"))
|
|
|
|
|
+ {
|
|
|
|
|
+ // Additional check: make sure it has a collider (walls should have colliders)
|
|
|
|
|
+ if (obj.GetComponent<Collider>() != null || obj.GetComponentInChildren<Collider>() != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Found untagged wall: {obj.name} - Scale: {obj.transform.localScale}, Position: {obj.transform.position}");
|
|
|
|
|
+
|
|
|
|
|
+ obj.tag = "Wall";
|
|
|
|
|
+ fixedWalls++;
|
|
|
|
|
+ Debug.Log($"Fixed wall tag for: {obj.name}");
|
|
|
|
|
+
|
|
|
|
|
+ // Also add it to our walls list
|
|
|
|
|
+ if (!walls.Contains(obj))
|
|
|
|
|
+ {
|
|
|
|
|
+ walls.Add(obj);
|
|
|
|
|
+ Debug.Log($"Added newly tagged wall to tracking: {obj.name}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (fixedWalls > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Fixed {fixedWalls} existing walls that weren't properly tagged");
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log("No walls found at all. This might indicate InitialRoomSetup hasn't run or there's a scene setup issue.");
|
|
|
|
|
+
|
|
|
|
|
+ // Debug: List some objects to see what's in the scene
|
|
|
|
|
+ Debug.Log("Sample objects in scene:");
|
|
|
|
|
+ for (int i = 0; i < Mathf.Min(20, allObjects.Length); i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (allObjects[i].name.Contains("Wall") || allObjects[i].name.Contains("wall") ||
|
|
|
|
|
+ allObjects[i].transform.localScale.y > 2f)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($" Potential wall: {allObjects[i].name} - Scale: {allObjects[i].transform.localScale} - Tag: {allObjects[i].tag}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void EnsurePrefabsExist()
|
|
|
|
|
+ {
|
|
|
|
|
+ // Create basic prefabs if they don't exist
|
|
|
|
|
+ if (wallPrefab == null)
|
|
|
|
|
+ {
|
|
|
|
|
+ wallPrefab = CreateWallPrefab();
|
|
|
|
|
+ Debug.Log("Created wall prefab dynamically");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (wallPointPrefab == null)
|
|
|
|
|
+ {
|
|
|
|
|
+ wallPointPrefab = CreateWallPointPrefab();
|
|
|
|
|
+ Debug.Log("Created wall point prefab dynamically");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (doorOpeningPrefab == null)
|
|
|
|
|
+ {
|
|
|
|
|
+ doorOpeningPrefab = CreateDoorOpeningPrefab();
|
|
|
|
|
+ Debug.Log("Created door opening prefab dynamically");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #region Prefab Creation
|
|
|
|
|
+
|
|
|
|
|
+ private GameObject CreateWallPrefab()
|
|
|
|
|
+ {
|
|
|
|
|
+ // Create a parent GameObject for the wall
|
|
|
|
|
+ GameObject wall = new GameObject("Wall_Prefab");
|
|
|
|
|
+
|
|
|
|
|
+ // Add a cube as child for the visual representation
|
|
|
|
|
+ GameObject wallMesh = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
|
|
|
+ wallMesh.name = "WallMesh";
|
|
|
|
|
+ wallMesh.transform.SetParent(wall.transform);
|
|
|
|
|
+ wallMesh.transform.localPosition = Vector3.zero;
|
|
|
|
|
+ wallMesh.transform.localRotation = Quaternion.identity;
|
|
|
|
|
+ wallMesh.transform.localScale = Vector3.one;
|
|
|
|
|
+
|
|
|
|
|
+ // Set up the wall material
|
|
|
|
|
+ Renderer renderer = wallMesh.GetComponent<Renderer>();
|
|
|
|
|
+ Material wallMaterial = new Material(Shader.Find("Universal Render Pipeline/Lit"));
|
|
|
|
|
+
|
|
|
|
|
+ // Set up proper wall color - light gray/beige
|
|
|
|
|
+ wallMaterial.color = new Color(0.9f, 0.9f, 0.8f); // Light beige/cream color
|
|
|
|
|
+
|
|
|
|
|
+ // Make sure it's not metallic and has proper smoothness
|
|
|
|
|
+ wallMaterial.SetFloat("_Metallic", 0.0f);
|
|
|
|
|
+ wallMaterial.SetFloat("_Smoothness", 0.2f);
|
|
|
|
|
+
|
|
|
|
|
+ renderer.material = wallMaterial;
|
|
|
|
|
+
|
|
|
|
|
+ // Ensure the wall has a collider for door placement detection
|
|
|
|
|
+ BoxCollider collider = wallMesh.GetComponent<BoxCollider>();
|
|
|
|
|
+ if (collider == null)
|
|
|
|
|
+ {
|
|
|
|
|
+ collider = wallMesh.AddComponent<BoxCollider>();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ wall.tag = "Wall";
|
|
|
|
|
+
|
|
|
|
|
+ // Don't destroy this object, keep it for instantiation
|
|
|
|
|
+ DontDestroyOnLoad(wall);
|
|
|
|
|
+ wall.SetActive(false); // Hide the template
|
|
|
|
|
+
|
|
|
|
|
+ return wall;
|
|
|
|
|
+ }
|
|
|
|
|
+ private GameObject CreateWallPointPrefab()
|
|
|
|
|
+ {
|
|
|
|
|
+ // Create a parent GameObject for the wall point
|
|
|
|
|
+ GameObject point = new GameObject("WallPoint_Prefab");
|
|
|
|
|
+
|
|
|
|
|
+ // Add a sphere as child for the visual representation
|
|
|
|
|
+ GameObject pointMesh = GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
|
|
|
|
+ pointMesh.name = "PointMesh";
|
|
|
|
|
+ pointMesh.transform.SetParent(point.transform);
|
|
|
|
|
+ pointMesh.transform.localPosition = Vector3.zero;
|
|
|
|
|
+ pointMesh.transform.localRotation = Quaternion.identity;
|
|
|
|
|
+ pointMesh.transform.localScale = Vector3.one * 0.2f;
|
|
|
|
|
+
|
|
|
|
|
+ Renderer renderer = pointMesh.GetComponent<Renderer>();
|
|
|
|
|
+ Material pointMaterial = new Material(Shader.Find("Universal Render Pipeline/Lit"));
|
|
|
|
|
+
|
|
|
|
|
+ // Set up bright red color for wall points
|
|
|
|
|
+ pointMaterial.color = Color.red;
|
|
|
|
|
+ pointMaterial.SetFloat("_Metallic", 0.0f);
|
|
|
|
|
+ pointMaterial.SetFloat("_Smoothness", 0.8f); // Make it a bit shinier for visibility
|
|
|
|
|
+
|
|
|
|
|
+ renderer.material = pointMaterial;
|
|
|
|
|
+
|
|
|
|
|
+ // Remove collider to prevent interference
|
|
|
|
|
+ Collider collider = pointMesh.GetComponent<Collider>();
|
|
|
|
|
+ if (collider != null) DestroyImmediate(collider);
|
|
|
|
|
+
|
|
|
|
|
+ DontDestroyOnLoad(point);
|
|
|
|
|
+ point.SetActive(false); // Hide the template
|
|
|
|
|
+
|
|
|
|
|
+ return point;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private GameObject CreateDoorOpeningPrefab()
|
|
|
|
|
+ {
|
|
|
|
|
+ // Create a parent GameObject for the door frame (visible part)
|
|
|
|
|
+ GameObject door = new GameObject("DoorOpening_Prefab");
|
|
|
|
|
+
|
|
|
|
|
+ // Create door frame - just the frame, not a solid door
|
|
|
|
|
+ GameObject doorFrame = new GameObject("DoorFrame");
|
|
|
|
|
+ doorFrame.transform.SetParent(door.transform);
|
|
|
|
|
+
|
|
|
|
|
+ // Create frame components: left post, right post, top beam
|
|
|
|
|
+ // Posts should be positioned at ground level with proper Y positioning
|
|
|
|
|
+ CreateDoorFramePost(doorFrame, "LeftPost", new Vector3(-doorWidth / 2f, doorHeight / 2f, 0f));
|
|
|
|
|
+ CreateDoorFramePost(doorFrame, "RightPost", new Vector3(doorWidth / 2f, doorHeight / 2f, 0f));
|
|
|
|
|
+ CreateDoorFrameBeam(doorFrame, "TopBeam", new Vector3(0f, doorHeight - 0.1f, 0f));
|
|
|
|
|
+
|
|
|
|
|
+ door.tag = "Door";
|
|
|
|
|
+ DontDestroyOnLoad(door);
|
|
|
|
|
+
|
|
|
|
|
+ return door;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void CreateDoorFramePost(GameObject parent, string name, Vector3 position)
|
|
|
|
|
+ {
|
|
|
|
|
+ GameObject post = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
|
|
|
+ post.name = name;
|
|
|
|
|
+ post.transform.SetParent(parent.transform);
|
|
|
|
|
+ post.transform.localPosition = position;
|
|
|
|
|
+ post.transform.localScale = new Vector3(0.1f, doorHeight, 0.2f); // Thin post
|
|
|
|
|
+
|
|
|
|
|
+ Renderer renderer = post.GetComponent<Renderer>();
|
|
|
|
|
+ Material frameMaterial = new Material(Shader.Find("Universal Render Pipeline/Lit"));
|
|
|
|
|
+ frameMaterial.color = new Color(0.4f, 0.2f, 0.1f); // Brown wood
|
|
|
|
|
+ frameMaterial.SetFloat("_Metallic", 0.0f);
|
|
|
|
|
+ frameMaterial.SetFloat("_Smoothness", 0.3f);
|
|
|
|
|
+ renderer.material = frameMaterial;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void CreateDoorFrameBeam(GameObject parent, string name, Vector3 position)
|
|
|
|
|
+ {
|
|
|
|
|
+ GameObject beam = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
|
|
|
+ beam.name = name;
|
|
|
|
|
+ beam.transform.SetParent(parent.transform);
|
|
|
|
|
+ beam.transform.localPosition = position;
|
|
|
|
|
+ beam.transform.localScale = new Vector3(doorWidth + 0.2f, 0.2f, 0.2f); // Wide beam across top
|
|
|
|
|
+
|
|
|
|
|
+ Renderer renderer = beam.GetComponent<Renderer>();
|
|
|
|
|
+ Material frameMaterial = new Material(Shader.Find("Universal Render Pipeline/Lit"));
|
|
|
|
|
+ frameMaterial.color = new Color(0.4f, 0.2f, 0.1f); // Brown wood
|
|
|
|
|
+ frameMaterial.SetFloat("_Metallic", 0.0f);
|
|
|
|
|
+ frameMaterial.SetFloat("_Smoothness", 0.3f);
|
|
|
|
|
+ renderer.material = frameMaterial;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
|
|
+ #region Main Update Loop
|
|
|
|
|
+
|
|
|
|
|
+ private void Update()
|
|
|
|
|
+ {
|
|
|
|
|
+ switch (currentMode)
|
|
|
|
|
+ {
|
|
|
|
|
+ case BuildingUIController.BuildingMode.CreatingWalls:
|
|
|
|
|
+ HandleWallCreation();
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case BuildingUIController.BuildingMode.CreatingDoors:
|
|
|
|
|
+ HandleDoorPlacement();
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case BuildingUIController.BuildingMode.CreatingEntrance:
|
|
|
|
|
+ HandleEntranceCreation();
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ HandleNormalMode();
|
|
|
|
|
+ HideAllPreviews();
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void SetBuildingMode(BuildingUIController.BuildingMode mode)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Cancel any current wall creation
|
|
|
|
|
+ if (isCreatingWall)
|
|
|
|
|
+ {
|
|
|
|
|
+ CancelWallCreation();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ currentMode = mode;
|
|
|
|
|
+ HideAllPreviews();
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Building mode changed to: {mode}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
|
|
+ #region Normal Mode
|
|
|
|
|
+
|
|
|
|
|
+ private void HandleNormalMode()
|
|
|
|
|
+ {
|
|
|
|
|
+ // In normal mode, allow deletion of entrances with right-click
|
|
|
|
|
+ if (Input.GetMouseButtonDown(1)) // Right click
|
|
|
|
|
+ {
|
|
|
|
|
+ Vector3 mousePos = GetMouseWorldPosition();
|
|
|
|
|
+ CheckForEntranceDeletion(mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void CheckForEntranceDeletion(Vector3 mousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ Ray ray = playerCamera.ScreenPointToRay(Input.mousePosition);
|
|
|
|
|
+
|
|
|
|
|
+ if (Physics.Raycast(ray, out RaycastHit hit, 1000f))
|
|
|
|
|
+ {
|
|
|
|
|
+ GameObject hitObj = hit.collider.gameObject;
|
|
|
|
|
+
|
|
|
|
|
+ // Check if we hit an entrance or entrance component
|
|
|
|
|
+ GameObject entranceToDelete = null;
|
|
|
|
|
+
|
|
|
|
|
+ if (hitObj.CompareTag("Entrance"))
|
|
|
|
|
+ {
|
|
|
|
|
+ entranceToDelete = hitObj;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (hitObj.transform.parent != null && hitObj.transform.parent.CompareTag("Entrance"))
|
|
|
|
|
+ {
|
|
|
|
|
+ entranceToDelete = hitObj.transform.parent.gameObject;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (entranceToDelete != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Deleting entrance: {entranceToDelete.name}");
|
|
|
|
|
+ DestroyImmediate(entranceToDelete);
|
|
|
|
|
+
|
|
|
|
|
+ // Note: The wall segments around the entrance will remain
|
|
|
|
|
+ // This creates a permanent opening where the entrance was
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
|
|
+ #region Wall Creation
|
|
|
|
|
+
|
|
|
|
|
+ private void HandleWallCreation()
|
|
|
|
|
+ {
|
|
|
|
|
+ Vector3 mousePos = GetMouseWorldPosition();
|
|
|
|
|
+
|
|
|
|
|
+ if (Input.GetMouseButtonDown(0)) // Left click
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!isCreatingWall)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Start creating a wall
|
|
|
|
|
+ StartWallCreation(mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Finish creating the wall
|
|
|
|
|
+ FinishWallCreation(mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (Input.GetMouseButtonDown(1)) // Right click
|
|
|
|
|
+ {
|
|
|
|
|
+ // Cancel wall creation
|
|
|
|
|
+ if (isCreatingWall)
|
|
|
|
|
+ {
|
|
|
|
|
+ CancelWallCreation();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Update preview while creating wall
|
|
|
|
|
+ if (isCreatingWall)
|
|
|
|
|
+ {
|
|
|
|
|
+ UpdateWallPreview(mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void StartWallCreation(Vector3 startPoint)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Snap to nearby existing points
|
|
|
|
|
+ Vector3 snappedStart = SnapToNearbyPoint(startPoint);
|
|
|
|
|
+
|
|
|
|
|
+ wallStartPoint = snappedStart;
|
|
|
|
|
+ isCreatingWall = true;
|
|
|
|
|
+
|
|
|
|
|
+ // Show preview
|
|
|
|
|
+ if (previewLine != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ previewLine.enabled = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Started wall creation at: {wallStartPoint}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void UpdateWallPreview(Vector3 currentMousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!isCreatingWall || previewLine == null) return;
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate snapped end point
|
|
|
|
|
+ Vector3 snappedEndPoint = SnapToAngle(wallStartPoint, currentMousePos);
|
|
|
|
|
+ Vector3 finalSnappedPoint = SnapToNearbyPoint(snappedEndPoint);
|
|
|
|
|
+
|
|
|
|
|
+ // Show snap indicator if we're snapping to something
|
|
|
|
|
+ if (Vector3.Distance(finalSnappedPoint, snappedEndPoint) > 0.1f)
|
|
|
|
|
+ {
|
|
|
|
|
+ ShowSnapIndicator(finalSnappedPoint);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ HideSnapIndicator();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Update preview line
|
|
|
|
|
+ previewLine.SetPosition(0, wallStartPoint);
|
|
|
|
|
+ previewLine.SetPosition(1, finalSnappedPoint);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void ShowSnapIndicator(Vector3 position)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (snapIndicator != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ snapIndicator.transform.position = position;
|
|
|
|
|
+ snapIndicator.SetActive(true);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void HideSnapIndicator()
|
|
|
|
|
+ {
|
|
|
|
|
+ if (snapIndicator != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ snapIndicator.SetActive(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void FinishWallCreation(Vector3 endPoint)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!isCreatingWall) return;
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate snapped end point
|
|
|
|
|
+ Vector3 snappedEndPoint = SnapToAngle(wallStartPoint, endPoint);
|
|
|
|
|
+ snappedEndPoint = SnapToNearbyPoint(snappedEndPoint);
|
|
|
|
|
+
|
|
|
|
|
+ // Create the actual wall
|
|
|
|
|
+ CreateWall(wallStartPoint, snappedEndPoint);
|
|
|
|
|
+
|
|
|
|
|
+ // Reset state
|
|
|
|
|
+ isCreatingWall = false;
|
|
|
|
|
+ if (previewLine != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ previewLine.enabled = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Created wall from {wallStartPoint} to {snappedEndPoint}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void CancelWallCreation()
|
|
|
|
|
+ {
|
|
|
|
|
+ isCreatingWall = false;
|
|
|
|
|
+ if (previewLine != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ previewLine.enabled = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log("Wall creation cancelled");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Vector3 SnapToAngle(Vector3 startPoint, Vector3 endPoint)
|
|
|
|
|
+ {
|
|
|
|
|
+ Vector3 direction = (endPoint - startPoint).normalized;
|
|
|
|
|
+ float distance = Vector3.Distance(startPoint, endPoint);
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate angle in degrees
|
|
|
|
|
+ float currentAngle = Mathf.Atan2(direction.z, direction.x) * Mathf.Rad2Deg;
|
|
|
|
|
+ if (currentAngle < 0) currentAngle += 360f;
|
|
|
|
|
+
|
|
|
|
|
+ // Find closest snap angle
|
|
|
|
|
+ float closestAngle = snapAngles[0];
|
|
|
|
|
+ float smallestDifference = Mathf.Abs(currentAngle - closestAngle);
|
|
|
|
|
+
|
|
|
|
|
+ foreach (float angle in snapAngles)
|
|
|
|
|
+ {
|
|
|
|
|
+ float difference = Mathf.Abs(currentAngle - angle);
|
|
|
|
|
+ if (difference > 180f) difference = 360f - difference; // Handle wrapping
|
|
|
|
|
+
|
|
|
|
|
+ if (difference < smallestDifference)
|
|
|
|
|
+ {
|
|
|
|
|
+ smallestDifference = difference;
|
|
|
|
|
+ closestAngle = angle;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate snapped direction
|
|
|
|
|
+ float rad = closestAngle * Mathf.Deg2Rad;
|
|
|
|
|
+ Vector3 snappedDirection = new Vector3(Mathf.Cos(rad), 0f, Mathf.Sin(rad));
|
|
|
|
|
+
|
|
|
|
|
+ return startPoint + snappedDirection * distance;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Vector3 SnapToNearbyPoint(Vector3 point)
|
|
|
|
|
+ {
|
|
|
|
|
+ float closestCornerDistance = float.MaxValue;
|
|
|
|
|
+ float closestWallDistance = float.MaxValue;
|
|
|
|
|
+ Vector3 closestCornerPoint = point;
|
|
|
|
|
+ Vector3 closestWallPoint = point;
|
|
|
|
|
+ bool foundCorner = false;
|
|
|
|
|
+
|
|
|
|
|
+ foreach (GameObject wall in walls)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (wall == null) continue;
|
|
|
|
|
+
|
|
|
|
|
+ // First priority: Check both endpoints of the wall (corners)
|
|
|
|
|
+ Vector3[] endpoints = GetWallEndpoints(wall);
|
|
|
|
|
+ foreach (Vector3 endpoint in endpoints)
|
|
|
|
|
+ {
|
|
|
|
|
+ float distance = Vector3.Distance(point, endpoint);
|
|
|
|
|
+ if (distance < snapDistance && distance < closestCornerDistance)
|
|
|
|
|
+ {
|
|
|
|
|
+ closestCornerDistance = distance;
|
|
|
|
|
+ closestCornerPoint = endpoint;
|
|
|
|
|
+ foundCorner = true;
|
|
|
|
|
+ Debug.Log($"Found corner snap point at {endpoint}, distance: {distance}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Second priority: Check snapping to wall surface/center (only if no corner found nearby)
|
|
|
|
|
+ if (!foundCorner || closestCornerDistance > snapDistance * 0.7f) // Allow wall snapping if no close corner
|
|
|
|
|
+ {
|
|
|
|
|
+ Vector3 wallCenter = wall.transform.position;
|
|
|
|
|
+ wallCenter.y = 0f; // Project to ground level
|
|
|
|
|
+
|
|
|
|
|
+ // Project point onto wall line to find closest point on wall
|
|
|
|
|
+ Vector3 wallDirection = wall.transform.forward;
|
|
|
|
|
+ Vector3 toPoint = point - wallCenter;
|
|
|
|
|
+ float projection = Vector3.Dot(toPoint, wallDirection);
|
|
|
|
|
+
|
|
|
|
|
+ // Clamp projection to wall bounds
|
|
|
|
|
+ float wallLength = wall.transform.localScale.z;
|
|
|
|
|
+ projection = Mathf.Clamp(projection, -wallLength / 2f, wallLength / 2f);
|
|
|
|
|
+
|
|
|
|
|
+ Vector3 closestPointOnWall = wallCenter + wallDirection * projection;
|
|
|
|
|
+ float wallDistance = Vector3.Distance(point, closestPointOnWall);
|
|
|
|
|
+
|
|
|
|
|
+ // Snap to wall surface if clicking near the wall
|
|
|
|
|
+ if (wallDistance < snapDistance && wallDistance < closestWallDistance)
|
|
|
|
|
+ {
|
|
|
|
|
+ closestWallDistance = wallDistance;
|
|
|
|
|
+ closestWallPoint = closestPointOnWall;
|
|
|
|
|
+ Debug.Log($"Found wall surface snap point at {closestPointOnWall}, distance: {wallDistance}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Return the best snap point: prioritize corners over wall surfaces
|
|
|
|
|
+ if (foundCorner && closestCornerDistance < snapDistance)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Using corner snap point: {closestCornerPoint}");
|
|
|
|
|
+ UpdateSnapIndicatorColor(true); // Corner = cyan
|
|
|
|
|
+ return closestCornerPoint;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (closestWallDistance < snapDistance)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Using wall surface snap point: {closestWallPoint}");
|
|
|
|
|
+ UpdateSnapIndicatorColor(false); // Wall surface = yellow
|
|
|
|
|
+ return closestWallPoint;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"No snap point found, using original point: {point}");
|
|
|
|
|
+ return point;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void UpdateSnapIndicatorColor(bool isCorner)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (snapIndicator != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Renderer renderer = snapIndicator.GetComponent<Renderer>();
|
|
|
|
|
+ if (renderer != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Color indicatorColor = isCorner ? Color.cyan : Color.yellow;
|
|
|
|
|
+ Color emissionColor = indicatorColor * 2f;
|
|
|
|
|
+
|
|
|
|
|
+ renderer.material.color = indicatorColor;
|
|
|
|
|
+ renderer.material.SetColor("_EmissionColor", emissionColor);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void CreateWall(Vector3 startPoint, Vector3 endPoint)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (Vector3.Distance(startPoint, endPoint) < 0.1f) return; // Too short
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate wall properties
|
|
|
|
|
+ Vector3 center = (startPoint + endPoint) / 2f;
|
|
|
|
|
+ center.y = wallHeight / 2f; // Set proper height
|
|
|
|
|
+
|
|
|
|
|
+ Vector3 direction = (endPoint - startPoint).normalized;
|
|
|
|
|
+ float length = Vector3.Distance(startPoint, endPoint);
|
|
|
|
|
+
|
|
|
|
|
+ // Create wall object from prefab
|
|
|
|
|
+ GameObject wall = Instantiate(wallPrefab, center, Quaternion.LookRotation(direction, Vector3.up));
|
|
|
|
|
+ wall.SetActive(true); // Make sure it's visible
|
|
|
|
|
+
|
|
|
|
|
+ // Scale the entire wall object to proper dimensions:
|
|
|
|
|
+ // X = thickness (perpendicular to wall direction)
|
|
|
|
|
+ // Y = height (up/down)
|
|
|
|
|
+ // Z = length (along the wall direction)
|
|
|
|
|
+ wall.transform.localScale = new Vector3(wallThickness, wallHeight, length);
|
|
|
|
|
+
|
|
|
|
|
+ // Set wall name and add to list
|
|
|
|
|
+ wall.name = $"Wall_{walls.Count}";
|
|
|
|
|
+ walls.Add(wall);
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Created wall: {wall.name} from {startPoint} to {endPoint}, length: {length}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
|
|
+ #region Door Placement
|
|
|
|
|
+
|
|
|
|
|
+ private void HandleDoorPlacement()
|
|
|
|
|
+ {
|
|
|
|
|
+ Vector3 mousePos = GetMouseWorldPosition();
|
|
|
|
|
+
|
|
|
|
|
+ // Find wall under mouse
|
|
|
|
|
+ GameObject wallUnderMouse = FindWallUnderMouse(mousePos);
|
|
|
|
|
+
|
|
|
|
|
+ // Update hover preview
|
|
|
|
|
+ UpdateDoorPreview(wallUnderMouse, mousePos);
|
|
|
|
|
+
|
|
|
|
|
+ if (Input.GetMouseButtonDown(0)) // Left click
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Door placement click detected at {mousePos}");
|
|
|
|
|
+ if (wallUnderMouse != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Wall found under mouse: {wallUnderMouse.name}");
|
|
|
|
|
+ PlaceDoorOnWall(wallUnderMouse, mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.LogWarning("No wall found under mouse cursor for door placement");
|
|
|
|
|
+ // Let's try a different approach - check nearby walls
|
|
|
|
|
+ GameObject nearestWall = FindNearestWall(mousePos);
|
|
|
|
|
+ if (nearestWall != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Found nearest wall: {nearestWall.name}, placing door there");
|
|
|
|
|
+ PlaceDoorOnWall(nearestWall, mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.LogWarning("No walls found nearby for door placement");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void UpdateDoorPreview(GameObject wall, Vector3 mousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (wall != hoveredWall)
|
|
|
|
|
+ {
|
|
|
|
|
+ hoveredWall = wall;
|
|
|
|
|
+
|
|
|
|
|
+ if (wall != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ ShowDoorPreview(wall, mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ HideDoorPreview();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (wall != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Update preview position
|
|
|
|
|
+ ShowDoorPreview(wall, mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void ShowDoorPreview(GameObject wall, Vector3 mousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (doorPreview == null) return;
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate door position on the wall
|
|
|
|
|
+ Vector3 doorPosition = CalculateDoorPositionOnWall(wall, mousePos);
|
|
|
|
|
+
|
|
|
|
|
+ // Position and orient the preview - door should face perpendicular to wall
|
|
|
|
|
+ doorPreview.transform.position = doorPosition;
|
|
|
|
|
+ doorPreview.transform.rotation = Quaternion.LookRotation(wall.transform.right);
|
|
|
|
|
+ doorPreview.SetActive(true);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void HideDoorPreview()
|
|
|
|
|
+ {
|
|
|
|
|
+ if (doorPreview != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ doorPreview.SetActive(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void PlaceDoorOnWall(GameObject wall, Vector3 mousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Attempting to place door on {wall.name} at mouse position {mousePos}");
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate door position
|
|
|
|
|
+ Vector3 doorPosition = CalculateDoorPositionOnWall(wall, mousePos);
|
|
|
|
|
+ Debug.Log($"Calculated door position: {doorPosition}");
|
|
|
|
|
+
|
|
|
|
|
+ // Check if door would intersect with existing doors
|
|
|
|
|
+ if (WouldDoorIntersectExistingDoors(wall, doorPosition))
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.LogWarning("Cannot place door - would intersect with existing door");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Get wall endpoints and direction for splitting
|
|
|
|
|
+ Vector3[] wallEndpoints = GetWallEndpoints(wall);
|
|
|
|
|
+ Vector3 wallStart = wallEndpoints[0];
|
|
|
|
|
+ Vector3 wallEnd = wallEndpoints[1];
|
|
|
|
|
+ Vector3 wallDirection = wall.transform.forward;
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate door boundaries along the wall
|
|
|
|
|
+ Vector3 doorStart = doorPosition - wallDirection * (doorWidth / 2f);
|
|
|
|
|
+ Vector3 doorEnd = doorPosition + wallDirection * (doorWidth / 2f);
|
|
|
|
|
+
|
|
|
|
|
+ // Create door at wall position with proper rotation
|
|
|
|
|
+ // Door should face perpendicular to the wall direction (reuse existing wallDirection)
|
|
|
|
|
+ Quaternion doorRotation = Quaternion.LookRotation(wall.transform.right); // Face perpendicular to wall
|
|
|
|
|
+
|
|
|
|
|
+ GameObject door = Instantiate(doorOpeningPrefab, doorPosition, doorRotation);
|
|
|
|
|
+ door.SetActive(true);
|
|
|
|
|
+ door.name = $"Door_on_{wall.name}";
|
|
|
|
|
+
|
|
|
|
|
+ // Split the original wall into two segments around the door
|
|
|
|
|
+ SplitWallAroundDoor(wall, wallStart, wallEnd, doorStart, doorEnd);
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Successfully placed door: {door.name} and split wall into segments");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private bool WouldDoorIntersectExistingDoors(GameObject wall, Vector3 doorPosition)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Find all existing doors
|
|
|
|
|
+ GameObject[] existingDoors = GameObject.FindGameObjectsWithTag("Door");
|
|
|
|
|
+
|
|
|
|
|
+ foreach (GameObject existingDoor in existingDoors)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Check if doors are on the same wall or parallel walls
|
|
|
|
|
+ float distance = Vector3.Distance(doorPosition, existingDoor.transform.position);
|
|
|
|
|
+ if (distance < doorWidth * 1.5f) // Doors too close
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Door too close to existing door {existingDoor.name}: distance = {distance}");
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void SplitWallAroundDoor(GameObject originalWall, Vector3 wallStart, Vector3 wallEnd, Vector3 doorStart, Vector3 doorEnd)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Calculate the two new wall segments
|
|
|
|
|
+ float originalWallLength = Vector3.Distance(wallStart, wallEnd);
|
|
|
|
|
+ float leftSegmentLength = Vector3.Distance(wallStart, doorStart);
|
|
|
|
|
+ float rightSegmentLength = Vector3.Distance(doorEnd, wallEnd);
|
|
|
|
|
+
|
|
|
|
|
+ // Only create segments if they're long enough
|
|
|
|
|
+ bool createLeftSegment = leftSegmentLength > 0.1f;
|
|
|
|
|
+ bool createRightSegment = rightSegmentLength > 0.1f;
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Splitting wall: original length = {originalWallLength}, left = {leftSegmentLength}, right = {rightSegmentLength}");
|
|
|
|
|
+
|
|
|
|
|
+ if (createLeftSegment)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Create left wall segment - full height
|
|
|
|
|
+ Vector3 leftCenter = (wallStart + doorStart) / 2f;
|
|
|
|
|
+ leftCenter.y = wallHeight / 2f;
|
|
|
|
|
+
|
|
|
|
|
+ GameObject leftWall = Instantiate(wallPrefab, leftCenter, originalWall.transform.rotation);
|
|
|
|
|
+ leftWall.SetActive(true);
|
|
|
|
|
+ leftWall.name = $"{originalWall.name}_Left";
|
|
|
|
|
+ leftWall.transform.localScale = new Vector3(wallThickness, wallHeight, leftSegmentLength);
|
|
|
|
|
+
|
|
|
|
|
+ walls.Add(leftWall);
|
|
|
|
|
+ Debug.Log($"Created left wall segment: {leftWall.name}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (createRightSegment)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Create right wall segment - full height
|
|
|
|
|
+ Vector3 rightCenter = (doorEnd + wallEnd) / 2f;
|
|
|
|
|
+ rightCenter.y = wallHeight / 2f;
|
|
|
|
|
+
|
|
|
|
|
+ GameObject rightWall = Instantiate(wallPrefab, rightCenter, originalWall.transform.rotation);
|
|
|
|
|
+ rightWall.SetActive(true);
|
|
|
|
|
+ rightWall.name = $"{originalWall.name}_Right";
|
|
|
|
|
+ rightWall.transform.localScale = new Vector3(wallThickness, wallHeight, rightSegmentLength);
|
|
|
|
|
+
|
|
|
|
|
+ walls.Add(rightWall);
|
|
|
|
|
+ Debug.Log($"Created right wall segment: {rightWall.name}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Create header beam above the door (if there are segments on both sides)
|
|
|
|
|
+ if (createLeftSegment && createRightSegment)
|
|
|
|
|
+ {
|
|
|
|
|
+ CreateDoorHeaderBeam(originalWall, doorStart, doorEnd);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Remove original wall from list and destroy it
|
|
|
|
|
+ walls.Remove(originalWall);
|
|
|
|
|
+ DestroyImmediate(originalWall);
|
|
|
|
|
+ Debug.Log("Removed original wall after splitting");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void CreateDoorHeaderBeam(GameObject originalWall, Vector3 doorStart, Vector3 doorEnd)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Create beam above door opening
|
|
|
|
|
+ Vector3 beamCenter = (doorStart + doorEnd) / 2f;
|
|
|
|
|
+ beamCenter.y = doorHeight + 0.1f; // Just above the door
|
|
|
|
|
+
|
|
|
|
|
+ GameObject headerBeam = Instantiate(wallPrefab, beamCenter, originalWall.transform.rotation);
|
|
|
|
|
+ headerBeam.SetActive(true);
|
|
|
|
|
+ headerBeam.name = $"{originalWall.name}_Header";
|
|
|
|
|
+
|
|
|
|
|
+ float beamLength = Vector3.Distance(doorStart, doorEnd);
|
|
|
|
|
+ float beamHeight = wallHeight - doorHeight - 0.1f; // Remaining height above door
|
|
|
|
|
+
|
|
|
|
|
+ if (beamHeight > 0.1f) // Only create beam if there's significant height remaining
|
|
|
|
|
+ {
|
|
|
|
|
+ headerBeam.transform.localScale = new Vector3(wallThickness, beamHeight, beamLength);
|
|
|
|
|
+ walls.Add(headerBeam);
|
|
|
|
|
+ Debug.Log($"Created door header beam: {headerBeam.name}");
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // If no room for header beam, destroy it
|
|
|
|
|
+ DestroyImmediate(headerBeam);
|
|
|
|
|
+ Debug.Log("Door is full height - no header beam needed");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
|
|
+ #region Entrance Creation
|
|
|
|
|
+
|
|
|
|
|
+ private void HandleEntranceCreation()
|
|
|
|
|
+ {
|
|
|
|
|
+ Vector3 mousePos = GetMouseWorldPosition();
|
|
|
|
|
+
|
|
|
|
|
+ // Find wall under mouse
|
|
|
|
|
+ GameObject wallUnderMouse = FindWallUnderMouse(mousePos);
|
|
|
|
|
+
|
|
|
|
|
+ // Update entrance preview (similar to door but different style)
|
|
|
|
|
+ UpdateEntrancePreview(wallUnderMouse, mousePos);
|
|
|
|
|
+
|
|
|
|
|
+ if (Input.GetMouseButtonDown(0)) // Left click
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Entrance placement click detected at {mousePos}");
|
|
|
|
|
+ if (wallUnderMouse != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Wall found under mouse: {wallUnderMouse.name}");
|
|
|
|
|
+ PlaceEntranceOnWall(wallUnderMouse, mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.LogWarning("No wall found under mouse cursor for entrance placement");
|
|
|
|
|
+
|
|
|
|
|
+ // Try alternative detection method first
|
|
|
|
|
+ GameObject alternativeWall = FindWallUnderMouseAlternative(mousePos);
|
|
|
|
|
+ if (alternativeWall != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Alternative method found wall: {alternativeWall.name}, placing entrance there");
|
|
|
|
|
+ PlaceEntranceOnWall(alternativeWall, mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Let's try a different approach - check nearby walls
|
|
|
|
|
+ GameObject nearestWall = FindNearestWall(mousePos);
|
|
|
|
|
+ if (nearestWall != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Found nearest wall: {nearestWall.name}, placing entrance there");
|
|
|
|
|
+ PlaceEntranceOnWall(nearestWall, mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.LogWarning("No walls found nearby for entrance placement");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void UpdateEntrancePreview(GameObject wall, Vector3 mousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (wall != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ ShowEntrancePreview(wall, mousePos);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ HideEntrancePreview();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void ShowEntrancePreview(GameObject wall, Vector3 mousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (doorPreview == null) return; // Reuse door preview for now
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate entrance position on the wall
|
|
|
|
|
+ Vector3 entrancePosition = CalculateDoorPositionOnWall(wall, mousePos);
|
|
|
|
|
+
|
|
|
|
|
+ // Position and orient the preview - entrance should face perpendicular to wall
|
|
|
|
|
+ doorPreview.transform.position = entrancePosition;
|
|
|
|
|
+ doorPreview.transform.rotation = Quaternion.LookRotation(wall.transform.right);
|
|
|
|
|
+
|
|
|
|
|
+ // Make entrance preview slightly different (maybe different scale or color)
|
|
|
|
|
+ doorPreview.transform.localScale = new Vector3(0.2f, doorHeight, doorWidth * 1.2f); // Slightly wider
|
|
|
|
|
+ doorPreview.SetActive(true);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void HideEntrancePreview()
|
|
|
|
|
+ {
|
|
|
|
|
+ if (doorPreview != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ doorPreview.SetActive(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void PlaceEntranceOnWall(GameObject wall, Vector3 mousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Attempting to place entrance on {wall.name} at mouse position {mousePos}");
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate entrance position on the wall surface
|
|
|
|
|
+ Vector3 entrancePosition = CalculateDoorPositionOnWall(wall, mousePos);
|
|
|
|
|
+ Debug.Log($"Calculated entrance position: {entrancePosition}");
|
|
|
|
|
+
|
|
|
|
|
+ // Check if there's already an entrance
|
|
|
|
|
+ GameObject[] existingEntrances = GameObject.FindGameObjectsWithTag("Entrance");
|
|
|
|
|
+ if (existingEntrances.Length > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.LogWarning("Building already has an entrance. Replacing existing entrance.");
|
|
|
|
|
+ foreach (GameObject existingEntrance in existingEntrances)
|
|
|
|
|
+ {
|
|
|
|
|
+ DestroyImmediate(existingEntrance);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Determine wall orientation based on its scale
|
|
|
|
|
+ Vector3 wallScale = wall.transform.localScale;
|
|
|
|
|
+ bool isNorthSouthWall = wallScale.x > wallScale.z; // Wide in X means North/South wall
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Wall scale: {wallScale}, isNorthSouthWall: {isNorthSouthWall}");
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate entrance boundaries and determine how to split the wall
|
|
|
|
|
+ float entranceWidth = doorWidth * 1.5f;
|
|
|
|
|
+
|
|
|
|
|
+ // Create entrance with proper rotation
|
|
|
|
|
+ GameObject entrance = CreateEntrancePrefab();
|
|
|
|
|
+ entrance.transform.position = entrancePosition;
|
|
|
|
|
+
|
|
|
|
|
+ // Set rotation based on wall orientation
|
|
|
|
|
+ if (isNorthSouthWall)
|
|
|
|
|
+ {
|
|
|
|
|
+ // For North/South walls (extending in X), entrance should face along Z-axis
|
|
|
|
|
+ entrance.transform.rotation = Quaternion.identity; // Facing forward (positive Z)
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // For East/West walls (extending in Z), entrance should face along X-axis
|
|
|
|
|
+ entrance.transform.rotation = Quaternion.Euler(0, 90, 0); // Facing right (positive X)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ entrance.SetActive(true);
|
|
|
|
|
+ entrance.name = "BuildingEntrance";
|
|
|
|
|
+ entrance.tag = "Entrance";
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Placed entrance at {entrance.transform.position} with rotation {entrance.transform.rotation.eulerAngles}");
|
|
|
|
|
+
|
|
|
|
|
+ // Split the wall properly based on its orientation
|
|
|
|
|
+ SplitWallForEntrance(wall, entrancePosition, entranceWidth, isNorthSouthWall);
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Successfully placed entrance and split wall");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void SplitWallForEntrance(GameObject originalWall, Vector3 entrancePosition, float entranceWidth, bool isNorthSouthWall)
|
|
|
|
|
+ {
|
|
|
|
|
+ Vector3 wallPos = originalWall.transform.position;
|
|
|
|
|
+ Vector3 wallScale = originalWall.transform.localScale;
|
|
|
|
|
+ Quaternion wallRotation = originalWall.transform.rotation;
|
|
|
|
|
+
|
|
|
|
|
+ // Get the original wall's material to maintain consistency
|
|
|
|
|
+ Material originalMaterial = originalWall.GetComponent<Renderer>()?.material;
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Splitting wall: {originalWall.name} at position {wallPos} with scale {wallScale}");
|
|
|
|
|
+
|
|
|
|
|
+ if (isNorthSouthWall)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Wall extends in X direction, split along X-axis
|
|
|
|
|
+ float wallLength = wallScale.x; // Corrected: X is the length for North/South walls
|
|
|
|
|
+ float wallLeft = wallPos.x - wallLength / 2f;
|
|
|
|
|
+ float wallRight = wallPos.x + wallLength / 2f;
|
|
|
|
|
+
|
|
|
|
|
+ float entranceLeft = entrancePosition.x - entranceWidth / 2f;
|
|
|
|
|
+ float entranceRight = entrancePosition.x + entranceWidth / 2f;
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"North/South wall split: wallLeft={wallLeft}, wallRight={wallRight}, entranceLeft={entranceLeft}, entranceRight={entranceRight}");
|
|
|
|
|
+
|
|
|
|
|
+ // Create left segment if there's enough space
|
|
|
|
|
+ if (entranceLeft - wallLeft > 0.5f)
|
|
|
|
|
+ {
|
|
|
|
|
+ float leftLength = entranceLeft - wallLeft;
|
|
|
|
|
+ Vector3 leftCenter = new Vector3(wallLeft + leftLength / 2f, wallPos.y, wallPos.z);
|
|
|
|
|
+
|
|
|
|
|
+ GameObject leftWall = Instantiate(wallPrefab, leftCenter, wallRotation);
|
|
|
|
|
+ leftWall.SetActive(true);
|
|
|
|
|
+ leftWall.name = $"{originalWall.name}_Left_Entrance";
|
|
|
|
|
+ leftWall.transform.localScale = new Vector3(leftLength, wallScale.y, wallScale.z);
|
|
|
|
|
+ leftWall.tag = "Wall";
|
|
|
|
|
+
|
|
|
|
|
+ // Apply original material if available
|
|
|
|
|
+ if (originalMaterial != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ leftWall.GetComponent<Renderer>().material = originalMaterial;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ walls.Add(leftWall);
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Created left wall segment: scale {leftWall.transform.localScale} at {leftWall.transform.position}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Create right segment if there's enough space
|
|
|
|
|
+ if (wallRight - entranceRight > 0.5f)
|
|
|
|
|
+ {
|
|
|
|
|
+ float rightLength = wallRight - entranceRight;
|
|
|
|
|
+ Vector3 rightCenter = new Vector3(entranceRight + rightLength / 2f, wallPos.y, wallPos.z);
|
|
|
|
|
+
|
|
|
|
|
+ GameObject rightWall = Instantiate(wallPrefab, rightCenter, wallRotation);
|
|
|
|
|
+ rightWall.SetActive(true);
|
|
|
|
|
+ rightWall.name = $"{originalWall.name}_Right_Entrance";
|
|
|
|
|
+ rightWall.transform.localScale = new Vector3(rightLength, wallScale.y, wallScale.z);
|
|
|
|
|
+ rightWall.tag = "Wall";
|
|
|
|
|
+
|
|
|
|
|
+ // Apply original material if available
|
|
|
|
|
+ if (originalMaterial != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ rightWall.GetComponent<Renderer>().material = originalMaterial;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ walls.Add(rightWall);
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Created right wall segment: scale {rightWall.transform.localScale} at {rightWall.transform.position}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Wall extends in Z direction, split along Z-axis
|
|
|
|
|
+ float wallLength = wallScale.z;
|
|
|
|
|
+ float wallFront = wallPos.z - wallLength / 2f;
|
|
|
|
|
+ float wallBack = wallPos.z + wallLength / 2f;
|
|
|
|
|
+
|
|
|
|
|
+ float entranceFront = entrancePosition.z - entranceWidth / 2f;
|
|
|
|
|
+ float entranceBack = entrancePosition.z + entranceWidth / 2f;
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"East/West wall split: wallFront={wallFront}, wallBack={wallBack}, entranceFront={entranceFront}, entranceBack={entranceBack}");
|
|
|
|
|
+
|
|
|
|
|
+ // Create front segment if there's enough space
|
|
|
|
|
+ if (entranceFront - wallFront > 0.5f)
|
|
|
|
|
+ {
|
|
|
|
|
+ float frontLength = entranceFront - wallFront;
|
|
|
|
|
+ Vector3 frontCenter = new Vector3(wallPos.x, wallPos.y, wallFront + frontLength / 2f);
|
|
|
|
|
+
|
|
|
|
|
+ GameObject frontWall = Instantiate(wallPrefab, frontCenter, wallRotation);
|
|
|
|
|
+ frontWall.SetActive(true);
|
|
|
|
|
+ frontWall.name = $"{originalWall.name}_Front_Entrance";
|
|
|
|
|
+ frontWall.transform.localScale = new Vector3(wallScale.x, wallScale.y, frontLength);
|
|
|
|
|
+ frontWall.tag = "Wall";
|
|
|
|
|
+
|
|
|
|
|
+ // Apply original material if available
|
|
|
|
|
+ if (originalMaterial != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ frontWall.GetComponent<Renderer>().material = originalMaterial;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ walls.Add(frontWall);
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Created front wall segment: scale {frontWall.transform.localScale} at {frontWall.transform.position}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Create back segment if there's enough space
|
|
|
|
|
+ if (wallBack - entranceBack > 0.5f)
|
|
|
|
|
+ {
|
|
|
|
|
+ float backLength = wallBack - entranceBack;
|
|
|
|
|
+ Vector3 backCenter = new Vector3(wallPos.x, wallPos.y, entranceBack + backLength / 2f);
|
|
|
|
|
+
|
|
|
|
|
+ GameObject backWall = Instantiate(wallPrefab, backCenter, wallRotation);
|
|
|
|
|
+ backWall.SetActive(true);
|
|
|
|
|
+ backWall.name = $"{originalWall.name}_Back_Entrance";
|
|
|
|
|
+ backWall.transform.localScale = new Vector3(wallScale.x, wallScale.y, backLength);
|
|
|
|
|
+ backWall.tag = "Wall";
|
|
|
|
|
+
|
|
|
|
|
+ // Apply original material if available
|
|
|
|
|
+ if (originalMaterial != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ backWall.GetComponent<Renderer>().material = originalMaterial;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ walls.Add(backWall);
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Created back wall segment: scale {backWall.transform.localScale} at {backWall.transform.position}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Remove original wall
|
|
|
|
|
+ walls.Remove(originalWall);
|
|
|
|
|
+ DestroyImmediate(originalWall);
|
|
|
|
|
+ Debug.Log("Removed original wall after splitting for entrance");
|
|
|
|
|
+ }
|
|
|
|
|
+ private GameObject CreateEntrancePrefab()
|
|
|
|
|
+ {
|
|
|
|
|
+ // Create a more elaborate entrance than a regular door
|
|
|
|
|
+ GameObject entrance = new GameObject("BuildingEntrance");
|
|
|
|
|
+
|
|
|
|
|
+ // Create entrance frame - wider and more elaborate
|
|
|
|
|
+ GameObject entranceFrame = new GameObject("EntranceFrame");
|
|
|
|
|
+ entranceFrame.transform.SetParent(entrance.transform);
|
|
|
|
|
+
|
|
|
|
|
+ float entranceWidth = doorWidth * 1.5f;
|
|
|
|
|
+
|
|
|
|
|
+ // Create frame components: left post, right post, top beam, and entrance mat
|
|
|
|
|
+ CreateEntrancePost(entranceFrame, "LeftPost", new Vector3(-entranceWidth / 2f, doorHeight / 2f, 0f), entranceWidth);
|
|
|
|
|
+ CreateEntrancePost(entranceFrame, "RightPost", new Vector3(entranceWidth / 2f, doorHeight / 2f, 0f), entranceWidth);
|
|
|
|
|
+ CreateEntranceBeam(entranceFrame, "TopBeam", new Vector3(0f, doorHeight - 0.1f, 0f), entranceWidth);
|
|
|
|
|
+ CreateEntranceMat(entranceFrame, "WelcomeMat", new Vector3(0f, 0.05f, 1f), entranceWidth);
|
|
|
|
|
+
|
|
|
|
|
+ entrance.tag = "Entrance";
|
|
|
|
|
+ DontDestroyOnLoad(entrance);
|
|
|
|
|
+
|
|
|
|
|
+ return entrance;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void CreateEntrancePost(GameObject parent, string name, Vector3 position, float width)
|
|
|
|
|
+ {
|
|
|
|
|
+ GameObject post = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
|
|
|
+ post.name = name;
|
|
|
|
|
+ post.transform.SetParent(parent.transform);
|
|
|
|
|
+ post.transform.localPosition = position;
|
|
|
|
|
+ post.transform.localScale = new Vector3(0.15f, doorHeight, 0.3f); // Slightly thicker than door posts
|
|
|
|
|
+
|
|
|
|
|
+ Renderer renderer = post.GetComponent<Renderer>();
|
|
|
|
|
+ Material frameMaterial = new Material(Shader.Find("Universal Render Pipeline/Lit"));
|
|
|
|
|
+ frameMaterial.color = new Color(0.3f, 0.15f, 0.05f); // Darker brown for entrance
|
|
|
|
|
+ frameMaterial.SetFloat("_Metallic", 0.0f);
|
|
|
|
|
+ frameMaterial.SetFloat("_Smoothness", 0.4f);
|
|
|
|
|
+ renderer.material = frameMaterial;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void CreateEntranceBeam(GameObject parent, string name, Vector3 position, float width)
|
|
|
|
|
+ {
|
|
|
|
|
+ GameObject beam = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
|
|
|
+ beam.name = name;
|
|
|
|
|
+ beam.transform.SetParent(parent.transform);
|
|
|
|
|
+ beam.transform.localPosition = position;
|
|
|
|
|
+ beam.transform.localScale = new Vector3(width + 0.3f, 0.3f, 0.3f); // Wider and thicker beam
|
|
|
|
|
+
|
|
|
|
|
+ Renderer renderer = beam.GetComponent<Renderer>();
|
|
|
|
|
+ Material frameMaterial = new Material(Shader.Find("Universal Render Pipeline/Lit"));
|
|
|
|
|
+ frameMaterial.color = new Color(0.3f, 0.15f, 0.05f); // Darker brown for entrance
|
|
|
|
|
+ frameMaterial.SetFloat("_Metallic", 0.0f);
|
|
|
|
|
+ frameMaterial.SetFloat("_Smoothness", 0.4f);
|
|
|
|
|
+ renderer.material = frameMaterial;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void CreateEntranceMat(GameObject parent, string name, Vector3 position, float width)
|
|
|
|
|
+ {
|
|
|
|
|
+ GameObject mat = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
|
|
|
+ mat.name = name;
|
|
|
|
|
+ mat.transform.SetParent(parent.transform);
|
|
|
|
|
+ mat.transform.localPosition = position;
|
|
|
|
|
+ mat.transform.localScale = new Vector3(width, 0.1f, 1.5f); // Welcome mat dimensions
|
|
|
|
|
+
|
|
|
|
|
+ Renderer renderer = mat.GetComponent<Renderer>();
|
|
|
|
|
+ Material matMaterial = new Material(Shader.Find("Universal Render Pipeline/Lit"));
|
|
|
|
|
+ matMaterial.color = new Color(0.8f, 0.2f, 0.2f); // Red welcome mat
|
|
|
|
|
+ matMaterial.SetFloat("_Metallic", 0.0f);
|
|
|
|
|
+ matMaterial.SetFloat("_Smoothness", 0.1f); // Rough mat texture
|
|
|
|
|
+ renderer.material = matMaterial;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
|
|
+ #region Helper Methods
|
|
|
|
|
+
|
|
|
|
|
+ private void CreatePreviewLine()
|
|
|
|
|
+ {
|
|
|
|
|
+ GameObject previewObj = new GameObject("WallPreview");
|
|
|
|
|
+ previewLine = previewObj.AddComponent<LineRenderer>();
|
|
|
|
|
+
|
|
|
|
|
+ // Use URP Unlit shader for line renderer (better for simple colored lines)
|
|
|
|
|
+ previewLine.material = new Material(Shader.Find("Universal Render Pipeline/Unlit"));
|
|
|
|
|
+ previewLine.material.color = Color.yellow;
|
|
|
|
|
+ previewLine.startColor = Color.yellow;
|
|
|
|
|
+ previewLine.endColor = Color.yellow;
|
|
|
|
|
+ previewLine.startWidth = 0.1f;
|
|
|
|
|
+ previewLine.endWidth = 0.1f;
|
|
|
|
|
+ previewLine.positionCount = 2;
|
|
|
|
|
+ previewLine.enabled = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void CreateDoorPreview()
|
|
|
|
|
+ {
|
|
|
|
|
+ // Create a simple preview object
|
|
|
|
|
+ doorPreview = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
|
|
|
+ doorPreview.name = "DoorPreview";
|
|
|
|
|
+
|
|
|
|
|
+ // Make it transparent green
|
|
|
|
|
+ Renderer renderer = doorPreview.GetComponent<Renderer>();
|
|
|
|
|
+ Material previewMaterial = new Material(Shader.Find("Universal Render Pipeline/Lit"));
|
|
|
|
|
+
|
|
|
|
|
+ // Set up bright green transparent color
|
|
|
|
|
+ previewMaterial.color = new Color(0f, 1f, 0f, 0.6f); // Bright transparent green
|
|
|
|
|
+
|
|
|
|
|
+ // Set up transparency properly for URP
|
|
|
|
|
+ previewMaterial.SetFloat("_Surface", 1); // Set to Transparent
|
|
|
|
|
+ previewMaterial.SetFloat("_Blend", 0); // Alpha blend
|
|
|
|
|
+ previewMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
|
|
|
|
|
+ previewMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
|
|
|
|
+ previewMaterial.SetInt("_ZWrite", 0);
|
|
|
|
|
+ previewMaterial.renderQueue = 3000;
|
|
|
|
|
+
|
|
|
|
|
+ // Make it non-metallic and smooth for better visibility
|
|
|
|
|
+ previewMaterial.SetFloat("_Metallic", 0.0f);
|
|
|
|
|
+ previewMaterial.SetFloat("_Smoothness", 0.9f);
|
|
|
|
|
+
|
|
|
|
|
+ renderer.material = previewMaterial;
|
|
|
|
|
+
|
|
|
|
|
+ // Scale to door size - match the actual door dimensions
|
|
|
|
|
+ doorPreview.transform.localScale = new Vector3(0.2f, doorHeight, doorWidth);
|
|
|
|
|
+ doorPreview.SetActive(false);
|
|
|
|
|
+
|
|
|
|
|
+ // Remove collider to prevent interference
|
|
|
|
|
+ Collider collider = doorPreview.GetComponent<Collider>();
|
|
|
|
|
+ if (collider != null) Destroy(collider);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void CreateSnapIndicator()
|
|
|
|
|
+ {
|
|
|
|
|
+ snapIndicator = GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
|
|
|
|
+ snapIndicator.name = "SnapIndicator";
|
|
|
|
|
+
|
|
|
|
|
+ // Make it a bright, pulsing indicator
|
|
|
|
|
+ Renderer renderer = snapIndicator.GetComponent<Renderer>();
|
|
|
|
|
+ Material indicatorMaterial = new Material(Shader.Find("Universal Render Pipeline/Lit"));
|
|
|
|
|
+ indicatorMaterial.color = Color.cyan;
|
|
|
|
|
+ indicatorMaterial.SetFloat("_Metallic", 0.0f);
|
|
|
|
|
+ indicatorMaterial.SetFloat("_Smoothness", 0.9f);
|
|
|
|
|
+
|
|
|
|
|
+ // Make it emissive so it glows
|
|
|
|
|
+ indicatorMaterial.EnableKeyword("_EMISSION");
|
|
|
|
|
+ indicatorMaterial.SetColor("_EmissionColor", Color.cyan * 2f);
|
|
|
|
|
+
|
|
|
|
|
+ renderer.material = indicatorMaterial;
|
|
|
|
|
+
|
|
|
|
|
+ // Scale it to be visible but not too large
|
|
|
|
|
+ snapIndicator.transform.localScale = Vector3.one * 0.3f;
|
|
|
|
|
+ snapIndicator.SetActive(false);
|
|
|
|
|
+
|
|
|
|
|
+ // Remove collider to prevent interference
|
|
|
|
|
+ Collider collider = snapIndicator.GetComponent<Collider>();
|
|
|
|
|
+ if (collider != null) Destroy(collider);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void HideAllPreviews()
|
|
|
|
|
+ {
|
|
|
|
|
+ if (previewLine != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ previewLine.enabled = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ HideDoorPreview();
|
|
|
|
|
+ HideSnapIndicator();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Vector3 GetMouseWorldPosition()
|
|
|
|
|
+ {
|
|
|
|
|
+ Ray ray = playerCamera.ScreenPointToRay(Input.mousePosition);
|
|
|
|
|
+
|
|
|
|
|
+ // Cast ray onto ground plane (Y = 0)
|
|
|
|
|
+ if (Physics.Raycast(ray, out RaycastHit hit))
|
|
|
|
|
+ {
|
|
|
|
|
+ return hit.point;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Fallback: project onto Y = 0 plane
|
|
|
|
|
+ float distance = -ray.origin.y / ray.direction.y;
|
|
|
|
|
+ return ray.origin + ray.direction * distance;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private GameObject FindWallUnderMouse(Vector3 mousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ Ray ray = playerCamera.ScreenPointToRay(Input.mousePosition);
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Raycasting for wall detection at mouse position: {Input.mousePosition}");
|
|
|
|
|
+ Debug.Log($"Ray origin: {ray.origin}, Ray direction: {ray.direction}");
|
|
|
|
|
+ Debug.Log($"Camera: {playerCamera?.name ?? "NULL"}, Camera position: {playerCamera?.transform.position ?? Vector3.zero}");
|
|
|
|
|
+ Debug.Log($"Total walls in list: {walls.Count}");
|
|
|
|
|
+
|
|
|
|
|
+ // Check if we have any walls with colliders
|
|
|
|
|
+ int wallsWithColliders = 0;
|
|
|
|
|
+ foreach (GameObject wall in walls)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (wall != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Collider[] colliders = wall.GetComponentsInChildren<Collider>();
|
|
|
|
|
+ if (colliders.Length > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ wallsWithColliders++;
|
|
|
|
|
+ Debug.Log($"Wall {wall.name} has {colliders.Length} colliders");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ Debug.Log($"Walls with colliders: {wallsWithColliders}");
|
|
|
|
|
+
|
|
|
|
|
+ // Try raycasting with all layers first
|
|
|
|
|
+ if (Physics.Raycast(ray, out RaycastHit hit, 1000f))
|
|
|
|
|
+ {
|
|
|
|
|
+ GameObject hitObj = hit.collider.gameObject;
|
|
|
|
|
+ Debug.Log($"Raycast hit object: {hitObj.name} on layer {hitObj.layer}");
|
|
|
|
|
+ Debug.Log($"Hit point: {hit.point}, Hit distance: {hit.distance}");
|
|
|
|
|
+
|
|
|
|
|
+ // Check if it's one of our walls (could be parent or child)
|
|
|
|
|
+ GameObject wallToCheck = hitObj;
|
|
|
|
|
+
|
|
|
|
|
+ // If we hit a child mesh, get the parent
|
|
|
|
|
+ if (hitObj.name == "WallMesh" && hitObj.transform.parent != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ wallToCheck = hitObj.transform.parent.gameObject;
|
|
|
|
|
+ Debug.Log($"Hit child mesh, checking parent: {wallToCheck.name}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (walls.Contains(wallToCheck))
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Hit object is a valid wall: {wallToCheck.name}");
|
|
|
|
|
+ return wallToCheck;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Hit object is not a wall we created: {wallToCheck.name}");
|
|
|
|
|
+ // Also check if the hit object has a Wall tag as fallback
|
|
|
|
|
+ if (hitObj.CompareTag("Wall") || (hitObj.transform.parent != null && hitObj.transform.parent.CompareTag("Wall")))
|
|
|
|
|
+ {
|
|
|
|
|
+ GameObject taggedWall = hitObj.CompareTag("Wall") ? hitObj : hitObj.transform.parent.gameObject;
|
|
|
|
|
+ Debug.Log($"Found wall by tag: {taggedWall.name}");
|
|
|
|
|
+ return taggedWall;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log("Raycast didn't hit anything - checking for potential issues:");
|
|
|
|
|
+ Debug.Log($"PlayerCamera null? {playerCamera == null}");
|
|
|
|
|
+ Debug.Log($"Physics.DefaultRaycastLayers: {Physics.DefaultRaycastLayers}");
|
|
|
|
|
+
|
|
|
|
|
+ // Try a wider raycast with all layers
|
|
|
|
|
+ RaycastHit[] hits = Physics.RaycastAll(ray, 1000f);
|
|
|
|
|
+ Debug.Log($"RaycastAll found {hits.Length} hits");
|
|
|
|
|
+ for (int i = 0; i < hits.Length; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Hit {i}: {hits[i].collider.gameObject.name} on layer {hits[i].collider.gameObject.layer}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private GameObject FindWallUnderMouseAlternative(Vector3 worldMousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Alternative approach: find the closest wall to the mouse world position
|
|
|
|
|
+ GameObject closestWall = null;
|
|
|
|
|
+ float closestDistance = float.MaxValue;
|
|
|
|
|
+ float maxDistance = 2f; // Maximum distance to consider a wall "under" the mouse
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Alternative wall detection at world pos: {worldMousePos}");
|
|
|
|
|
+
|
|
|
|
|
+ foreach (GameObject wall in walls)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (wall == null) continue;
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate distance from mouse world position to wall center
|
|
|
|
|
+ float distance = Vector3.Distance(worldMousePos, wall.transform.position);
|
|
|
|
|
+
|
|
|
|
|
+ // Also check distance to wall bounds
|
|
|
|
|
+ Bounds wallBounds = GetWallBounds(wall);
|
|
|
|
|
+ float boundDistance = wallBounds.SqrDistance(worldMousePos);
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Wall {wall.name}: center distance = {distance}, bound distance = {Mathf.Sqrt(boundDistance)}");
|
|
|
|
|
+
|
|
|
|
|
+ if (boundDistance < maxDistance * maxDistance && distance < closestDistance)
|
|
|
|
|
+ {
|
|
|
|
|
+ closestDistance = distance;
|
|
|
|
|
+ closestWall = wall;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (closestWall != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Alternative method found wall: {closestWall.name} at distance {closestDistance}");
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log("Alternative method found no walls nearby");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return closestWall;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Bounds GetWallBounds(GameObject wall)
|
|
|
|
|
+ {
|
|
|
|
|
+ Renderer renderer = wall.GetComponentInChildren<Renderer>();
|
|
|
|
|
+ if (renderer != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ return renderer.bounds;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Fallback: calculate bounds from transform
|
|
|
|
|
+ Vector3 scale = wall.transform.localScale;
|
|
|
|
|
+ return new Bounds(wall.transform.position, scale);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private GameObject FindNearestWall(Vector3 mousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ GameObject nearestWall = null;
|
|
|
|
|
+ float nearestDistance = float.MaxValue;
|
|
|
|
|
+
|
|
|
|
|
+ foreach (GameObject wall in walls)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (wall == null) continue;
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate distance from mouse position to wall
|
|
|
|
|
+ float distance = Vector3.Distance(mousePos, wall.transform.position);
|
|
|
|
|
+ if (distance < nearestDistance && distance < 5f) // Within 5 units
|
|
|
|
|
+ {
|
|
|
|
|
+ nearestDistance = distance;
|
|
|
|
|
+ nearestWall = wall;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (nearestWall != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"Found nearest wall: {nearestWall.name} at distance {nearestDistance}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nearestWall;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Vector3[] GetWallEndpoints(GameObject wall)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Calculate endpoints from wall transform
|
|
|
|
|
+ Vector3 center = wall.transform.position;
|
|
|
|
|
+ // With our new rotation, the wall extends along the forward (Z) axis
|
|
|
|
|
+ Vector3 wallDirection = wall.transform.forward;
|
|
|
|
|
+ float length = wall.transform.localScale.z; // Z is now the length
|
|
|
|
|
+
|
|
|
|
|
+ Vector3 start = center - wallDirection * (length / 2f);
|
|
|
|
|
+ Vector3 end = center + wallDirection * (length / 2f);
|
|
|
|
|
+
|
|
|
|
|
+ // Ensure Y = 0 for ground-level snapping
|
|
|
|
|
+ start.y = 0f;
|
|
|
|
|
+ end.y = 0f;
|
|
|
|
|
+
|
|
|
|
|
+ return new Vector3[] { start, end };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Vector3 CalculateDoorPositionOnWall(GameObject wall, Vector3 mousePos)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Project mouse position onto the wall
|
|
|
|
|
+ Vector3 wallCenter = wall.transform.position;
|
|
|
|
|
+ Vector3 wallScale = wall.transform.localScale;
|
|
|
|
|
+
|
|
|
|
|
+ // Determine wall orientation based on scale (not rotation)
|
|
|
|
|
+ bool isNorthSouthWall = wallScale.x > wallScale.z;
|
|
|
|
|
+
|
|
|
|
|
+ Vector3 wallDirection;
|
|
|
|
|
+ float wallLength;
|
|
|
|
|
+
|
|
|
|
|
+ if (isNorthSouthWall)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Wall extends in X direction (North/South wall)
|
|
|
|
|
+ wallDirection = Vector3.right;
|
|
|
|
|
+ wallLength = wallScale.x;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Wall extends in Z direction (East/West wall)
|
|
|
|
|
+ wallDirection = Vector3.forward;
|
|
|
|
|
+ wallLength = wallScale.z;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Project mouse onto wall line
|
|
|
|
|
+ Vector3 toMouse = mousePos - wallCenter;
|
|
|
|
|
+ float projection = Vector3.Dot(toMouse, wallDirection);
|
|
|
|
|
+
|
|
|
|
|
+ // Clamp to wall bounds
|
|
|
|
|
+ projection = Mathf.Clamp(projection, -wallLength / 2f + doorWidth / 2f, wallLength / 2f - doorWidth / 2f);
|
|
|
|
|
+
|
|
|
|
|
+ Vector3 doorPos = wallCenter + wallDirection * projection;
|
|
|
|
|
+ doorPos.y = 0f; // Set door at ground level
|
|
|
|
|
+
|
|
|
|
|
+ Debug.Log($"Door position calculation: wallCenter={wallCenter}, wallDirection={wallDirection}, projection={projection}, doorPos={doorPos}");
|
|
|
|
|
+
|
|
|
|
|
+ return doorPos;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #endregion
|
|
|
|
|
+}
|