unityzgy/Assets/ThirdPackages/VRPackage/VRTK/Scripts/Interactions/GrabAttachMechanics/VRTK_TrackObjectGrabAttach.cs
ayuan9957 bf12e02276 feat: 多语言本地化系统 - 支持中/英/法/俄实时切换
- LocalizationManager: 新增翻译表(SetFormatted/SetDuration/LocalizeOperateMsg)
- LoginPanel: InputField placeholder本地化、字体颜色保持
- HistoryPanel: 用时数据本地化、placeholder本地化
- RecordDetailPanel: 操作详情消息本地化(LanguageChanged重建)
- AppraiseWindowBase: 评价等级本地化、操作消息重建
- EditorAppraiser: 所有评估消息改用InjectOperateMsgLocalized
- StudentOperateRecorder: 新增InjectOperateMsgLocalized方法
- LocalizationLanguageTestBar: 单例模式、ScreenSpaceOverlay筛选
- 字体切换时保留颜色和verticalOverflow
2026-07-16 10:05:59 +08:00

135 lines
6.5 KiB
C#

// Track Object Grab Attach|GrabAttachMechanics|50080
namespace VRTK.GrabAttachMechanics
{
using UnityEngine;
/// <summary>
/// The Track Object Grab Attach script doesn't attach the object to the controller via a joint, instead it ensures the object tracks the direction of the controller.
/// </summary>
/// <remarks>
/// This works well for items that are on hinged joints or objects that require to interact naturally with other scene rigidbodies.
/// </remarks>
/// <example>
/// `VRTK/Examples/021_Controller_GrabbingObjectsWithJoints` demonstrates this grab attach mechanic on the Chest handle and Fire Extinguisher body.
/// </example>
[AddComponentMenu("VRTK/Scripts/Interactions/Grab Attach Mechanics/VRTK_TrackObjectGrabAttach")]
public class VRTK_TrackObjectGrabAttach : VRTK_BaseGrabAttach
{
[Header("Track Options", order = 2)]
[Tooltip("The maximum distance the grabbing controller is away from the object before it is automatically dropped.")]
public float detachDistance = 1f;
[Tooltip("The maximum amount of velocity magnitude that can be applied to the object. Lowering this can prevent physics glitches if objects are moving too fast.")]
public float velocityLimit = float.PositiveInfinity;
[Tooltip("The maximum amount of angular velocity magnitude that can be applied to the object. Lowering this can prevent physics glitches if objects are moving too fast.")]
public float angularVelocityLimit = float.PositiveInfinity;
protected bool isReleasable = true;
/// <summary>
/// The StopGrab method ends the grab of the current object and cleans up the state.
/// </summary>
/// <param name="applyGrabbingObjectVelocity">If true will apply the current velocity of the grabbing object to the grabbed object on release.</param>
public override void StopGrab(bool applyGrabbingObjectVelocity)
{
if (isReleasable)
{
ReleaseObject(applyGrabbingObjectVelocity);
}
base.StopGrab(applyGrabbingObjectVelocity);
}
/// <summary>
/// The CreateTrackPoint method sets up the point of grab to track on the grabbed object.
/// </summary>
/// <param name="controllerPoint">The point on the controller where the grab was initiated.</param>
/// <param name="currentGrabbedObject">The object that is currently being grabbed.</param>
/// <param name="currentGrabbingObject">The object that is currently doing the grabbing.</param>
/// <param name="customTrackPoint">A reference to whether the created track point is an auto generated custom object.</param>
/// <returns>The transform of the created track point.</returns>
public override Transform CreateTrackPoint(Transform controllerPoint, GameObject currentGrabbedObject, GameObject currentGrabbingObject, ref bool customTrackPoint)
{
Transform trackPoint = null;
if (precisionGrab)
{
trackPoint = new GameObject(VRTK_SharedMethods.GenerateVRTKObjectName(true, currentGrabbedObject.name, "TrackObject", "PrecisionSnap", "AttachPoint")).transform;
trackPoint.parent = currentGrabbingObject.transform;
SetTrackPointOrientation(ref trackPoint, currentGrabbedObject.transform, controllerPoint);
customTrackPoint = true;
}
else
{
trackPoint = base.CreateTrackPoint(controllerPoint, currentGrabbedObject, currentGrabbingObject, ref customTrackPoint);
}
return trackPoint;
}
/// <summary>
/// The ProcessUpdate method is run in every Update method on the interactable object. It is responsible for checking if the tracked object has exceeded it's detach distance.
/// </summary>
public override void ProcessUpdate()
{
if (trackPoint && grabbedObjectScript.IsDroppable())
{
float distance = Vector3.Distance(trackPoint.position, initialAttachPoint.position);
if (distance > detachDistance)
{
ForceReleaseGrab();
}
}
}
/// <summary>
/// The ProcessFixedUpdate method is run in every FixedUpdate method on the interactable object. It applies velocity to the object to ensure it is tracking the grabbing object.
/// </summary>
public override void ProcessFixedUpdate()
{
if (!grabbedObject)
{
return;
}
float maxDistanceDelta = 10f;
Vector3 positionDelta = trackPoint.position - (grabbedSnapHandle != null ? grabbedSnapHandle.position : grabbedObject.transform.position);
Quaternion rotationDelta = trackPoint.rotation * Quaternion.Inverse((grabbedSnapHandle != null ? grabbedSnapHandle.rotation : grabbedObject.transform.rotation));
float angle;
Vector3 axis;
rotationDelta.ToAngleAxis(out angle, out axis);
angle = ((angle > 180) ? angle -= 360 : angle);
if (angle != 0)
{
Vector3 angularTarget = angle * axis;
Vector3 calculatedAngularVelocity = Vector3.MoveTowards(grabbedObjectRigidBody.angularVelocity, angularTarget, maxDistanceDelta);
if (angularVelocityLimit == float.PositiveInfinity || calculatedAngularVelocity.sqrMagnitude < angularVelocityLimit)
{
grabbedObjectRigidBody.angularVelocity = calculatedAngularVelocity;
}
}
Vector3 velocityTarget = positionDelta / Time.fixedDeltaTime;
Vector3 calculatedVelocity = Vector3.MoveTowards(grabbedObjectRigidBody.velocity, velocityTarget, maxDistanceDelta);
if (velocityLimit == float.PositiveInfinity || calculatedVelocity.sqrMagnitude < velocityLimit)
{
grabbedObjectRigidBody.velocity = calculatedVelocity;
}
}
protected override void Initialise()
{
tracked = true;
climbable = false;
kinematic = false;
FlipSnapHandles();
}
protected virtual void SetTrackPointOrientation(ref Transform trackPoint, Transform currentGrabbedObject, Transform controllerPoint)
{
trackPoint.position = currentGrabbedObject.position;
trackPoint.rotation = currentGrabbedObject.rotation;
}
}
}