| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622 |
- 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;
- if (wallPrefab == null)
- {
- Debug.LogError("WallPrefab is null! Cannot create wall segments. Aborting split operation.");
- return;
- }
- 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}");
- float leftSegmentLength = entranceLeft - wallLeft;
- float rightSegmentLength = wallRight - entranceRight;
- Debug.Log($"Segment lengths: left={leftSegmentLength}, right={rightSegmentLength}"); // Create left segment if there's enough space
- if (leftSegmentLength > 0.5f)
- {
- Vector3 leftCenter = new Vector3(wallLeft + leftSegmentLength / 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(leftSegmentLength, wallScale.y, wallScale.z);
- leftWall.tag = "Wall";
- // Apply original material if available, with error checking
- if (originalMaterial != null)
- {
- Renderer leftRenderer = leftWall.GetComponent<Renderer>();
- if (leftRenderer != null)
- {
- leftRenderer.material = originalMaterial;
- Debug.Log($"Applied original material to left wall segment");
- }
- else
- {
- Debug.LogWarning($"Left wall segment {leftWall.name} has no Renderer component - cannot apply material");
- }
- }
- walls.Add(leftWall);
- Debug.Log($"SUCCESS: Created left wall segment: {leftWall.name}");
- }
- else
- {
- Debug.Log($"LEFT SEGMENT TOO SMALL: {leftSegmentLength} <= 0.5f, not creating");
- }
- // Create right segment if there's enough space
- if (rightSegmentLength > 0.5f)
- {
- Vector3 rightCenter = new Vector3(entranceRight + rightSegmentLength / 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(rightSegmentLength, wallScale.y, wallScale.z);
- rightWall.tag = "Wall";
- // Apply original material if available, with error checking
- if (originalMaterial != null)
- {
- Renderer rightRenderer = rightWall.GetComponent<Renderer>();
- if (rightRenderer != null)
- {
- rightRenderer.material = originalMaterial;
- Debug.Log($"Applied original material to right wall segment");
- }
- else
- {
- Debug.LogWarning($"Right wall segment {rightWall.name} has no Renderer component - cannot apply material");
- }
- }
- walls.Add(rightWall);
- Debug.Log($"SUCCESS: Created right wall segment: {rightWall.name}");
- }
- else
- {
- Debug.Log($"RIGHT SEGMENT TOO SMALL: {rightSegmentLength} <= 0.5f, not creating");
- }
- }
- 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}");
- float frontSegmentLength = entranceFront - wallFront;
- float backSegmentLength = wallBack - entranceBack;
- Debug.Log($"Segment lengths: front={frontSegmentLength}, back={backSegmentLength}"); // Create front segment if there's enough space
- if (frontSegmentLength > 0.5f)
- {
- Vector3 frontCenter = new Vector3(wallPos.x, wallPos.y, wallFront + frontSegmentLength / 2f);
- Debug.Log($"Creating front segment at {frontCenter} with scale ({wallScale.x}, {wallScale.y}, {frontSegmentLength})");
- GameObject frontWall = Instantiate(wallPrefab, frontCenter, wallRotation);
- frontWall.SetActive(true);
- frontWall.name = $"{originalWall.name}_Front_Entrance";
- frontWall.transform.localScale = new Vector3(wallScale.x, wallScale.y, frontSegmentLength);
- frontWall.tag = "Wall";
- // Apply original material if available, with error checking
- if (originalMaterial != null)
- {
- Renderer frontRenderer = frontWall.GetComponent<Renderer>();
- if (frontRenderer != null)
- {
- frontRenderer.material = originalMaterial;
- Debug.Log($"Applied original material to front wall segment");
- }
- else
- {
- Debug.LogWarning($"Front wall segment {frontWall.name} has no Renderer component - cannot apply material");
- }
- }
- walls.Add(frontWall);
- Debug.Log($"SUCCESS: Created front wall segment: {frontWall.name}");
- }
- else
- {
- Debug.Log($"FRONT SEGMENT TOO SMALL: {frontSegmentLength} <= 0.5f, not creating");
- }
- // Create back segment if there's enough space
- if (backSegmentLength > 0.5f)
- {
- Vector3 backCenter = new Vector3(wallPos.x, wallPos.y, entranceBack + backSegmentLength / 2f);
- Debug.Log($"Creating back segment at {backCenter} with scale ({wallScale.x}, {wallScale.y}, {backSegmentLength})");
- GameObject backWall = Instantiate(wallPrefab, backCenter, wallRotation);
- backWall.SetActive(true);
- backWall.name = $"{originalWall.name}_Back_Entrance";
- backWall.transform.localScale = new Vector3(wallScale.x, wallScale.y, backSegmentLength);
- backWall.tag = "Wall";
- // Apply original material if available, with error checking
- if (originalMaterial != null)
- {
- Renderer backRenderer = backWall.GetComponent<Renderer>();
- if (backRenderer != null)
- {
- backRenderer.material = originalMaterial;
- Debug.Log($"Applied original material to back wall segment");
- }
- else
- {
- Debug.LogWarning($"Back wall segment {backWall.name} has no Renderer component - cannot apply material");
- }
- }
- walls.Add(backWall);
- Debug.Log($"SUCCESS: Created back wall segment: {backWall.name}");
- }
- else
- {
- Debug.Log($"BACK SEGMENT TOO SMALL: {backSegmentLength} <= 0.5f, not creating");
- }
- }
- // Remove original wall
- Debug.Log($"REMOVING ORIGINAL WALL: {originalWall.name} (active: {originalWall.activeInHierarchy})");
- walls.Remove(originalWall);
- // Try multiple removal methods to ensure it's gone
- originalWall.SetActive(false);
- DestroyImmediate(originalWall);
- Debug.Log("Original wall removal completed");
- }
- 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;
- // Use the wall's actual transform directions instead of world axes
- Vector3 wallDirection;
- float wallLength;
- // Determine wall orientation based on scale
- bool isNorthSouthWall = wallScale.x > wallScale.z;
- if (isNorthSouthWall)
- {
- // Wall extends in X direction - use the wall's right vector (local X axis)
- wallDirection = wall.transform.right;
- wallLength = wallScale.x;
- }
- else
- {
- // Wall extends in Z direction - use the wall's forward vector (local Z axis)
- wallDirection = wall.transform.forward;
- wallLength = wallScale.z;
- }
- // Project mouse position onto the wall's direction vector
- Vector3 toMouse = mousePos - wallCenter;
- float projection = Vector3.Dot(toMouse, wallDirection);
- // Clamp to wall bounds
- float clampedProjection = Mathf.Clamp(projection, -wallLength / 2f + doorWidth / 2f, wallLength / 2f - doorWidth / 2f);
- Vector3 doorPos = wallCenter + wallDirection * clampedProjection;
- doorPos.y = 0f; // Set door at ground level
- return doorPos;
- }
- #endregion
- }
|