Files
Cielonos/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Camera/LookAtWithConstraints.cs
2026-05-10 11:47:55 -04:00

107 lines
4.2 KiB
C#

#if GRAPH_DESIGNER
/// ---------------------------------------------
/// Behavior Designer
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.CameraTasks
{
using Opsive.GraphDesigner.Runtime.Variables;
using UnityEngine;
[Opsive.Shared.Utility.Category("Camera")]
[Opsive.Shared.Utility.Description("Looks at target with rotation constraints and smoothing.")]
public class LookAtWithConstraints : TargetGameObjectAction
{
[Tooltip("The target GameObject to look at.")]
[SerializeField] protected SharedVariable<GameObject> m_Target;
[Tooltip("The target position. Only used if Target is null.")]
[SerializeField] protected SharedVariable<Vector3> m_TargetPosition;
[Tooltip("The smoothing speed.")]
[SerializeField] protected SharedVariable<float> m_SmoothingSpeed = 5.0f;
[Tooltip("The minimum X rotation (Euler angles).")]
[SerializeField] protected SharedVariable<float> m_MinRotationX = -90.0f;
[Tooltip("The maximum X rotation (Euler angles).")]
[SerializeField] protected SharedVariable<float> m_MaxRotationX = 90.0f;
[Tooltip("The minimum Y rotation (Euler angles).")]
[SerializeField] protected SharedVariable<float> m_MinRotationY = -180.0f;
[Tooltip("The maximum Y rotation (Euler angles).")]
[SerializeField] protected SharedVariable<float> m_MaxRotationY = 180.0f;
[Tooltip("The task will complete when the rotation is within this angle of the target rotation.")]
[SerializeField] protected SharedVariable<float> m_ArrivedAngle = 1f;
private Camera m_ResolvedCamera;
/// <summary>
/// Initializes the target GameObject.
/// </summary>
protected override void InitializeTarget()
{
base.InitializeTarget();
m_ResolvedCamera = m_ResolvedGameObject.GetComponent<Camera>();
}
/// <summary>
/// Updates the camera look at.
/// </summary>
/// <returns>The status of the action.</returns>
public override TaskStatus OnUpdate()
{
if (m_ResolvedCamera == null) {
return TaskStatus.Failure;
}
var targetPosition = GetTargetPosition();
var direction = targetPosition - m_ResolvedCamera.transform.position;
if (direction.sqrMagnitude < 0.01f) {
return TaskStatus.Success;
}
var targetRotation = Quaternion.LookRotation(direction);
var eulerAngles = targetRotation.eulerAngles;
eulerAngles.x = Mathf.Clamp(eulerAngles.x, m_MinRotationX.Value, m_MaxRotationX.Value);
eulerAngles.y = Mathf.Clamp(eulerAngles.y, m_MinRotationY.Value, m_MaxRotationY.Value);
targetRotation = Quaternion.Euler(eulerAngles);
m_ResolvedCamera.transform.rotation = Quaternion.Slerp(m_ResolvedCamera.transform.rotation, targetRotation, m_SmoothingSpeed.Value * Time.deltaTime);
var arrived = Quaternion.Angle(m_ResolvedCamera.transform.rotation, targetRotation) <= m_ArrivedAngle.Value;
if (arrived) {
m_ResolvedCamera.transform.rotation = targetRotation;
}
return arrived ? TaskStatus.Success : TaskStatus.Running;
}
/// <summary>
/// Gets the target position.
/// </summary>
private Vector3 GetTargetPosition()
{
if (m_Target.Value != null) {
return m_Target.Value.transform.position;
} else {
return m_TargetPosition.Value;
}
}
/// <summary>
/// Resets the action values back to their default.
/// </summary>
public override void Reset()
{
base.Reset();
m_Target = null;
m_TargetPosition = null;
m_SmoothingSpeed = 5.0f;
m_MinRotationX = -90.0f;
m_MaxRotationX = 90.0f;
m_MinRotationY = -180.0f;
m_MaxRotationY = 180.0f;
m_ArrivedAngle = 1f;
}
}
}
#endif