using UnityEngine; namespace GraphicsCat { public class SoftBoundaryFloating : MonoBehaviour { [Header("Floating Area")] public Vector3 floatingAreaSize = new Vector3(5f, 5f, 5f); [Tooltip("Start changing direction when close to boundary")] public float boundaryBufferDistance = 0.5f; [Header("Movement Settings")] public float maxSpeed = 1f; public float directionChangeSmoothness = 2f; public Vector2 directionChangeInterval = new Vector2(2f, 5f); private Vector3 _currentDirection; private Vector3 _targetDirection; private Vector3 _initialLocalPosition; private float _nextDirectionChangeTime; private void Start() { _initialLocalPosition = transform.localPosition; _currentDirection = Random.insideUnitSphere.normalized; _targetDirection = Random.insideUnitSphere.normalized; ScheduleNextDirectionChange(); } private void Update() { if (Time.time >= _nextDirectionChangeTime || IsNearBoundary()) { _targetDirection = CalculateNewDirection(); ScheduleNextDirectionChange(); } _currentDirection = Vector3.Slerp( _currentDirection, _targetDirection, directionChangeSmoothness * Time.deltaTime ); transform.localPosition += _currentDirection * maxSpeed * Time.deltaTime; } private bool IsNearBoundary() { Vector3 localPos = transform.localPosition - _initialLocalPosition; float halfX = floatingAreaSize.x / 2f - boundaryBufferDistance; float halfY = floatingAreaSize.y / 2f - boundaryBufferDistance; float halfZ = floatingAreaSize.z / 2f - boundaryBufferDistance; return Mathf.Abs(localPos.x) > halfX || Mathf.Abs(localPos.y) > halfY || Mathf.Abs(localPos.z) > halfZ; } private Vector3 CalculateNewDirection() { Vector3 localPos = transform.localPosition - _initialLocalPosition; Vector3 awayFromEdge = Vector3.zero; float weightX = Mathf.Clamp01((Mathf.Abs(localPos.x) - floatingAreaSize.x / 2f + boundaryBufferDistance) / boundaryBufferDistance); float weightY = Mathf.Clamp01((Mathf.Abs(localPos.y) - floatingAreaSize.y / 2f + boundaryBufferDistance) / boundaryBufferDistance); float weightZ = Mathf.Clamp01((Mathf.Abs(localPos.z) - floatingAreaSize.z / 2f + boundaryBufferDistance) / boundaryBufferDistance); awayFromEdge.x = -Mathf.Sign(localPos.x) * weightX; awayFromEdge.y = -Mathf.Sign(localPos.y) * weightY; awayFromEdge.z = -Mathf.Sign(localPos.z) * weightZ; Vector3 randomDir = Random.insideUnitSphere.normalized; return (randomDir + awayFromEdge * 2f).normalized; } private void ScheduleNextDirectionChange() { _nextDirectionChangeTime = Time.time + Random.Range( directionChangeInterval.x, directionChangeInterval.y ); } // Correction: Gizmos position displays correctly in edit mode private void OnDrawGizmosSelected() { Gizmos.color = Color.cyan; // Key change: get the world matrix of the current object Matrix4x4 gizmoMatrix = Matrix4x4.TRS( transform.position, transform.rotation, transform.lossyScale ); Gizmos.matrix = gizmoMatrix; Gizmos.DrawWireCube(Vector3.zero, floatingAreaSize); if (boundaryBufferDistance > 0) { Gizmos.color = Color.yellow; Vector3 bufferSize = floatingAreaSize - Vector3.one * boundaryBufferDistance * 2f; Gizmos.DrawWireCube(Vector3.zero, bufferSize); } } } }