| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480 |
- using UnityEngine;
- using System.Collections.Generic;
- using System.Linq;
- public enum BuildingMode
- {
- PlacingWalls,
- PlacingDoor,
- AddingDoorToExistingWall
- }
- public class RoomBuilder : MonoBehaviour
- {
- [Header("Building Settings")]
- [SerializeField] private float snapTolerance = 1f;
- [SerializeField] private Material wallMaterial;
- [SerializeField] private Material previewMaterial;
- [SerializeField] private float wallHeight = 3f;
- [SerializeField] private float wallThickness = 0.2f;
- [Header("Door Settings")]
- [SerializeField] private float doorWidth = 1.5f;
- [SerializeField] private Material doorFrameMaterial;
- [Header("Visual Feedback")]
- [SerializeField] private GameObject wallPointPrefab;
- [SerializeField] private LineRenderer previewLine;
- private List<Vector3> currentRoomPoints = new List<Vector3>();
- private List<GameObject> wallSegments = new List<GameObject>();
- private List<GameObject> wallPointMarkers = new List<GameObject>();
- private bool isBuildingRoom = false;
- private bool isPlacingDoor = false;
- private BuildingMode currentBuildingMode = BuildingMode.PlacingWalls;
- private Camera playerCamera;
- private float lastRoomCompletionTime = 0f;
- private const float ROOM_DETECTION_COOLDOWN = 1.0f; // 1 second cooldown
- private GameObject previewWall;
- private Room currentRoom;
- // Events
- public System.Action<Room> OnRoomCompleted;
- public System.Action<string> OnBuildingError;
- private void Start()
- {
- playerCamera = Camera.main;
- if (previewLine == null)
- {
- CreatePreviewLine();
- }
- }
- private void Update()
- {
- if (GameManager.Instance != null && !GameManager.Instance.IsBuilding())
- return;
- HandleInput();
- UpdatePreview();
- }
- private void OnGUI()
- {
- // Show building mode information
- if (GameManager.Instance != null && GameManager.Instance.IsBuilding())
- {
- GUIStyle style = new GUIStyle();
- style.fontSize = 16;
- style.normal.textColor = Color.white;
- string modeText = "";
- string instructionText = "";
- if (isBuildingRoom)
- {
- modeText = "Building Room";
- instructionText = "Left-click to place wall points | Right-click to complete room";
- }
- else if (isPlacingDoor)
- {
- modeText = "Placing Door";
- instructionText = "Click on a wall to place door";
- }
- else if (currentBuildingMode == BuildingMode.AddingDoorToExistingWall)
- {
- modeText = "Adding Door to Wall";
- instructionText = "Click on existing wall to add door | ESC to cancel | Tab to toggle modes";
- }
- else
- {
- modeText = "Ready to Build";
- instructionText = "Left-click to start room | Tab to add door to existing wall | Auto-detects enclosed rooms";
- }
- GUI.Label(new Rect(10, 10, 400, 30), $"Mode: {modeText}", style);
- GUI.Label(new Rect(10, 35, 400, 30), instructionText, style);
- }
- }
- #region Input Handling
- private void HandleInput()
- {
- // Only handle building inputs when we're supposed to be building
- if (GameManager.Instance == null || !GameManager.Instance.IsBuilding())
- return;
- // Building mode switching - use Tab instead of D to avoid camera conflict
- if (Input.GetKeyDown(KeyCode.Tab) && !isBuildingRoom && !isPlacingDoor)
- {
- currentBuildingMode = BuildingMode.AddingDoorToExistingWall;
- Debug.Log("Switched to door placement mode - Click on existing walls to add doors");
- }
- else if (Input.GetKeyDown(KeyCode.Tab) && currentBuildingMode == BuildingMode.AddingDoorToExistingWall)
- {
- currentBuildingMode = BuildingMode.PlacingWalls;
- Debug.Log("Switched to wall building mode");
- }
- if (Input.GetMouseButtonDown(0)) // Left click
- {
- Debug.Log($"Mouse click detected - isPlacingDoor={isPlacingDoor}, currentBuildingMode={currentBuildingMode}");
- if (currentBuildingMode == BuildingMode.AddingDoorToExistingWall)
- {
- TryAddDoorToExistingWall();
- }
- else if (isPlacingDoor)
- {
- TryPlaceDoor();
- }
- else
- {
- TryPlaceWallPoint();
- }
- }
- else if (Input.GetMouseButtonDown(1)) // Right click
- {
- if (isBuildingRoom)
- {
- // Instead of forcing completion, try to auto-complete smartly
- // Only allow manual completion if we have a valid room shape
- if (currentRoomPoints.Count >= 3)
- {
- TryCompleteRoom();
- }
- else
- {
- OnBuildingError?.Invoke("Need at least 3 points to complete room manually");
- }
- }
- }
- else if (Input.GetKeyDown(KeyCode.Escape))
- {
- if (currentBuildingMode == BuildingMode.AddingDoorToExistingWall)
- {
- currentBuildingMode = BuildingMode.PlacingWalls;
- Debug.Log("Cancelled door placement mode");
- }
- else
- {
- CancelBuilding();
- }
- }
- }
- private Vector3 GetMouseWorldPosition()
- {
- Ray ray = playerCamera.ScreenPointToRay(Input.mousePosition);
- if (Physics.Raycast(ray, out RaycastHit hit))
- {
- return hit.point;
- }
- else
- {
- // Fallback: project to ground plane (y = 0)
- Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
- if (groundPlane.Raycast(ray, out float distance))
- {
- return ray.GetPoint(distance);
- }
- }
- return Vector3.zero;
- }
- #endregion
- #region Wall Building
- private void TryPlaceWallPoint()
- {
- Vector3 mousePos = GetMouseWorldPosition();
- if (!isBuildingRoom)
- {
- // Check if we're starting near an existing wall
- Vector3 snapPoint = FindWallSnapPoint(mousePos);
- if (snapPoint != Vector3.zero)
- {
- Debug.Log($"Starting room from existing wall at: {snapPoint}");
- StartRoom(snapPoint);
- }
- else
- {
- StartRoom(mousePos);
- }
- }
- else
- {
- // Check if we're close to the first point (completing the room)
- if (Vector3.Distance(mousePos, currentRoomPoints[0]) < snapTolerance)
- {
- AutoCompleteRoom();
- return;
- }
- // Check if we're clicking on an existing wall to complete the room
- Vector3 wallSnapPoint = FindWallSnapPoint(mousePos);
- if (wallSnapPoint != Vector3.zero)
- {
- Debug.Log($"Completing room by connecting to existing wall at: {wallSnapPoint}");
- AddWallPoint(wallSnapPoint);
- // If we started from an existing wall and now connect to another existing wall,
- // we can complete the room with just 2 points (wall-to-wall connection)
- if (currentRoomPoints.Count >= 2)
- {
- Debug.Log("Wall-to-wall connection detected, triggering comprehensive room detection");
- // Instead of AutoCompleteRoom, use the comprehensive room detection
- CheckForNewEnclosedRoomsGlobal();
- return;
- }
- }
- AddWallPoint(mousePos);
- // Auto-check if room is now enclosed (only for non-wall-snap cases)
- if (IsRoomEnclosed(currentRoomPoints))
- {
- AutoCompleteRoom();
- }
- // ADDITIONAL: Force completion check if we have enough points and walls
- if (currentRoomPoints.Count >= 3)
- {
- Debug.Log("Checking for forced room completion with sufficient points");
- // Get all walls and see if we have enough to complete a room
- List<GameObject> allWalls = new List<GameObject>();
- GameObject[] allGameObjects = FindObjectsByType<GameObject>(FindObjectsSortMode.None);
- foreach (GameObject obj in allGameObjects)
- {
- if (obj != null && obj.GetComponent<Renderer>() != null &&
- (obj.name.Contains("Wall") || obj.name.Contains("wall")))
- {
- allWalls.Add(obj);
- }
- }
- if (allWalls.Count >= 4) // Enough walls for a room
- {
- Debug.Log("Sufficient walls detected, forcing room completion");
- CheckForNewEnclosedRoomsGlobal();
- }
- }
- }
- }
- private void AutoCompleteRoom()
- {
- // Check if room already has a door
- if (DoesRoomHaveDoor())
- {
- Debug.Log("Room already has a door, completing without door placement.");
- CompleteRoomWithoutDoor();
- }
- else
- {
- Debug.Log("Room completed, needs door placement.");
- CompleteRoom();
- }
- }
- private Vector3 FindWallSnapPoint(Vector3 clickPosition)
- {
- float snapDistance = 2.0f; // Distance to snap to existing walls
- GameObject closestWall = null;
- float closestDistance = float.MaxValue;
- // Check all existing wall segments
- foreach (GameObject wall in wallSegments)
- {
- if (wall == null || wall.name == "Door Opening" || wall.name == "Door Frame Post") continue;
- Renderer wallRenderer = wall.GetComponent<Renderer>();
- if (wallRenderer == null) continue;
- // Check distance to wall bounds
- Bounds bounds = wallRenderer.bounds;
- float distance = bounds.SqrDistance(clickPosition);
- if (distance < closestDistance && distance < snapDistance * snapDistance)
- {
- closestWall = wall;
- closestDistance = distance;
- }
- }
- if (closestWall != null)
- {
- // Find the closest point on the wall surface to snap to
- Transform wallTransform = closestWall.transform;
- Vector3 wallScale = wallTransform.localScale;
- Vector3 wallCenter = wallTransform.position;
- // Calculate wall endpoints based on wall's forward direction (length direction)
- Vector3 wallDirection = wallTransform.forward;
- float wallLength = wallScale.z; // Length is in Z direction after LookRotation
- Vector3 wallStart = wallCenter - wallDirection * wallLength / 2f;
- Vector3 wallEnd = wallCenter + wallDirection * wallLength / 2f;
- // Project click position onto the wall line to find closest point
- Vector3 wallVector = wallEnd - wallStart;
- Vector3 clickVector = clickPosition - wallStart;
- float t = Mathf.Clamp01(Vector3.Dot(clickVector, wallVector) / wallVector.sqrMagnitude);
- Vector3 snapPoint = wallStart + t * wallVector;
- // Ensure snap point is at ground level
- snapPoint.y = 0f;
- Debug.Log($"Found wall snap point: {snapPoint} on wall from {wallStart} to {wallEnd}");
- return snapPoint;
- }
- return Vector3.zero; // No wall found to snap to
- }
- private bool DoesRoomHaveDoor()
- {
- // Check if any wall segments in current room area have door openings or door frames
- foreach (GameObject segment in wallSegments)
- {
- if (segment != null && (segment.name == "Door Opening" || segment.name == "Door Frame Post"))
- {
- return true;
- }
- }
- return false;
- }
- private bool IsRoomEnclosed(List<Vector3> points)
- {
- // Check if the current points form a closed shape
- if (points.Count < 3) return false;
- // Check if we're close to starting point or clicked on existing wall
- Vector3 lastPoint = points[points.Count - 1];
- Vector3 firstPoint = points[0];
- return Vector3.Distance(lastPoint, firstPoint) < snapTolerance * 2f;
- }
- private void CompleteRoomWithoutDoor()
- {
- // Complete the room without entering door placement mode
- if (currentRoomPoints.Count > 2)
- {
- Vector3 lastPoint = currentRoomPoints[currentRoomPoints.Count - 1];
- Vector3 firstPoint = currentRoomPoints[0];
- if (Vector3.Distance(lastPoint, firstPoint) > 0.1f)
- {
- CreateWallSegment(lastPoint, firstPoint);
- }
- }
- Debug.Log("Room completed without additional door (existing door found).");
- // Clean up any very short or overlapping wall segments
- CleanupWallSegments();
- // Finalize the room immediately
- FinishRoom();
- // Reset building state
- ResetBuildingState();
- }
- private void StartRoom(Vector3 startPoint)
- {
- Debug.Log("Starting room construction");
- isBuildingRoom = true;
- currentRoomPoints.Clear();
- currentRoomPoints.Add(startPoint);
- // Create visual marker for start point
- if (wallPointPrefab != null)
- {
- GameObject marker = Instantiate(wallPointPrefab, startPoint, Quaternion.identity);
- marker.GetComponent<Renderer>().material.color = Color.green; // Start point is green
- wallPointMarkers.Add(marker);
- }
- }
- private void AddWallPoint(Vector3 newPoint)
- {
- currentRoomPoints.Add(newPoint);
- // Create wall segment from previous point to new point
- CreateWallSegment(currentRoomPoints[currentRoomPoints.Count - 2], newPoint);
- // Create visual marker
- if (wallPointPrefab != null)
- {
- GameObject marker = Instantiate(wallPointPrefab, newPoint, Quaternion.identity);
- wallPointMarkers.Add(marker);
- }
- Debug.Log($"Added wall point {currentRoomPoints.Count}: {newPoint}");
- // Check if this wall placement has created any new enclosed rooms
- CheckForNewEnclosedRooms();
- // Additional comprehensive check if we have enough points
- if (currentRoomPoints.Count >= 3)
- {
- Debug.Log("Also triggering global room detection as backup");
- CheckForNewEnclosedRoomsGlobal();
- }
- // SIMPLE FALLBACK: If we have 3+ points and are near existing walls, try to complete
- if (currentRoomPoints.Count >= 3)
- {
- Vector3 firstPoint = currentRoomPoints[0];
- Vector3 lastPoint = currentRoomPoints[currentRoomPoints.Count - 1];
- // Simple distance check - if start and end are close to existing walls, complete the room
- if (IsNearExistingWall(firstPoint) && IsNearExistingWall(lastPoint))
- {
- Debug.Log("Simple room completion: Start and end points near existing walls");
- ForceSimpleRoomCompletion();
- }
- }
- }
- private bool IsNearExistingWall(Vector3 point)
- {
- GameObject[] allObjects = FindObjectsByType<GameObject>(FindObjectsSortMode.None);
- foreach (GameObject obj in allObjects)
- {
- if (obj != null && obj.name.Contains("Wall") && obj.GetComponent<Renderer>() != null)
- {
- if (Vector3.Distance(point, obj.transform.position) < 3.0f)
- {
- return true;
- }
- }
- }
- return false;
- }
- private void ForceSimpleRoomCompletion()
- {
- Debug.Log("Forcing simple room completion");
- // Create a simple room from current points
- if (currentRoomPoints.Count >= 3)
- {
- List<Vector3> roomArea = new List<Vector3>(currentRoomPoints);
- // Check if it has a door
- bool hasDoor = DoesAreaHaveDoor(roomArea);
- if (!hasDoor)
- {
- Debug.Log("Simple room has no door - forcing door placement");
- ForceRoomDoorPlacement(roomArea);
- }
- else
- {
- Debug.Log("Simple room has door - completing");
- CompleteDetectedRoom(roomArea);
- }
- }
- }
- private void TryCompleteRoom()
- {
- if (currentRoomPoints.Count < 3)
- {
- OnBuildingError?.Invoke("Room needs at least 3 points");
- return;
- }
- Vector3 lastPoint = currentRoomPoints[currentRoomPoints.Count - 1];
- Vector3 firstPoint = currentRoomPoints[0];
- // Check if there's a clear line to the first point
- if (IsValidClosingWall(lastPoint, firstPoint))
- {
- CompleteRoom();
- }
- else
- {
- OnBuildingError?.Invoke("Cannot complete room: No clear line to start point");
- }
- }
- private void CompleteRoom()
- {
- // Add final wall segment to close the room
- if (currentRoomPoints.Count > 2)
- {
- Vector3 lastPoint = currentRoomPoints[currentRoomPoints.Count - 1];
- Vector3 firstPoint = currentRoomPoints[0];
- if (Vector3.Distance(lastPoint, firstPoint) > 0.1f)
- {
- CreateWallSegment(lastPoint, firstPoint);
- }
- }
- Debug.Log("Room walls completed. Now place a door.");
- // Clean up any very short or overlapping wall segments
- CleanupWallSegments();
- // Start door placement phase
- isBuildingRoom = false;
- isPlacingDoor = true;
- // Change marker colors to indicate door placement phase
- foreach (var marker in wallPointMarkers)
- {
- if (marker != null)
- marker.GetComponent<Renderer>().material.color = Color.blue;
- }
- }
- private void CleanupWallSegments()
- {
- // Remove any walls that are too short or overlapping
- for (int i = wallSegments.Count - 1; i >= 0; i--)
- {
- if (wallSegments[i] == null) continue;
- Transform wallTransform = wallSegments[i].transform;
- Vector3 wallScale = wallTransform.localScale;
- // Remove walls that are too short (likely overlapping or error segments)
- if (wallScale.z < 0.2f) // Z is the length dimension
- {
- Debug.Log($"Removing short wall segment: {wallScale.z}");
- DestroyImmediate(wallSegments[i]);
- wallSegments.RemoveAt(i);
- }
- }
- }
- private bool IsValidClosingWall(Vector3 from, Vector3 to)
- {
- // For now, just check distance (can be improved with obstacle checking)
- return Vector3.Distance(from, to) < 20f; // Max wall length
- }
- private void CreateWallSegment(Vector3 from, Vector3 to)
- {
- // Ensure points are at ground level (y = 0) for consistency
- from.y = 0f;
- to.y = 0f;
- Vector3 center = (from + to) / 2f;
- Vector3 direction = to - from;
- float length = direction.magnitude;
- // Skip very short wall segments to prevent overlapping
- if (length < 0.1f)
- {
- Debug.LogWarning($"Skipping very short wall segment: {length}");
- return;
- }
- GameObject wall = GameObject.CreatePrimitive(PrimitiveType.Cube);
- wall.name = "Wall Segment";
- // Anchor wall to floor - position at ground level with wall extending upward
- wall.transform.position = new Vector3(center.x, wallHeight / 2f, center.z);
- wall.transform.rotation = Quaternion.LookRotation(direction);
- wall.transform.localScale = new Vector3(wallThickness, wallHeight, length);
- if (wallMaterial != null)
- {
- wall.GetComponent<Renderer>().material = wallMaterial;
- }
- // Add collider for pathfinding obstacles but make non-clickable
- Collider wallCollider = wall.GetComponent<Collider>();
- if (wallCollider != null)
- {
- wallCollider.isTrigger = false;
- // Walls should block navigation but not be clickable for UI
- wall.layer = LayerMask.NameToLayer("Default"); // Ensure it's on a non-UI layer
- }
- wallSegments.Add(wall);
- // After adding any wall, check if it might have completed an enclosed room
- // (but only if we're not already in a specific building mode)
- if (!isPlacingDoor && currentBuildingMode != BuildingMode.AddingDoorToExistingWall)
- {
- CheckForNewEnclosedRoomsGlobal();
- }
- }
- #endregion
- #region Door Placement
- private void TryPlaceDoor()
- {
- Vector3 mousePos = GetMouseWorldPosition();
- Debug.Log($"Trying to place door at mouse position: {mousePos}");
- // Find the closest wall segment
- GameObject closestWall = FindClosestWallSegment(mousePos);
- if (closestWall != null)
- {
- Debug.Log($"Found wall for door placement: {closestWall.name}");
- PlaceDoor(closestWall, mousePos);
- FinishRoom(); // This should reset the building state
- // Extra safety: force reset building state immediately
- Debug.Log("Building state reset.");
- return; // Exit immediately after placing door
- }
- else
- {
- Debug.LogWarning("No suitable wall found for door placement");
- OnBuildingError?.Invoke("Click closer to a wall to place the door (not too close to corners)");
- }
- }
- private void TryAddDoorToExistingWall()
- {
- Vector3 mousePos = GetMouseWorldPosition();
- Debug.Log($"Trying to add door to existing wall at: {mousePos}");
- // Find the closest existing wall segment (not door-related)
- GameObject targetWall = null;
- float closestDistance = float.MaxValue;
- foreach (GameObject wall in wallSegments)
- {
- if (wall == null || wall.name == "Door Opening" || wall.name == "Door Frame Post") continue;
- Renderer wallRenderer = wall.GetComponent<Renderer>();
- if (wallRenderer == null) continue;
- Bounds bounds = wallRenderer.bounds;
- float distance = bounds.SqrDistance(mousePos);
- if (distance < closestDistance && distance < 16f) // Max click distance squared
- {
- targetWall = wall;
- closestDistance = distance;
- }
- }
- if (targetWall != null)
- {
- Debug.Log($"Adding door to existing wall: {targetWall.name}");
- PlaceDoor(targetWall, mousePos);
- // Switch back to normal building mode
- currentBuildingMode = BuildingMode.PlacingWalls;
- Debug.Log("Door added successfully, switched back to wall building mode");
- }
- else
- {
- OnBuildingError?.Invoke("Click closer to an existing wall to add a door");
- }
- }
- private GameObject FindClosestWallSegment(Vector3 position)
- {
- GameObject closest = null;
- float closestDistance = float.MaxValue;
- foreach (GameObject wall in wallSegments)
- {
- if (wall == null) continue;
- // Get the wall bounds
- Renderer wallRenderer = wall.GetComponent<Renderer>();
- if (wallRenderer == null) continue;
- Bounds bounds = wallRenderer.bounds;
- float distance = bounds.SqrDistance(position);
- // Check if click is within reasonable distance and not too close to wall ends
- if (distance < closestDistance && distance < 16f) // Max click distance squared (4^2)
- {
- // Additional check: make sure we're not too close to wall endpoints
- Transform wallTransform = wall.transform;
- Vector3 wallDirection = wallTransform.forward;
- float wallLength = wallTransform.localScale.z;
- Vector3 wallStart = wallTransform.position - wallDirection * wallLength / 2f;
- Vector3 wallEnd = wallTransform.position + wallDirection * wallLength / 2f;
- float distToStart = Vector3.Distance(position, wallStart);
- float distToEnd = Vector3.Distance(position, wallEnd);
- // Only allow door placement if not too close to wall ends
- if (distToStart > doorWidth * 0.75f && distToEnd > doorWidth * 0.75f)
- {
- closestDistance = distance;
- closest = wall;
- }
- }
- }
- return closest;
- }
- private void PlaceDoor(GameObject wallSegment, Vector3 clickPosition)
- {
- // Create door opening by modifying the wall
- Transform wallTransform = wallSegment.transform;
- Vector3 wallScale = wallTransform.localScale;
- Vector3 wallCenter = wallTransform.position;
- // Calculate wall endpoints correctly based on wall's forward direction (length direction)
- Vector3 wallDirection = wallTransform.forward;
- float wallLength = wallScale.z; // Length is in Z direction after LookRotation
- Vector3 wallStart = wallCenter - wallDirection * wallLength / 2f;
- Vector3 wallEnd = wallCenter + wallDirection * wallLength / 2f;
- // Project click position onto the wall line to find closest point
- Vector3 wallVector = wallEnd - wallStart;
- Vector3 clickVector = clickPosition - wallStart;
- float t = Mathf.Clamp01(Vector3.Dot(clickVector, wallVector) / wallVector.sqrMagnitude);
- Vector3 doorPosition = wallStart + t * wallVector;
- // Validate door position - ensure it's not too close to wall ends
- float distFromStart = Vector3.Distance(doorPosition, wallStart);
- float distFromEnd = Vector3.Distance(doorPosition, wallEnd);
- float minDistance = doorWidth * 0.6f;
- if (distFromStart < minDistance || distFromEnd < minDistance)
- {
- // Adjust door position to be away from wall ends
- if (distFromStart < distFromEnd)
- {
- doorPosition = wallStart + wallDirection * minDistance;
- }
- else
- {
- doorPosition = wallEnd - wallDirection * minDistance;
- }
- }
- Debug.Log($"Door placed at: {doorPosition} on wall from {wallStart} to {wallEnd}");
- // Remove original wall and create two wall segments with a gap
- wallSegments.Remove(wallSegment);
- DestroyImmediate(wallSegment);
- CreateWallWithDoor(wallStart, wallEnd, doorPosition);
- }
- private void CreateWallWithDoor(Vector3 wallStart, Vector3 wallEnd, Vector3 doorPosition)
- {
- Vector3 wallDirection = (wallEnd - wallStart).normalized;
- float doorHalfWidth = doorWidth / 2f;
- Vector3 door1End = doorPosition - wallDirection * doorHalfWidth;
- Vector3 door2Start = doorPosition + wallDirection * doorHalfWidth;
- // Create wall segment before door (if long enough)
- float leftSegmentLength = Vector3.Distance(wallStart, door1End);
- if (leftSegmentLength > 0.5f)
- {
- CreateWallSegment(wallStart, door1End);
- }
- // Create wall segment after door (if long enough)
- float rightSegmentLength = Vector3.Distance(door2Start, wallEnd);
- if (rightSegmentLength > 0.5f)
- {
- CreateWallSegment(door2Start, wallEnd);
- }
- // Create door frame markers (simplified)
- CreateDoorFrame(doorPosition, wallDirection);
- }
- private void CreateDoorFrame(Vector3 position, Vector3 direction)
- {
- Debug.Log($"Creating door frame at position: {position}, direction: {direction}");
- // Create simple door frame markers - two posts on sides of the opening
- float frameHeight = wallHeight * 0.85f; // Door frame slightly lower than wall
- // Fix rotation: Use the direction itself (not perpendicular) for door post positioning
- // This positions posts along the wall direction, not perpendicular to it
- Vector3 postDirection = direction.normalized;
- // Position posts precisely at the door opening edges along the wall
- Vector3 leftPost = position - postDirection * doorWidth / 2f;
- Vector3 rightPost = position + postDirection * doorWidth / 2f;
- // Ensure door posts are exactly at ground level like walls
- leftPost.y = 0f;
- rightPost.y = 0f;
- Debug.Log($"Door posts positioned at: Left={leftPost}, Right={rightPost}, Height={frameHeight}");
- CreateDoorPost(leftPost, frameHeight);
- CreateDoorPost(rightPost, frameHeight);
- // Create a subtle ground-level door opening indicator
- GameObject doorOpening = new GameObject("Door Opening");
- doorOpening.transform.position = new Vector3(position.x, 0.01f, position.z); // Just above ground
- // Add a simple flat rectangle for the door opening - perpendicular to wall direction
- GameObject indicator = GameObject.CreatePrimitive(PrimitiveType.Cube);
- indicator.transform.SetParent(doorOpening.transform);
- indicator.transform.localPosition = Vector3.zero;
- // Rotate indicator to be perpendicular to the wall (across the door opening)
- Vector3 perpendicular = Vector3.Cross(direction, Vector3.up).normalized;
- indicator.transform.localRotation = Quaternion.LookRotation(perpendicular);
- indicator.transform.localScale = new Vector3(doorWidth, 0.02f, 0.1f); // Thin flat indicator
- Renderer indicatorRenderer = indicator.GetComponent<Renderer>();
- if (indicatorRenderer != null)
- {
- indicatorRenderer.material.color = new Color(0.2f, 0.8f, 0.2f, 0.7f); // Semi-transparent green
- }
- indicator.name = "Door Indicator";
- // Make door indicator non-clickable by removing collider
- Collider indicatorCollider = indicator.GetComponent<Collider>();
- if (indicatorCollider != null)
- {
- DestroyImmediate(indicatorCollider);
- }
- wallSegments.Add(doorOpening);
- }
- private void CreateDoorPost(Vector3 position, float height)
- {
- GameObject post = GameObject.CreatePrimitive(PrimitiveType.Cube);
- post.name = "Door Frame Post";
- // Position door posts to match wall anchoring (anchored to floor)
- // Ensure Y position matches how walls are positioned at wallHeight/2
- post.transform.position = new Vector3(position.x, height / 2f, position.z);
- post.transform.localScale = new Vector3(0.15f, height, 0.15f); // Slightly thinner posts
- if (doorFrameMaterial != null)
- {
- post.GetComponent<Renderer>().material = doorFrameMaterial;
- }
- else
- {
- post.GetComponent<Renderer>().material.color = new Color(0.4f, 0.2f, 0.05f); // Darker brown
- }
- // Make door posts non-clickable but solid
- Collider postCollider = post.GetComponent<Collider>();
- if (postCollider != null)
- {
- postCollider.isTrigger = false; // Keep solid for visual barrier
- post.layer = LayerMask.NameToLayer("Default"); // Non-clickable layer
- }
- wallSegments.Add(post);
- }
- private void FinishRoom()
- {
- // Use the stored room data if we have it (from auto-detection), otherwise create new
- if (currentRoom == null)
- {
- currentRoom = new Room
- {
- roomPoints = new List<Vector3>(currentRoomPoints),
- wallObjects = new List<GameObject>(wallSegments),
- isComplete = true,
- roomType = RoomType.Generic
- };
- }
- else
- {
- // Update the existing room with completion status
- currentRoom.isComplete = true;
- currentRoom.hasEntrance = true;
- }
- lastRoomCompletionTime = Time.time; // Set completion time for cooldown
- Debug.Log($"Room completed with door placed");
- // Clean up visual markers
- foreach (GameObject marker in wallPointMarkers)
- {
- if (marker != null)
- DestroyImmediate(marker);
- }
- // Notify completion
- OnRoomCompleted?.Invoke(currentRoom);
- // Reset building state
- ResetBuildingState();
- }
- #endregion
- #region Preview and Visual Feedback
- private void UpdatePreview()
- {
- if (!isBuildingRoom || currentRoomPoints.Count == 0)
- {
- if (previewLine != null)
- previewLine.enabled = false;
- return;
- }
- Vector3 mousePos = GetMouseWorldPosition();
- // Update preview line
- if (previewLine != null)
- {
- previewLine.enabled = true;
- previewLine.positionCount = 2;
- previewLine.SetPosition(0, currentRoomPoints[currentRoomPoints.Count - 1]);
- previewLine.SetPosition(1, mousePos);
- // Change color based on snap distance to first point
- if (currentRoomPoints.Count > 2 && Vector3.Distance(mousePos, currentRoomPoints[0]) < snapTolerance)
- {
- previewLine.material.color = Color.green; // Can close room
- }
- else
- {
- previewLine.material.color = Color.white; // Normal building
- }
- }
- }
- private void CreatePreviewLine()
- {
- GameObject previewObj = new GameObject("Preview Line");
- previewLine = previewObj.AddComponent<LineRenderer>();
- previewLine.material = new Material(Shader.Find("Sprites/Default"));
- previewLine.startColor = Color.white;
- previewLine.endColor = Color.white;
- previewLine.startWidth = 0.1f;
- previewLine.enabled = false;
- }
- #endregion
- #region Utility Methods
- private void CancelBuilding()
- {
- if (isBuildingRoom || isPlacingDoor)
- {
- Debug.Log("Cancelling room construction");
- // Clean up
- foreach (GameObject wall in wallSegments)
- {
- if (wall != null)
- DestroyImmediate(wall);
- }
- foreach (GameObject marker in wallPointMarkers)
- {
- if (marker != null)
- DestroyImmediate(marker);
- }
- // Reset state
- isBuildingRoom = false;
- isPlacingDoor = false;
- currentRoomPoints.Clear();
- wallSegments.Clear();
- wallPointMarkers.Clear();
- if (previewLine != null)
- previewLine.enabled = false;
- }
- }
- public bool IsBuilding()
- {
- return isBuildingRoom || isPlacingDoor;
- }
- private void ResetBuildingState()
- {
- Debug.Log($"ResetBuildingState() called - Before: isBuildingRoom={isBuildingRoom}, isPlacingDoor={isPlacingDoor}, currentBuildingMode={currentBuildingMode}");
- // Reset all building-related state variables
- isBuildingRoom = false;
- isPlacingDoor = false;
- currentBuildingMode = BuildingMode.PlacingWalls;
- currentRoomPoints.Clear();
- wallSegments.Clear();
- wallPointMarkers.Clear();
- if (previewLine != null)
- previewLine.enabled = false;
- Debug.Log($"ResetBuildingState() completed - After: isBuildingRoom={isBuildingRoom}, isPlacingDoor={isPlacingDoor}, currentBuildingMode={currentBuildingMode}");
- }
- private void CheckForNewEnclosedRooms()
- {
- Debug.Log("CheckForNewEnclosedRooms() called");
- // Skip room detection if we just completed a room recently (prevents immediate re-detection)
- if (Time.time - lastRoomCompletionTime < ROOM_DETECTION_COOLDOWN)
- {
- Debug.Log("Skipping room detection due to cooldown period");
- return;
- }
- // Skip if we're already placing a door
- if (isPlacingDoor)
- {
- Debug.Log("Skipping room detection - already placing door");
- return;
- }
- // Get all wall segments from multiple sources to ensure we find ALL walls
- List<GameObject> allWalls = new List<GameObject>();
- // Method 1: Include walls from our wallSegments list
- List<GameObject> roomBuilderWalls = wallSegments.Where(wall =>
- wall != null &&
- wall.name == "Wall Segment" &&
- wall.GetComponent<Renderer>() != null
- ).ToList();
- allWalls.AddRange(roomBuilderWalls);
- // Method 2: Find all GameObjects that look like walls in the scene
- GameObject[] allGameObjects = FindObjectsByType<GameObject>(FindObjectsSortMode.None);
- foreach (GameObject obj in allGameObjects)
- {
- if (obj != null && obj.GetComponent<Renderer>() != null &&
- (obj.name.Contains("Wall") || obj.name.Contains("wall")) &&
- !allWalls.Contains(obj))
- {
- allWalls.Add(obj);
- }
- }
- Debug.Log($"Found {roomBuilderWalls.Count} walls from RoomBuilder, {allWalls.Count} total walls in scene");
- // Debug: List all walls found
- foreach (var wall in allWalls)
- {
- if (wall != null)
- {
- Debug.Log($"Wall found: {wall.name} at position {wall.transform.position}");
- }
- }
- // Find enclosed areas using the wall network
- List<List<Vector3>> enclosedAreas = FindEnclosedAreas(allWalls);
- Debug.Log($"FindEnclosedAreas returned {enclosedAreas.Count} areas");
- foreach (var area in enclosedAreas)
- {
- Debug.Log($"Checking area with {area.Count} points");
- if (IsValidRoom(area))
- {
- // Check if this room has any doors
- bool hasDoor = DoesAreaHaveDoor(area);
- Debug.Log($"Valid room found with {area.Count} points. Has door: {hasDoor}");
- if (!hasDoor)
- {
- Debug.Log($"Found new enclosed room without door - forcing door placement");
- ForceRoomDoorPlacement(area);
- return; // Handle one room at a time
- }
- else
- {
- Debug.Log($"Found enclosed room with existing door - completing room");
- CompleteDetectedRoom(area);
- }
- }
- else
- {
- Debug.Log($"Area not valid as room (too small or insufficient points)");
- }
- }
- }
- private List<List<Vector3>> FindEnclosedAreas(List<GameObject> walls)
- {
- Debug.Log("FindEnclosedAreas called");
- List<List<Vector3>> enclosedAreas = new List<List<Vector3>>();
- // Instead of just checking current room points, do a comprehensive wall network analysis
- if (walls.Count >= 3) // Need at least 3 walls to form a room
- {
- Debug.Log("Attempting comprehensive wall network analysis");
- // Use the global polygon detection method
- enclosedAreas = DetectClosedPolygonsFromWalls(walls);
- }
- // Also check if current room points form a potential room (original logic)
- if (currentRoomPoints.Count >= 3)
- {
- Debug.Log("Checking current room points for completion");
- Vector3 firstPoint = currentRoomPoints[0];
- Vector3 lastPoint = currentRoomPoints[currentRoomPoints.Count - 1];
- // Check if there are existing walls that could complete the loop
- foreach (GameObject wall in walls)
- {
- if (CouldWallCompleteRoom(wall, firstPoint, lastPoint))
- {
- Debug.Log("Found wall that could complete current room");
- List<Vector3> completedRoom = new List<Vector3>(currentRoomPoints);
- enclosedAreas.Add(completedRoom);
- break;
- }
- }
- }
- Debug.Log($"FindEnclosedAreas returning {enclosedAreas.Count} areas");
- return enclosedAreas;
- }
- private bool CouldWallCompleteRoom(GameObject wall, Vector3 roomStart, Vector3 roomEnd)
- {
- if (wall == null) return false;
- // Get wall endpoints
- Transform wallTransform = wall.transform;
- Vector3 wallScale = wallTransform.localScale;
- Vector3 wallCenter = wallTransform.position;
- Vector3 wallDirection = wallTransform.forward;
- float wallLength = wallScale.z;
- Vector3 wallStart = wallCenter - wallDirection * wallLength / 2f;
- Vector3 wallEnd = wallCenter + wallDirection * wallLength / 2f;
- // Check if either end of the room is close to either end of this wall
- float tolerance = snapTolerance * 2f;
- return (Vector3.Distance(roomStart, wallStart) < tolerance ||
- Vector3.Distance(roomStart, wallEnd) < tolerance) &&
- (Vector3.Distance(roomEnd, wallStart) < tolerance ||
- Vector3.Distance(roomEnd, wallEnd) < tolerance);
- }
- private bool IsValidRoom(List<Vector3> area)
- {
- if (area.Count < 3) return false;
- // Calculate area - rooms should have minimum area
- float area2D = CalculatePolygonArea(area);
- return area2D > 4f; // Minimum room area
- }
- private float CalculatePolygonArea(List<Vector3> points)
- {
- if (points.Count < 3) return 0f;
- float area = 0f;
- for (int i = 0; i < points.Count; i++)
- {
- Vector3 current = points[i];
- Vector3 next = points[(i + 1) % points.Count];
- area += (current.x * next.z - next.x * current.z);
- }
- return Mathf.Abs(area) / 2f;
- }
- private bool DoesAreaHaveDoor(List<Vector3> area)
- {
- // Check if there are any door openings or door frame posts within the room area
- foreach (GameObject segment in wallSegments)
- {
- if (segment != null && (segment.name == "Door Opening" || segment.name == "Door Frame Post"))
- {
- Vector3 doorPos = segment.transform.position;
- if (IsPointInPolygon(doorPos, area))
- {
- return true;
- }
- }
- }
- return false;
- }
- private bool IsPointInPolygon(Vector3 point, List<Vector3> polygon)
- {
- // Simple ray casting algorithm for 2D point-in-polygon test
- bool inside = false;
- for (int i = 0, j = polygon.Count - 1; i < polygon.Count; j = i++)
- {
- Vector3 pi = polygon[i];
- Vector3 pj = polygon[j];
- if (((pi.z > point.z) != (pj.z > point.z)) &&
- (point.x < (pj.x - pi.x) * (point.z - pi.z) / (pj.z - pi.z) + pi.x))
- {
- inside = !inside;
- }
- }
- return inside;
- }
- private void ForceRoomDoorPlacement(List<Vector3> roomArea)
- {
- Debug.Log("Forcing door placement for enclosed room");
- // Switch to door placement mode
- isBuildingRoom = false;
- isPlacingDoor = true;
- currentBuildingMode = BuildingMode.PlacingDoor;
- // Store the room data
- currentRoom = new Room
- {
- roomPoints = roomArea,
- isComplete = false
- };
- // Clear current room points since we're now in door mode
- currentRoomPoints.Clear();
- OnBuildingError?.Invoke("Room detected! Click on a wall to place a door.");
- }
- private void CompleteDetectedRoom(List<Vector3> roomArea)
- {
- Debug.Log("Completing room with existing door");
- // Create and complete the room
- Room detectedRoom = new Room
- {
- roomPoints = roomArea,
- isComplete = true,
- hasEntrance = true
- };
- // Fire completion event
- OnRoomCompleted?.Invoke(detectedRoom);
- // Reset building state
- ResetBuildingState();
- }
- private void CheckForNewEnclosedRoomsGlobal()
- {
- // This is a more comprehensive room detection that works with all existing walls
- // It finds enclosed areas using all wall segments, not just current room points
- List<GameObject> actualWalls = wallSegments.Where(wall =>
- wall != null &&
- wall.name == "Wall Segment" &&
- wall.GetComponent<Renderer>() != null
- ).ToList();
- if (actualWalls.Count < 3) return; // Need at least 3 walls to form a room
- Debug.Log($"Checking for enclosed rooms with {actualWalls.Count} walls");
- // Use a more sophisticated approach to detect closed polygons
- List<List<Vector3>> detectedRooms = DetectClosedPolygonsFromWalls(actualWalls);
- Debug.Log($"Found {detectedRooms.Count} potential rooms");
- foreach (var roomArea in detectedRooms)
- {
- Debug.Log($"Checking room with {roomArea.Count} points, area: {CalculatePolygonArea(roomArea)}");
- if (IsValidRoom(roomArea))
- {
- bool hasDoor = DoesAreaHaveDoor(roomArea);
- Debug.Log($"Valid room found. Has door: {hasDoor}");
- if (!hasDoor)
- {
- Debug.Log($"Detected new enclosed room without door - forcing door placement");
- ForceRoomDoorPlacement(roomArea);
- return; // Handle one room at a time
- }
- else
- {
- Debug.Log($"Room already has door - completing");
- CompleteDetectedRoom(roomArea);
- return;
- }
- }
- }
- Debug.Log("No valid enclosed rooms detected");
- }
- private List<List<Vector3>> DetectClosedPolygonsFromWalls(List<GameObject> walls)
- {
- List<List<Vector3>> closedPolygons = new List<List<Vector3>>();
- Debug.Log($"Starting simplified room detection with {walls.Count} walls");
- // Simple approach: Look for rectangular rooms formed by connecting existing walls
- // This is more reliable than complex graph algorithms for your use case
- // Check if current room points connect existing walls to form a room
- if (currentRoomPoints.Count >= 2)
- {
- Vector3 firstPoint = currentRoomPoints[0];
- Vector3 lastPoint = currentRoomPoints[currentRoomPoints.Count - 1];
- Debug.Log($"Checking if room points form enclosed area: {currentRoomPoints.Count} points");
- Debug.Log($"First point: {firstPoint}, Last point: {lastPoint}");
- // Check if we can find existing walls that connect our start and end points
- bool startsOnWall = IsPointOnAnyWall(firstPoint, walls);
- bool endsOnWall = IsPointOnAnyWall(lastPoint, walls);
- Debug.Log($"First point on wall: {startsOnWall}, Last point on wall: {endsOnWall}");
- if (startsOnWall && endsOnWall && currentRoomPoints.Count >= 3)
- {
- // Check if there's a path of existing walls that could complete the room
- if (CanWallsCompleteRoom(firstPoint, lastPoint, walls))
- {
- Debug.Log("Found completed room using wall connections!");
- List<Vector3> completedRoom = new List<Vector3>(currentRoomPoints);
- closedPolygons.Add(completedRoom);
- }
- }
- }
- Debug.Log($"Simplified detection found {closedPolygons.Count} rooms");
- return closedPolygons;
- }
- private bool IsPointOnAnyWall(Vector3 point, List<GameObject> walls)
- {
- float tolerance = 2.0f; // Distance tolerance for "on wall"
- foreach (GameObject wall in walls)
- {
- if (wall == null) continue;
- // Check if point is close to this wall
- Bounds wallBounds = wall.GetComponent<Renderer>().bounds;
- if (wallBounds.SqrDistance(point) < tolerance * tolerance)
- {
- Debug.Log($"Point {point} is near wall {wall.name}");
- return true;
- }
- }
- return false;
- }
- private bool CanWallsCompleteRoom(Vector3 startPoint, Vector3 endPoint, List<GameObject> walls)
- {
- // Simple check: if we have walls forming the outer boundary and our points connect them,
- // we likely have a completed room
- // Count how many walls we have that could form room boundaries
- int boundaryWalls = 0;
- foreach (GameObject wall in walls)
- {
- if (wall != null && wall.name.Contains("Wall"))
- {
- boundaryWalls++;
- }
- }
- Debug.Log($"Found {boundaryWalls} potential boundary walls");
- // If we have sufficient boundary walls and our points connect them, assume room completion
- return boundaryWalls >= 4; // At least 4 walls needed for a room
- }
- private Vector3 RoundVector3(Vector3 vector, float precision)
- {
- return new Vector3(
- Mathf.Round(vector.x / precision) * precision,
- Mathf.Round(vector.y / precision) * precision,
- Mathf.Round(vector.z / precision) * precision
- );
- }
- private List<Vector3> FindSmallestCycle(Dictionary<Vector3, List<Vector3>> graph, Vector3 start, HashSet<Vector3> globalVisited)
- {
- if (globalVisited.Contains(start)) return null;
- // DFS to find the shortest cycle starting from this point
- HashSet<Vector3> pathVisited = new HashSet<Vector3>();
- List<Vector3> path = new List<Vector3>();
- if (DFSFindCycle(graph, start, start, pathVisited, path))
- {
- return new List<Vector3>(path);
- }
- return null;
- }
- private bool DFSFindCycle(Dictionary<Vector3, List<Vector3>> graph, Vector3 current, Vector3 target, HashSet<Vector3> pathVisited, List<Vector3> path)
- {
- // Check if we found a cycle back to start - use exact equality since we're using rounded coordinates
- if (path.Count > 0 && path.Count >= 3)
- {
- // Check if current point connects back to target in the graph
- if (graph.ContainsKey(current) && graph[current].Contains(target))
- {
- Debug.Log($"Found cycle! Path length: {path.Count}");
- return true;
- }
- }
- if (path.Count > 6) return false; // Limit search depth to avoid infinite loops
- pathVisited.Add(current);
- path.Add(current);
- if (graph.ContainsKey(current))
- {
- foreach (var neighbor in graph[current])
- {
- // Don't revisit the previous node (except when completing cycle)
- if (path.Count == 1 ||
- (!pathVisited.Contains(neighbor)) ||
- (path.Count >= 3 && neighbor.Equals(target)))
- {
- if (DFSFindCycle(graph, neighbor, target, pathVisited, path))
- return true;
- }
- }
- }
- pathVisited.Remove(current);
- path.RemoveAt(path.Count - 1);
- return false;
- }
- #endregion
- }
- // Data classes
- [System.Serializable]
- public class Room
- {
- public List<Vector3> roomPoints = new List<Vector3>();
- public List<GameObject> wallObjects = new List<GameObject>();
- public bool isComplete = false;
- public RoomType roomType = RoomType.Generic;
- public Vector3 doorPosition;
- public bool hasEntrance = false;
- public bool hasReception = false;
- }
- public enum RoomType
- {
- Generic,
- Reception,
- GuestRoom,
- Restaurant,
- Kitchen,
- Storage,
- Bathroom,
- Lobby
- }
|