107 lines
4.0 KiB
C#
107 lines
4.0 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
} |