using UnityEngine; using System.Collections.Generic; using System; using UnityEngine.EventSystems; using Plan2D; using Unity.VisualScripting; [RequireComponent(typeof(MeshCollider))] [RequireComponent(typeof(MoveObjectCategory))] [RequireComponent(typeof(ObjectDataVisualizer))] public class MoveObject : MonoBehaviour { Transform lastHit; Transform _attachedTo; public Transform AttachedTo { get { //print("From move _objectNumber=====" + _objectNumber); string objectName = _G.OBJs[_objectNumber][22]; //print("From move objectName=====" + objectName); if (_attachedTo == null) { _attachedTo = SceneModeManager.GetObjectInRoom(objectName); if (_attachedTo == null) { Debug.Log("Unable to find " + objectName); return null; } } else if (_attachedTo.name == objectName) { return _attachedTo; } _attachedTo = SceneModeManager.GetObjectInRoom(objectName); return _attachedTo; } set { string current = _G.OBJs[_objectNumber][22]; if (_attachedTo == value) { //Debug.Log("Do nothing, value is already the same"); } else { _attachedTo = value; _G.OBJs[_objectNumber][22] = _attachedTo.name; } } } ObjectDataVisualizer _visualizer; Plane _plane; Vector3 _movementOffset; Vector3 _planeOrigin; Vector3 _lastIntersection; Vector3 _startPos; Quaternion _rotation; Vector3 _finalPos; Quaternion _finalRotation; float _initialYPositionForWallMovement = 0; float _verticalThresholdForWallMovement = 2.2f; float _minDistanceToCamera = _G._MinDistanceToCamera + 1f; bool _moving = false; int _objectNumber; bool _isChild = false; bool _hit = false; string _tempParent = ""; public bool Hit { get { return _hit; } } bool _dragging = true; Vector2 _startMousePosition; static bool _usePreciseCollisionCheck = true; static bool _useRayDelta = false; [HideInInspector] public bool IgnoreCollision; //public bool WaitForPlacement = false; static GameObject _hiderControl; bool _allowsChangingAttachedTo = true; public bool _allowRotation; public bool _allowElevating; float _previousPositionVerticalOffset = 0f; private void Awake() { if (!Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift) ) { _objectNumber = Get.GetObjectIndex(this.name); _visualizer = GetComponent(); SetPlaneForRayCast(false, Vector3.zero); _allowsChangingAttachedTo = Plan2DHandler.GetObjectType(_G.OBJs[_objectNumber], AttachedTo.name) != ObjectTypes.StructuralElements; string type = _G.OBJs[_objectNumber][2]; _allowRotation = type != "Patio" && type != "Door" && type != "Opening" && type != "Window"; _allowElevating = type != "Patio" /*&& type != "Door"*/ && type != "Opening"; if (type == "StructureElements") { _allowRotation = false; IgnoreCollision = true; } } } void OnMouseDown() { if (!Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift)) { print("Nameclick====awake 2 " + name); _G.SELECEDLIST = new(); if(_G.SELECEDLIST.Contains(name)){ SceneModeManager.GetObjectInScene(name).GetComponent().material = _G.INV; if (gameObject.layer != 2) { Set.Layer(SceneModeManager.GetObjectInScene(name).gameObject, 0); } _G.SELECEDLIST.Remove(name); } OnMouseDownEvent(); } else { print("Nameclick====awake" + name); if (!_G.SELECEDLIST.Contains(name)) { _G.SELECEDLIST.Add(name); //this.gameObject.transform.GetComponent().material = _G.GBT; //SceneModeManager.GetObjectInScene(name).GetComponent().material = _G.GBT; DOIT.AllSelOff(); } } } private void OnMouseDownEvent() { if (EventSystem.current.IsPointerOverGameObject()) return; if (Input.touchCount > 0 && EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)) return; OnMouseDownEventAfterProtection(); } public void OnMouseDownEventAfterProtection() { if (SceneModeManager.Selected != gameObject && (SceneModeManager.CompareSceneMode(SceneModes.ReadyMove) || SceneModeManager.CompareSceneMode(SceneModes.Panel))) { DOIT.ResetRoomSelect(); DOIT.AllSelOff(); } if (SceneModeManager.Selected != gameObject && SceneModeManager.CompareSceneMode(SceneModes.Navigate)) { HandleSetSelected(); } } public void HandelObjectArrowMove(Vector3 Start, Vector3 End,String Attached_to){ Vector3 delta=Start - End; Vector3 Direction = delta.normalized; if (Attached_to!="floor" && Attached_to!="ceil" ) { DOIT.meshlight(); AddToMove(); CheckAllowedMovement(End, false); } else { DOIT.meshlight(); AddToMove(); CheckAllowedMovement(End, false); } CheckAllowedMovement(End, true); CheckCollisionUsingPrecision(ref Start, End, Direction, true); TopControl.ShowMesure(); } public void OnMouseDragEvent() { if (_moving && (SceneModeManager.CompareSceneMode(SceneModes.MoveHandle) || SceneModeManager.CompareSceneMode(SceneModes.SlidingHandle)) && _G.OBJs[_objectNumber][3] == "UNLOCK") { HandleObjectDrag(); } CheckDraggingState(); } public void OnMouseUpEvent() { print("Pass OnMouseUpEvent()"); if (!SceneModeManager.CompareSceneMode(SceneModes.Panel) && !SceneModeManager.CompareSceneMode(SceneModes.Paint) && SceneModeManager.SelectedName != "") { GroupOn(); } print("SceneModeManager.SelectedName==== "+ SceneModeManager.SelectedName); if (!string.IsNullOrEmpty(SceneModeManager.SelectedName)) { string cO = SceneModeManager.SelectedName[..4]; if (cO == "wind" || cO == "door" || cO == "pati" || cO == "open") { HOLE.RefreshAllWalls(); }// HOLE.wall(_G.OBJs[nO][22]); } if (!SceneModeManager.CompareSceneMode(SceneModes.GroupMove) && !SceneModeManager.CompareSceneMode(SceneModes.ReadyMove) && !SceneModeManager.CompareSceneMode(SceneModes.Paint)) { if (SceneModeManager.CompareSceneMode(SceneModes.Move) || SceneModeManager.CompareSceneMode(SceneModes.Hit)) { HandleMoveOrHitState(); } if (_G.Redflag == true) { Collision.checkALL(); } } } public void HandleSetReadyMoveForBeforeMouseDrag() { if (SceneModeManager.CompareSceneMode(SceneModes.GroupMove) || SceneModeManager.CompareSceneMode(SceneModes.ReadyMove) || SceneModeManager.CompareSceneMode(SceneModes.MoveHandle)) { SetPlaneForRayCast(false, Vector3.zero); Ray ray = GetRayFromScreenPoint(); _lastIntersection = GetIntersectionWithPlane(ray); if (_plane.Raycast(ray, out float dist)) { _movementOffset = transform.position - ray.GetPoint(dist); _initialYPositionForWallMovement = ray.GetPoint(dist).y; _movementOffset.y = 0; } _startMousePosition = _G.TOUCH ? Input.touches[0].position : (Vector2)Input.mousePosition; _dragging = false; } else if (SceneModeManager.CompareSceneMode(SceneModes.SlidingHandle)) { SetPlaneForVerticalMovement(); Ray ray = GetRayFromScreenPoint(); _lastIntersection = GetIntersectionWithPlane(ray); if (_plane.Raycast(ray, out float dist)) { _movementOffset = transform.position - ray.GetPoint(dist); _movementOffset.x = 0; _movementOffset.z = 0; } _startMousePosition = _G.TOUCH ? Input.touches[0].position : (Vector2)Input.mousePosition; _dragging = false; } } public void SetPlaneForVerticalMovement() { if (_plane.normal != Vector3.zero) { if (Physics.Raycast(GetRayFromScreenPoint(), out RaycastHit info)) { // Adjust the RaycastHit point to have the same height as Camera.Main Vector3 adjustedPoint = new Vector3(info.transform.position.x, Camera.main.transform.position.y, info.transform.position.z); // Set the plane's normal to be the direction from the adjusted point towards the camera Vector3 planeNormal = (Camera.main.transform.position - adjustedPoint).normalized; // Set the plane's origin to be the initial RaycastHit point _planeOrigin = info.transform.position; // Set the plane's normal and position _plane.SetNormalAndPosition(planeNormal, _planeOrigin); return; } } // Fallback if the Raycast doesn't hit anything // Set the plane's origin to be attachedTo.transform.position _planeOrigin = this.transform.position; // Set the plane's normal to be facing the camera Vector3 fallbackPlaneNormal = Camera.main.transform.forward; // Set the plane's normal and position //print("_planeOrigin ==v= " +_planeOrigin); _plane.SetNormalAndPosition(fallbackPlaneNormal, _planeOrigin); } private void SetPlaneForRayCast(bool usePosition, Vector3 desiredPos, bool reposition = false) { //print("Attache to === " + AttachedTo.name); float dot = Vector3.Dot(Camera.main.transform.forward, AttachedTo.transform.forward); Vector3 normal = AttachedTo.transform.forward; //if(AttachedTo.name=="floor")normal = AttachedTo.transform.up; if(AttachedTo.name=="ceil")normal = -AttachedTo.transform.up; if (dot < 0.0001f && dot > -0.0001f) { //Debug.Log("TODO: Changes direction of plane, because dot with camera is too steep "); //normal = Vector3.up; } float height = DOIT.ConvertStringToNumber(_G.OBJs[_objectNumber][7]) * 0.5f; if (!usePosition) { Vector3 adjustedPosition = transform.position; adjustedPosition.y -= height; _planeOrigin = adjustedPosition; //Debug.Log("Camera Direction is " + Camera.main.transform.forward + " Direction of AttachedTo: " + AttachedTo.transform.forward + " + Dot is : " + dot); //print("_planeOrigin ==2= " +_planeOrigin); _plane.SetNormalAndPosition(normal, _planeOrigin); return; } if (reposition) { desiredPos = desiredPos - transform.up * height; } _planeOrigin = desiredPos; //print("_planeOrigin === " +_planeOrigin); _plane.SetNormalAndPosition(normal, _planeOrigin); } private void HandleSetSelected() { SceneModeManager.SelectedName = this.name; CommandHandler.Instance.BeforeDataTemp = CommandHandler.CopyObjectData(_G.OBJs[_objectNumber]); MeshRenderer selectedMeshRenderer = gameObject.GetComponent(); if (selectedMeshRenderer != null) { selectedMeshRenderer.material = _G.GGT; if (gameObject.layer != 2) { Set.Layer(selectedMeshRenderer.gameObject, 20); } } // activate state machine if (_hiderControl == null) { _hiderControl = GameObject.Find("HIDER").transform.Find("CONTROL").gameObject; } if (_hiderControl != null) { _hiderControl.SetActive(true); } //_G.NAVIGATE = false; SceneModeManager.Instance.SetSceneMode(SceneModes.ReadyMove); if (!string.IsNullOrEmpty(SceneModeManager.SelectedName)) { DOIT.meshlight(); } TopControl.ShowMesure(); } public void HandleObjectDrag() { Ray currentRay = GetRayFromScreenPoint(); Vector3 currentIntersection = GetIntersectionWithPlane(currentRay); //if (currentIntersection == null) return; if (_lastIntersection == null) { _lastIntersection = currentIntersection; } Vector3 delta = currentIntersection - _lastIntersection; if (SceneModeManager.CompareSceneMode(SceneModes.SlidingHandle)) { HandleDragVertical(); } else { if (AttachedTo == SceneModeManager.Floor || AttachedTo == SceneModeManager.Ceil) { HandleDragOnFloorOrCeiling(delta); } else { if (_allowsChangingAttachedTo) { Vector3 wallDirection = -AttachedTo.transform.forward; float verticalPositionChange = _initialYPositionForWallMovement - currentIntersection.y; float directionBetweenWallAndCamera = Vector3.Dot(wallDirection, Camera.main.transform.forward); //Debug.Log("wallDirection " + wallDirection + " Camera.main.transform.forward " + Camera.main.transform.forward + " directionBetweenWallAndCamera " + directionBetweenWallAndCamera); if (directionBetweenWallAndCamera > 0.2f) { verticalPositionChange *= -1; } if (verticalPositionChange > _verticalThresholdForWallMovement) { UpdateAttachedTo(SceneModeManager.Floor, transform.position); HandleDragOnFloorOrCeiling(delta); } else { HandleDragOnWalls(delta); } } else { HandleDragOnWalls(delta); } } } _lastIntersection = currentIntersection; TopControl.ShowMesure(); //if (_G.MesureONOFF) Mesure.Show(); } public void SetInitialVerticalOffset() { Ray currentRay = GetRayFromScreenPoint(); Vector3 currentIntersection = GetIntersectionWithPlane(currentRay); // Calculate the offset between the current intersection and the object's position on the y-axis _previousPositionVerticalOffset = currentIntersection.y - transform.position.y; } private void HandleDragVertical(/*Vector3 delta*/) { Ray currentRay = GetRayFromScreenPoint(); Vector3 currentIntersection = GetIntersectionWithPlane(currentRay); // Calculate the desired y position based on the initial offset float desiredY = currentIntersection.y - _previousPositionVerticalOffset; // Create a new position with the desired y and current x and z Vector3 desiredPosition = new (transform.position.x, desiredY, transform.position.z); DOIT.meshlight(); AddToMove(); //print("desiredPosition===="+desiredPosition); CheckAllowedMovement(desiredPosition, false); } private Vector3 GetIntersectionWithPlane(Ray ray) { if (_plane.Raycast(ray, out float distance)) { Vector3 rayPoint = ray.GetPoint(distance); return rayPoint; } else { return Vector3.zero; // return null if there's no intersection } } private Vector3 GetIntersectionWithPlane(Ray ray, Plane plane) { if (plane.Raycast(ray, out float distance)) { Vector3 rayPoint = ray.GetPoint(distance); return rayPoint; } else { return Vector3.zero; // return null if there's no intersection } } private void HandleDragOnFloorOrCeiling(Vector3 delta) { if (_useRayDelta) { delta.y = 0f; Vector3 desiredPosition = transform.position + delta; DOIT.meshlight(); AddToMove(); CheckAllowedMovement(desiredPosition, true); } else { Ray ray = GetRayFromScreenPoint(); float distance; DOIT.meshlight(); AddToMove(); if (_plane.Raycast(ray, out distance)) { Vector3 desiredPos = ray.GetPoint(distance); desiredPos.y = transform.position.y; //desiredPos = HitObject.OPosition(desiredPos, Yfact); CheckAllowedMovement(desiredPos, true); } } } private void HandleDragOnWalls(Vector3 delta) { if (_useRayDelta) { delta.y = 0f; float distance = delta.magnitude; float direction = Vector3.Dot(delta, AttachedTo.transform.right) > 0 ? 1f : -1f; // Restrict movement to the right/left direction of attachedTo Vector3 moveAmount = direction * MathF.Abs(distance) * AttachedTo.transform.right; Vector3 desiredPosition = transform.position + moveAmount; DOIT.meshlight(); AddToMove(); CheckAllowedMovement(desiredPosition, false); } else { Ray ray = GetRayFromScreenPoint(); if (_plane.Raycast(ray, out float dist)) { Vector3 hitPosition = ray.GetPoint(dist); hitPosition.y = transform.position.y; DOIT.meshlight(); AddToMove(); CheckAllowedMovement(hitPosition, false); } } } private Ray GetRayFromScreenPoint() { return _G.TOUCH ? Camera.main.ScreenPointToRay(Input.touches[0].position) : Camera.main.ScreenPointToRay(Input.mousePosition); } private void CheckDraggingState() { Vector2 inputPosition = _G.TOUCH ? Input.touches[0].position : (Vector2)Input.mousePosition; if (Mathf.Abs(inputPosition.sqrMagnitude - _startMousePosition.sqrMagnitude) > 1.0f) { _dragging = true; } if (!_moving && _dragging && SceneModeManager.CompareSceneMode(SceneModes.MoveHandle) || SceneModeManager.CompareSceneMode(SceneModes.SlidingHandle)) { _moving = true; UpdateInitialPos(); } } private void HandleMoveOrHitState() { if (_hiderControl == null) { _hiderControl = GameObject.Find("HIDER").transform.Find("CONTROL").gameObject; } { _hiderControl.SetActive(false); Set.alpha(Get.o2("Canvas", "Language"), true); } int nO = Get.GetObjectIndex(SceneModeManager.SelectedName); string cO = SceneModeManager.SelectedName[..4]; GameObject attachedTo = GameObject.Find(_G.OBJs[nO][22]); print("cO======" + cO); if (cO == "wind" || cO == "door" || cO == "pati" || cO == "open") { HOLE.RefreshAllWalls();// HOLE.wall(_G.OBJs[nO][22]); } if (!SceneModeManager.CompareSceneMode(SceneModes.SnapOn)) //"SetsnapOn" { SceneModeManager.SelectedName = this.name; } if (_G.HIT != "" && _G.HIT.IndexOf("sceil") ==-1 && SceneModeManager.CompareSceneMode(SceneModes.Hit)) { _tempParent = SceneModeManager.SelectedName; grouping.SwitchParent(this.gameObject); if (!_usePreciseCollisionCheck) Push.It(); // _G.SM = "navigate"; //_direction = Vector3.zero; ReplaceInitialParent(); } else { SceneModeManager.SelectedName = this.name; if (SceneModeManager.CompareSceneMode(SceneModes.Navigate)) { Collision.check(Get.GetObjectIndex(SceneModeManager.SelectedName)); } } OnMoveOver(); } private void CheckAllowedMovement(Vector3 desiredPosition, bool allowsSliding) { // Move directly to the desiredPosition if the remaining distance is less than stepSize transform.position = GetFinalAllowedPosition(desiredPosition, allowsSliding); //Debug.Log("finalPosition :" + transform.position); DOIT.SaveObjectPositionInData(transform); } public Vector3 GetFinalAllowedPosition(Vector3 desiredPosition, bool allowsSliding) { Vector3 currentPosition = transform.position; Vector3 movementDirection = (desiredPosition - currentPosition).normalized; //_direction = movementDirection; if (movementDirection == Vector3.zero /*&& !_initialCheck*/) { return currentPosition; } if (_usePreciseCollisionCheck) { if (!CheckDistanceWithCamera(ref desiredPosition)) { CheckCollisionUsingPrecision(ref desiredPosition, currentPosition, movementDirection, allowsSliding); //Debug.Log("Check Collision End"); } } // Move directly to the desiredPosition if the remaining distance is less than stepSize return desiredPosition; } bool CheckDistanceWithCamera(ref Vector3 desiredPosition) { float distanceToCamera = Vector3.Distance(desiredPosition, Camera.main.transform.position); //Debug.Log("Distance + " + distanceToCamera); bool isTooClose = distanceToCamera <= _minDistanceToCamera; if (isTooClose) { SetToHit(Camera.main.transform, desiredPosition); float displacementNeeded = _minDistanceToCamera - distanceToCamera + Mathf.Epsilon; // Add Epsilon to ensure the new distance will be larger than _minDistanceToCamera Vector3 delta = -(desiredPosition - transform.position); delta.y = 0f; Vector3 directionAwayFromCamera = delta.normalized; desiredPosition += directionAwayFromCamera * displacementNeeded; } return isTooClose; } private void CheckCollisionUsingPrecision(ref Vector3 desiredPosition, Vector3 currentPosition, Vector3 movementDirection, bool allowsSliding) { Debug.Log("Check Collision 2"); List group = new() { transform }; float initialRemainingDistance = Vector3.Distance(currentPosition, desiredPosition); float closestDisplacement = float.PositiveInfinity; GameObject collidedWith = null; Vector3 nextPositionForTransform = Vector3.zero; group = GetObjectFromGroupGameObject(group); //group = GetObjectFromObjectCategory(group); bool collideForVerticalMovement = SceneModeManager.CompareSceneMode(SceneModes.SlidingHandle); foreach (Transform t in group) { MoveObject moveObject = t.GetComponent(); if (moveObject == null) continue; Vector3 initialTtPosition = t.position; Vector3 tPosition = t.position; Vector3 halfSize = CalculateHalfSize(t); List otherObjects = GetListOfAllObjectToCollide(t, tPosition, movementDirection, initialRemainingDistance, collideForVerticalMovement); float remainingDistance = initialRemainingDistance; float stepSize = 0.1f; // Adjust this value as needed float maxDistance = MathF.Max(MathF.Max(_G.HEIGHT, _G.WIDE), _G.DEPTH); int loopAmount = 6000; if (remainingDistance > maxDistance) { //Debug.Log($"distance is bigger than maxDistance {remainingDistance}"); remainingDistance = maxDistance; desiredPosition = currentPosition; return; } while (remainingDistance > stepSize && loopAmount > 0) { loopAmount--; if (loopAmount == 0) { Debug.Log($"Reach maximum loop amount"); desiredPosition = currentPosition; return; } Vector3 nextPositionToEvaluate = tPosition + movementDirection * stepSize; List movingObjectCorners = CalculateBoxCorners(t, nextPositionToEvaluate, halfSize); foreach (var otherObject in otherObjects) { if (otherObject.TryGetComponent(out MoveObject moveObjectOther)) { if (moveObjectOther.IgnoreCollision) { continue; } } if (moveObject.IgnoreCollision) { if (!(otherObject.CompareTag("wall") || otherObject.CompareTag("floor") || otherObject.CompareTag("ceilling"))) { continue; } } if (IsInGroup(group, otherObject) || (otherObject == AttachedTo.transform && !collideForVerticalMovement) || IgnoreCollisionWithOtherObject(t, group, otherObject)) { // Debug.Log("Ignore Collision with " + otherObject); continue; } Vector3 otherHalfSize = CalculateHalfSize(otherObject); List otherObjectCorners = CalculateBoxCorners(otherObject, otherObject.transform.position, otherHalfSize); allowsSliding = false; var (isColliding, mtv) = CombinedCollisionCheck(movingObjectCorners, otherObjectCorners, movementDirection, allowsSliding); if (isColliding) { //Debug.Log("Collision Detected with " + otherObject + " Mtv calculated :" + mtv +" and movement direction :" + movementDirection); // Step 1: Resolve the collision by moving the box to the non-overlapping position Vector3 newPosition = nextPositionToEvaluate + mtv; Vector3 calculatedPosition = newPosition; //if collideWith Wall , need to slide back along initial Movement direction else the mtv should be enough //if (otherObject.CompareTag("wall")) { // Step 2: Find the direction of a vector perpendicular to the MTV and on the same plane as movementDirection Vector3 perpendicularToMTV = Vector3.Cross(mtv.normalized, movementDirection).normalized; //Debug.Log("perpendicularToMTV " + perpendicularToMTV); if (perpendicularToMTV != Vector3.zero) { Vector3 intersectionPoint = LinePlaneIntersection(tPosition, movementDirection, newPosition, mtv.normalized); if (intersectionPoint != Vector3.zero) { calculatedPosition = intersectionPoint; //Debug.Log("intersectionPoint " + intersectionPoint); } } } //else //{ //Vector3 directionToMTV = (newPosition - intersectionPoint).normalized; //Vector3 deltaMovement = desiredPosition - intersectionPoint; //float dotMovement = Vector3.Dot(deltaMovement, directionToMTV); //Vector3 movementToAdd = directionToMTV * dotMovement; //calculatedPosition = intersectionPoint + movementToAdd; //} if (t != transform) { Vector3 delta = currentPosition - initialTtPosition; calculatedPosition += delta; } float displacement = Vector3.Distance(currentPosition, calculatedPosition); if (displacement < closestDisplacement) { closestDisplacement = displacement; nextPositionForTransform = calculatedPosition; collidedWith = otherObject.gameObject; } remainingDistance = 0; } } tPosition = nextPositionToEvaluate; remainingDistance -= stepSize; } } if (collidedWith != null) { desiredPosition = nextPositionForTransform; desiredPosition = SetToHit(collidedWith.transform, desiredPosition); return; } } public void DebugRayWithDuration(Vector3 start, Vector3 end, Color color, float duration) { Debug.DrawLine(start, end, color, duration); } Vector3 LinePlaneIntersection(Vector3 linePoint, Vector3 lineDirection, Vector3 planePoint, Vector3 planeNormal) { // Calculate the distance from the line point to the plane point Vector3 lineToPlane = planePoint - linePoint; // Calculate the value of t at the intersection point float t = Vector3.Dot(lineToPlane, planeNormal) / Vector3.Dot(lineDirection, planeNormal); // If the denominator is zero, the line and plane are parallel and there is no intersection if (Mathf.Approximately(Vector3.Dot(lineDirection, planeNormal), 0)) { return Vector3.zero; } // Calculate the intersection point Vector3 intersection = linePoint + t * lineDirection; return intersection; } List GetObjectFromGroupGameObject(List group) { Transform groupObject = transform.Find("Group"); if (groupObject != null) { foreach (Transform t in groupObject) { group.Add(t); } } return group; } bool IgnoreCollisionWithOtherObject(Transform movingObject, List group, Transform objectBeingCompared) { movingObject.TryGetComponent(out MoveObjectCategory categoryMovingObject); objectBeingCompared.TryGetComponent(out MoveObjectCategory category); if (category == null && objectBeingCompared.parent == SceneModeManager.Scene) return true; if (categoryMovingObject == null || category == null) return false; bool isMovingObjectDecorative = categoryMovingObject.IsDecoration(); bool isOtherObjectDecorative = category.IsDecoration(); if (!isMovingObjectDecorative && !isOtherObjectDecorative) return false; if (isMovingObjectDecorative && isOtherObjectDecorative) return false; if (isMovingObjectDecorative) { Vector3 halfSize = CalculateHalfSize(movingObject); List corners = CalculateBoxCorners(transform, transform.position, halfSize); float maxDistance = 1f; foreach (Vector3 corner in corners) { Vector3 simulateCollisionCorner = corner + Vector3.up * maxDistance; if (Physics.Raycast(origin: simulateCollisionCorner, direction: Vector3.down, hitInfo: out RaycastHit hit, maxDistance: maxDistance)) { Transform hitTransform = hit.transform; foreach (Transform t in group) { if (hitTransform == t || hit.transform.IsChildOf(t)) break; } return true; } } } if (isOtherObjectDecorative) { // check height to see which one is on top return true; } return false; } private List GetListOfAllObjectToCollide(Transform t, Vector3 halfSize, Vector3 direction, float distance, bool isVerticalCollision) { List all = new List(); //bool useRaycast = true; //if (useRaycast) //{ // // Debug.Log("distance " + distance); // RaycastHit[] infos = Physics.BoxCastAll(t.transform.position, halfSize, direction, t.rotation, distance); // Debug.Log("start"); // foreach (var info in infos) // { // Transform current = info.transform; // if (all.Contains(current)) continue; // if (current == t) continue; // if (current.name == "sfloor" || current.name == "sceil") continue; // all.Add(info.transform); // Debug.Log(info.transform.name); // } // Debug.Log("end"); // return all; //} Transform scene = SceneModeManager.Scene; for (int i = 0; i < scene.childCount; i++) { Transform child = scene.GetChild(i); if (child == this.transform) continue; all.Add(child); } Transform room = SceneModeManager.Room; for (int i = 0; i < room.childCount; i++) { Transform child = room.GetChild(i); if (!isVerticalCollision) { if (child.CompareTag("wall")) { //Transform childOfChild = child.GetChild(0); all.Add(child); } } else { if (child == SceneModeManager.Floor || child == SceneModeManager.Ceil) { all.Add(child); } } } return all; } bool IsInGroup(List group, Transform itemToCompare) { foreach (var t in group) { if (itemToCompare == t || itemToCompare.IsChildOf(t)) { return true; } } return false; } private List CalculateBoxCorners(Transform t, Vector3 center, Vector3 halfSize) { bool isCeilOrFloor = false; float topValue = halfSize.y; float bottomValue = -halfSize.y; if (t == SceneModeManager.Ceil) { isCeilOrFloor = true; bottomValue = 0.1f; } else if (t == SceneModeManager.Floor) { isCeilOrFloor = true; bottomValue = -0.1f; } List corners = new List { // Calculate the eight corners of the box GetCornerAt(t, center, -halfSize.x, bottomValue, -halfSize.z, isCeilOrFloor), GetCornerAt(t, center, -halfSize.x, bottomValue, halfSize.z, isCeilOrFloor), GetCornerAt(t, center, -halfSize.x, topValue, -halfSize.z, isCeilOrFloor), GetCornerAt(t, center, -halfSize.x, topValue, halfSize.z, isCeilOrFloor), GetCornerAt(t, center, halfSize.x, bottomValue, -halfSize.z, isCeilOrFloor), GetCornerAt(t, center, halfSize.x, bottomValue, halfSize.z, isCeilOrFloor), GetCornerAt(t, center, halfSize.x, topValue, -halfSize.z, isCeilOrFloor), GetCornerAt(t, center, halfSize.x, topValue, halfSize.z, isCeilOrFloor), }; return corners; } Vector3 GetCornerAt(Transform t, Vector3 center, float rightOffset, float upOffset, float forwardOffset, bool isCeilOrFloor) { Vector3 upRelativeDirection = isCeilOrFloor ? Vector3.up : t.up; Vector3 rightRelativeDirection = isCeilOrFloor ? Vector3.right : t.right; Vector3 forwardRelativeDirection = isCeilOrFloor ? Vector3.forward : t.forward; Vector3 corner = center + (rightRelativeDirection * rightOffset) + (upRelativeDirection * upOffset) + (forwardRelativeDirection * forwardOffset); return corner; } private (bool, Vector3) CombinedCollisionCheck(List cornersA, List cornersB, Vector3 movementDirection, bool allowsSliding) { // First, perform broad-phase AABB collision detection if (!AABB_Intersect(cornersA, cornersB)) { return (false, Vector3.zero); // If the AABBs don't overlap, there's no collision } return CheckCollisionOverlap(cornersA, cornersB, movementDirection, allowsSliding); } private bool AABB_Intersect(List cornersA, List cornersB) { // Convert the corners to AABBs Vector3 minA = GetAABBMin(cornersA); Vector3 maxA = GetAABBMax(cornersA); Vector3 minB = GetAABBMin(cornersB); Vector3 maxB = GetAABBMax(cornersB); // Perform AABB intersection check float offset = -1e-5f; if (maxA.x + offset <= minB.x || minA.x >= maxB.x + offset) return false; if (maxA.y + offset <= minB.y || minA.y >= maxB.y + offset) return false; if (maxA.z + offset <= minB.z || minA.z >= maxB.z + offset) return false; return true; } private Vector3 GetAABBMin(List corners) { Vector3 min = corners[0]; for (int i = 1; i < corners.Count; i++) { min = Vector3.Min(min, corners[i]); } return min; } private Vector3 GetAABBMax(List corners) { Vector3 max = corners[0]; for (int i = 1; i < corners.Count; i++) { max = Vector3.Max(max, corners[i]); } return max; } private (bool, Vector3) CheckCollisionOverlap(List cornersA, List cornersB, Vector3 movementDirection, bool allowsSliding) { // Edges for box A Vector3 edgeA1 = (cornersA[1] - cornersA[0]).normalized; // X axis Vector3 edgeA2 = (cornersA[2] - cornersA[0]).normalized; // Y axis Vector3 edgeA3 = (cornersA[4] - cornersA[0]).normalized; // Z axis // Edges for box B Vector3 edgeB1 = (cornersB[1] - cornersB[0]).normalized; // X axis Vector3 edgeB2 = (cornersB[2] - cornersB[0]).normalized; // Y axis Vector3 edgeB3 = (cornersB[4] - cornersB[0]).normalized; // Z axis //// Calculate the cross products of the edges of box B with the movement direction of box A //Vector3 axis1 = Vector3.Cross(edgeB1, movementDirection); //Vector3 axis2 = Vector3.Cross(edgeB2, movementDirection); //Vector3 axis3 = Vector3.Cross(edgeB3, movementDirection); //List axes = new List { edgeB1, edgeB2, edgeB3, axis1, axis2, axis3 }; // Calculate the cross products of the edges of box A with the edges of box B Vector3 axisA1 = Vector3.Cross(edgeA1, edgeB1).normalized; Vector3 axisA2 = Vector3.Cross(edgeA1, edgeB2).normalized; Vector3 axisA3 = Vector3.Cross(edgeA1, edgeB3).normalized; Vector3 axisA4 = Vector3.Cross(edgeA2, edgeB1).normalized; Vector3 axisA5 = Vector3.Cross(edgeA2, edgeB2).normalized; Vector3 axisA6 = Vector3.Cross(edgeA2, edgeB3).normalized; Vector3 axisA7 = Vector3.Cross(edgeA3, edgeB1).normalized; Vector3 axisA8 = Vector3.Cross(edgeA3, edgeB2).normalized; Vector3 axisA9 = Vector3.Cross(edgeA3, edgeB3).normalized; List axes = new List { edgeA1, edgeA2, edgeA3, edgeB1, edgeB2, edgeB3, axisA1, axisA2, axisA3, axisA4, axisA5, axisA6, axisA7, axisA8, axisA9 }; Vector3 smallestOverlapAxis = Vector3.zero; float smallestOverlap = float.PositiveInfinity; bool isSliding = false; // Flag to check if sliding is happening // Check for overlap along each axis foreach (Vector3 axis in axes) { // Ignore axis if it is perpendicular to the movement direction if (Mathf.Abs(Vector3.Dot(axis, movementDirection)) < 1e-5f) continue; float minA = float.PositiveInfinity; float maxA = float.NegativeInfinity; float minB = float.PositiveInfinity; float maxB = float.NegativeInfinity; // Project corners of first box onto the axis, and calculate min and max foreach (Vector3 corner in cornersA) { float projection = Vector3.Dot(corner, axis); minA = Mathf.Min(minA, projection); maxA = Mathf.Max(maxA, projection); } // Project corners of second box onto the axis, and calculate min and max foreach (Vector3 corner in cornersB) { float projection = Vector3.Dot(corner, axis); minB = Mathf.Min(minB, projection); maxB = Mathf.Max(maxB, projection); } // If the intervals don't overlap, return false (no collision) if (maxA < minB || maxB < minA) { return (false, Vector3.zero); } float overlap = 0f; // The amount to move Box A if (minA <= minB && maxA <= maxB) // Case 1 { overlap = minB - maxA; // Move Box A to the right } else if (minB < minA && maxB <= maxA) // Case 2 { overlap = maxB - minA; // Move Box A to the left } else if (minA <= minB && maxA > maxB) // Case 3 { overlap = maxB - minA; // Move Box A to the left (?) } else if (minB < minA && maxB > maxA) // Case 4 { overlap = minB - maxA; // Move Box A to the right (?) } //If the overlap is smaller than the smallest recorded overlap, replace it if (Mathf.Abs(overlap) < Mathf.Abs(smallestOverlap)) { smallestOverlap = overlap; smallestOverlapAxis = axis; } } // If sliding is allowed and there is an overlap, return the normal MTV outside Object B if (allowsSliding) { Vector3 normalMtv = -smallestOverlapAxis; return (true, normalMtv * smallestOverlap); } // If we haven't returned yet, the boxes overlap // Return the Minimum Translation Vector (MTV) along the original movement direction return (true, smallestOverlapAxis * smallestOverlap); } private Vector3 CalculateHalfSize(Transform t) { bool isWall = t.CompareTag("wall"); float objectHeight = t.localScale.y - 0.5f; float objectDepth = t.localScale.z - 0.5f; float objectWidth = t.localScale.x - 0.5f; if (isWall) { int wallIndex = int.Parse(t.name[1..]) - 1; // Get the box size from the transform's scale objectHeight = _G.HEIGHT; objectDepth = 0.0f; objectWidth = _G.WallsWidth[wallIndex]; } else { bool isFloorOrCeil = t == SceneModeManager.Floor || t == SceneModeManager.Ceil || t.name == "sfloor" || t.name.IndexOf("sceil")!=-1; if (isFloorOrCeil) { //Debug.Log("Check With Ceil or floor "); objectHeight = 0f; objectDepth = 1000f; objectWidth = 1000f; } } Vector3 halfSize = new Vector3(objectWidth, objectHeight, objectDepth) * 0.5f; // Rotate the halfSize vector to match the object's orientation //halfSize = t.rotation * halfSize; halfSize.x = Mathf.Abs(halfSize.x); halfSize.y = Mathf.Abs(halfSize.y); halfSize.z = Mathf.Abs(halfSize.z); //Debug.Log("halfSize " + halfSize + " for " + t.name); return halfSize; } private Vector3 SetToHit(Transform other, Vector3 calculatedPosition) { Debug.Log("Check Collision 4 " + other.name); _hit = true; if (lastHit != other) { lastHit = other; Mesure.OnUpdate(_hit); } //print(" hit object ==" + other.name); //GameObject.Find(_G.SELECTED).GetComponent().material = _G.GBT; TopControl.ShowMesure(); _G.HIT = other.name; // SceneModeManager.Instance.SetSceneMode(SceneModes.Hit); DOIT.SaveObjectPositionInData(SceneModeManager.Selected); calculatedPosition = CheckCollisionWithWalls(other, calculatedPosition); return calculatedPosition; } public Vector3 CheckCollisionWithWalls(Transform other, Vector3 calculatedPosition) { Debug.Log("Check Collision 3 "+other.name); // Check if hit is with wall if (!other.CompareTag("wall")) return calculatedPosition; if (!other.name.StartsWith("w")) return calculatedPosition; if (gameObject.name[..4].Equals("lamp")) return calculatedPosition; // if is with wall // try to pair selected with hit wall GameObject movingObject = SceneModeManager.Selected; if (movingObject == null) return calculatedPosition; // Prevent switching from and to previous and next wall print("AttachedTo.name.StartsWith===" + AttachedTo.name.StartsWith("w")); if (AttachedTo.name.StartsWith("w")) { return calculatedPosition; } // find closest point of impact on wall // get depth of object // offset it to exit the wall surface int nO = Get.GetObjectIndex(SceneModeManager.SelectedName); // rotate object to match wall //Vector3 wallForward = other.transform.forward; Vector3 wallForward = other.transform.forward; movingObject.transform.rotation = Quaternion.LookRotation(wallForward); int wallIndex = int.Parse(other.name[1..]) - 1; float wallWideness = _G.WallsWidth[wallIndex]; Vector3 direction = other.transform.forward; Vector2 wallCenterPosition = _G.WallsPointCenter[wallIndex]; Vector3 wallP1 = new Vector3(wallCenterPosition.x, calculatedPosition.y, wallCenterPosition.y) - wallWideness * 0.5f * other.transform.right; Vector3 wallP2 = wallP1 + wallWideness * other.transform.right; // Get nextPoint of wall by offseting by measure wide _G.wW[i] //Add Door thickness on some cabinet // float DoorOn = 0; // if (new List() { "W1", "T1", "B1", "W9", "W10", "B9", "B10" }.Contains(_G.OBJs[nO][4])) // { // float DoorThickness = DOIT.ConvertStringToNumber(Get.LibraryValue(GlobalSelectionManager.GetValue(GlobalOption.DOORCAB_0).ModelID, CsvHeaders.Door_Thickness, DataTypes.Door)); // DoorOn = DoorThickness + _G.DGap; // } //float halfObjectDepth = (DOIT.CSn(_G.OBJs[nO][8]) + DoorOn) * 0.5f; float halfObjectDepth = Mathf.Abs(movingObject.transform.lossyScale.z - 0.5f) * 0.5f; // find position of object on the the segment of the wall Vector3 pointOnWall = Plan2DHandler.GetPositionOnLine(calculatedPosition, wallP1, wallP2); pointOnWall.y = calculatedPosition.y; //movingObject.transform.position = pointOnWall + movingObject.transform.forward * halfObjectDepth; Vector3 reposition = pointOnWall - movingObject.transform.forward * halfObjectDepth; //Debug.Log("p1 :" + wallP1 + "; point on wall :" + pointOnWall + "; p2 :" + wallP2); //Debug.Log("halfObjectDepth :" + halfObjectDepth + "; direction :" + movingObject.transform.forward + "; finalPosition :" + reposition); UpdateAttachedTo(other, reposition); return reposition; } private void UpdateAttachedTo(Transform other, Vector3 newPosition) { Debug.Log("Check Collision 1 "+other.name); //int nO = Get.GetObjectIndex(_G.SELECTED); DOIT.ResetRoomSelect(); AttachedTo = other; //Ray ray = GetRayFromScreenPoint(); UpdateLastIntersection(newPosition); SetPlaneForRayCast(true, _lastIntersection); _initialYPositionForWallMovement = _lastIntersection.y; //Debug.Log("Changes Attached to " + other.name); Mesure.OnUpdate(true); //DOIT.meshlight(); } public void GroupOn() { int nsO = Get.GetObjectIndex(SceneModeManager.SelectedName); string[] group = _G.OBJs[nsO][89].Split('_'); foreach (string O in group) { if (O != SceneModeManager.SelectedName && DOIT.exist(Get.GetObjectIndex(O))) { SceneModeManager.GetObjectInScene(O).GetComponent().material = _G.GBT; } } } public void AddToMove() { int nsO = Get.GetObjectIndex(SceneModeManager.SelectedName); string[] group = _G.OBJs[nsO][89].Split('_'); GameObject Sel = SceneModeManager.Selected; if (Sel.transform.Find("Group") == null) { GameObject Group = new GameObject("Group"); Group.transform.SetParent(Sel.transform, true); } foreach (string O in group) { if (O != SceneModeManager.SelectedName && DOIT.exist(Get.GetObjectIndex(O))) { GameObject obj = Get.o1(O); obj.transform.SetParent(Sel.transform.Find("Group").transform); obj.GetComponent()?.SetToMove(true); } } } void ReplaceInitialParent() { if (_tempParent != "") { GameObject initialParent = SceneModeManager.GetObjectInScene(_tempParent).gameObject; grouping.SwitchBackParent(initialParent); } _tempParent = ""; } public void SetToMove(bool moving) { _dragging = moving; _isChild = moving; } private void OnMoveFinishedCallBack(bool byPassCommand = false) { // need to prevent Callback when placing object initialy and you collide with something during the initial placement if (_startPos == Vector3.zero) return; if (Vector3.Distance(_startPos, _finalPos) > Mathf.Epsilon) { MoveCommand moveCommand = new MoveCommand(gameObject, _startPos, _rotation, CommandHandler.Instance.BeforeDataTemp[22], _finalPos, _finalRotation, AttachedTo.name); if (byPassCommand) { moveCommand.Execute(); } else { CommandHandler.Instance.AddToHistory(moveCommand); } CommandHandler.Instance.BeforeDataTemp = null; _G._beforePos = Vector3.zero; _startPos = _finalPos; } } public void OnMoveOver() { if (!_G.GHOSTLIST.Contains(name) && Vector3.Distance(_startPos, transform.position) > Mathf.Epsilon) { //RepositionIntoRoom(); } UpdateFinalPos(); OnMoveFinishedCallBack(); _moving = false; _dragging = false; _hit = false; } public void UpdateInitialPos() { GameObject gameObject = this.gameObject; if (gameObject) { CommandHandler.Instance.BeforeDataTemp = CommandHandler.CopyObjectData(_G.OBJs[_objectNumber]); _G._beforePos = gameObject.transform.position; _startPos = _G._beforePos; _rotation = gameObject.transform.rotation; } } public void UpdateFinalPos() { _finalPos = transform.position; _finalRotation = transform.rotation; } public void UpdateFinalPos(Vector3 finalPos) { _finalPos = finalPos; _finalRotation = transform.rotation; } public void MoveObjectToPos(Vector3 finalPos, bool byPassMoveCommand = false) { UpdateInitialPos(); UpdateFinalPos(finalPos); OnMoveFinishedCallBack(byPassMoveCommand); _moving = false; // DOIT.setPosObj(_G.SELECTED); } public void RepositionIntoRoom() { // if is opening return if (!_allowsChangingAttachedTo) return; // Get the collider of the object Collider collider = gameObject.GetComponent(); // Calculate the bounds of the object in world space Bounds bounds = collider.bounds; bounds.center = transform.TransformPoint(bounds.center); // Transform the center into world space // Calculate the relative room extents based on the world space bounds Vector3 relativeRoomExtents = (new Vector3(_G.WIDE + 0.5f, _G.HEIGHT + 0.5f, _G.DEPTH + 0.5f) - bounds.size) / 2.0f; Vector3 positionObject = transform.position; // Clamp the object's position within the room extents Vector3 newPosition = new Vector3( Mathf.Clamp(positionObject.x, -relativeRoomExtents.x, relativeRoomExtents.x), Mathf.Clamp(positionObject.y, -relativeRoomExtents.y, relativeRoomExtents.y), Mathf.Clamp(positionObject.z, -relativeRoomExtents.z, relativeRoomExtents.z) ); // If the new position is close to the current position, return if (Vector3.Distance(newPosition, positionObject) < Mathf.Epsilon) { return; } // Set the object's position to the new position transform.position = newPosition; // Set the plane for raycast SetPlaneForRayCast(true, newPosition, true); // Update last intersection UpdateLastIntersection(newPosition); } public Vector3 RepositionIntoRoom(Vector3 finalPos) { // if is opning return if (!_allowsChangingAttachedTo) { return GetFinalAllowedPosition(finalPos, true); } Vector3 relativeRoomExtents = (new Vector3(_G.WIDE + 0.5f, _G.HEIGHT + 0.5f, _G.DEPTH + 0.5f) - gameObject.GetComponent().bounds.size) / 2.0f; Vector3 positionObject = finalPos; float newY = positionObject.y > relativeRoomExtents.y ? relativeRoomExtents.y : positionObject.y; newY = positionObject.y < -relativeRoomExtents.y ? -relativeRoomExtents.y : newY; if (!_allowsChangingAttachedTo) { return GetFinalAllowedPosition(new Vector3(finalPos.x, newY, finalPos.z), true); } float newX = positionObject.x > relativeRoomExtents.x ? relativeRoomExtents.x : positionObject.x; newX = positionObject.x < -relativeRoomExtents.x ? -relativeRoomExtents.x : newX; float newZ = positionObject.z > relativeRoomExtents.z ? relativeRoomExtents.z : positionObject.z; newZ = positionObject.z < -relativeRoomExtents.z ? -relativeRoomExtents.z : newZ; Vector3 newPosition = new Vector3(newX, newY, newZ); if (Vector3.Distance(newPosition, positionObject) < Mathf.Epsilon) { return GetFinalAllowedPosition(finalPos, true); } //Debug.Log("Reposition from " + positionObject + ": to " + newPosition); return GetFinalAllowedPosition(newPosition, true); //return GetFinalAllowedPosition(finalPos, true); } private void UpdateLastIntersection(Vector3 currentObjectPosition) { Vector3 position = currentObjectPosition; float height = DOIT.ConvertStringToNumber(_G.OBJs[_objectNumber][7]) * 0.5f; position.y -= height; _lastIntersection = position; _initialYPositionForWallMovement = _lastIntersection.y; } }