- LocalizationManager: 新增翻译表(SetFormatted/SetDuration/LocalizeOperateMsg) - LoginPanel: InputField placeholder本地化、字体颜色保持 - HistoryPanel: 用时数据本地化、placeholder本地化 - RecordDetailPanel: 操作详情消息本地化(LanguageChanged重建) - AppraiseWindowBase: 评价等级本地化、操作消息重建 - EditorAppraiser: 所有评估消息改用InjectOperateMsgLocalized - StudentOperateRecorder: 新增InjectOperateMsgLocalized方法 - LocalizationLanguageTestBar: 单例模式、ScreenSpaceOverlay筛选 - 字体切换时保留颜色和verticalOverflow
220 lines
7.5 KiB
C#
220 lines
7.5 KiB
C#
using DG.Tweening;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using VRTK;
|
|
using VRTK.GrabAttachMechanics;
|
|
|
|
//VR交互控制基类 定义拆装时可抓取和特定位置安装的交互设备
|
|
[RequireComponent(typeof(VRTK_InteractableObject))]
|
|
public abstract class VRGrabInterractableBase : MonoBehaviour, IStepNodeAction
|
|
{
|
|
protected VRTK_InteractableObject vRTK_Interactable;
|
|
public bool defultIsOnRightPos;//默认初始位置和角度是安装目标位置
|
|
|
|
//protected VRTK_BaseGrabAttach vRTK_BaseGrab;
|
|
//启用复位逻辑 设置目标位置
|
|
public bool checkPos;
|
|
|
|
[PropertyActive("checkPos", true, CompareType.NotEqul)]
|
|
public Vector3 rightPos;
|
|
[PropertyActive("checkPos", true, CompareType.NotEqul)]
|
|
public Vector3 allowPosError;//位置检测允许误差 单位m
|
|
//启用复位逻辑 设置目标角度
|
|
public bool checkAngle;
|
|
[PropertyActive("checkAngle", true, CompareType.NotEqul)]
|
|
public Vector3 rightAngle;
|
|
[PropertyActive("checkAngle", true, CompareType.NotEqul)]
|
|
public Vector3 allowAngleError;
|
|
protected bool onFixedPos;//到达特定的位置
|
|
|
|
public UnityAction atFixedPos;//到达特定的工作位置 复位完成后执行
|
|
public UnityAction atFreePos;//放置在了其他位置执行 结束抓取时未满足安置位置时执行
|
|
|
|
|
|
public event UnityAction OnGrabbedEvent;//开始抓取时执行
|
|
public event UnityAction<bool> UnGrabbedEvent;//结束抓取时 是否满足安装条件
|
|
|
|
[SerializeField] protected ProcessEnum currentProcess;
|
|
|
|
public Collider thisCollider;
|
|
|
|
protected virtual void Awake()
|
|
{
|
|
vRTK_Interactable = this.GetComponent<VRTK_InteractableObject>();
|
|
vRTK_Interactable.InteractableObjectUngrabbed += Ungrabbed;
|
|
vRTK_Interactable.InteractableObjectGrabbed += OnGrabbed;
|
|
|
|
vRTK_Interactable.touchHighlightColor = Color.red;
|
|
vRTK_Interactable.touchHighlightColor.a = 0.3f;
|
|
if (GroupLearnHelper.isGroup)//分组训练时添加可抓取物体的 同步发送和处理组件
|
|
{
|
|
this.gameObject.AddComponent<VRGrabedSyncSender>();
|
|
this.gameObject.AddComponent<VRGrabedSyncHandler>();
|
|
}
|
|
SetGrabInteractable(false);//流程未激活时禁用抓取交互
|
|
//vRTK_Interactable.
|
|
|
|
this.GetComponent<VRTK_BaseGrabAttach>().precisionGrab = true;//抓取接触位置 不抓取中心
|
|
if (thisCollider == null)
|
|
{
|
|
thisCollider = this.GetComponentInChildren<Collider>();
|
|
}
|
|
thisCollider.enabled = false;
|
|
|
|
if (checkPos && defultIsOnRightPos)
|
|
{
|
|
SetRightPos(this.transform.localPosition, allowPosError);
|
|
}
|
|
|
|
if (checkAngle && defultIsOnRightPos)
|
|
{
|
|
SetRightAngle(this.transform.localEulerAngles, allowAngleError);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnGrabbed(object sender, InteractableObjectEventArgs e)
|
|
{
|
|
OnGrabbedEvent?.Invoke();
|
|
}
|
|
|
|
protected virtual void Ungrabbed(object sender, InteractableObjectEventArgs e)
|
|
{
|
|
bool onAllowableFixed = false;//判断是否启用了复位逻辑 且满足安装位置需要
|
|
if (checkPos)
|
|
{
|
|
onAllowableFixed = CheckPos();
|
|
}
|
|
if (checkAngle)
|
|
{
|
|
if (checkPos && onAllowableFixed)//检查角度时 若先检查了位置 则先判定是否满足位置要求 若位置不满足 则无需检查 直接判定不满足要求
|
|
onAllowableFixed = CheckAngle();
|
|
}
|
|
|
|
UnGrabbedEvent?.Invoke(onAllowableFixed);
|
|
Debug.Log(this.gameObject.name + "UnGrabbed");
|
|
Ungrabbbed(onAllowableFixed);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 主动操作物体被放下完成位置角度检测后或场景同步时执行
|
|
/// </summary>
|
|
/// <param name="onAllowableFixed">当前位置是否满足安装条件</param>
|
|
public void Ungrabbbed(bool onAllowableFixed)
|
|
{
|
|
if (onAllowableFixed)//满足安装条件
|
|
{
|
|
StartHoming();//播放归位动画
|
|
}
|
|
else//未处于安装位置
|
|
{
|
|
this.gameObject.GetComponent<Rigidbody>().isKinematic = false;//安置在其他位置时 启用刚体影响
|
|
onFixedPos = false;
|
|
atFreePos?.Invoke();
|
|
atFreePos = null;
|
|
}
|
|
}
|
|
|
|
|
|
//开始动画复位到准确的安装位置
|
|
private void StartHoming()
|
|
{
|
|
Debug.Log("开始复位");
|
|
this.gameObject.GetComponent<Rigidbody>().isKinematic = true;//避免重力或其他物体影响其归位
|
|
this.transform.DOLocalMove(rightPos, 1f).OnComplete(HomgingOver);
|
|
this.transform.DOLocalRotateQuaternion(Quaternion.Euler(rightAngle), 1f);
|
|
}
|
|
|
|
//复位完成
|
|
protected virtual void HomgingOver()
|
|
{
|
|
atFixedPos?.Invoke();
|
|
atFixedPos = null;//只执行一次
|
|
onFixedPos = true;
|
|
}
|
|
|
|
//启用/禁用抓取功能
|
|
public void SetGrabInteractable(bool interactable)
|
|
{
|
|
vRTK_Interactable.isGrabbable = interactable;
|
|
}
|
|
|
|
public abstract void Active(ProcessEnum stepName, UnityAction finishedEven);
|
|
|
|
|
|
public virtual void UnActive(ProcessEnum stepName)
|
|
{
|
|
atFixedPos = null;
|
|
atFreePos = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置与父物体的相对正确位置 不设置不检查
|
|
/// </summary>
|
|
/// <param name="targetPos">目标位置</param>
|
|
/// <param name="allowError">误差距离</param>
|
|
public void SetRightPos(Vector3 targetPos, Vector3 allowError)
|
|
{
|
|
checkPos = true;
|
|
rightPos = targetPos;
|
|
allowPosError = allowError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置与父物体的相对正确角度不设置不检查
|
|
/// </summary>
|
|
/// <param name="targetAngle">目标角度</param>
|
|
/// <param name="allowError">允许误差角度</param>
|
|
public void SetRightAngle(Vector3 targetAngle, Vector3 allowError)
|
|
{
|
|
checkAngle = true;
|
|
rightAngle = targetAngle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查位置是否符合要求
|
|
/// </summary>
|
|
/// <returns> true 符合要求</returns>
|
|
bool CheckPos()
|
|
{
|
|
if (Mathf.Abs(this.transform.localPosition.x - rightPos.x) > allowPosError.x)
|
|
return false;
|
|
if (Mathf.Abs(this.transform.localPosition.y - rightPos.y) > allowPosError.y)
|
|
return false;
|
|
if (Mathf.Abs(this.transform.localPosition.z - rightPos.z) > allowPosError.z)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查角度是否符合要求
|
|
/// </summary>
|
|
/// <returns>true 符合要求</returns>
|
|
bool CheckAngle()
|
|
{
|
|
Vector3 currentAngle = NormalizeEuler(this.transform.localEulerAngles);
|
|
|
|
Vector3 targeAngle = NormalizeEuler(rightAngle);
|
|
|
|
if (Mathf.Abs(currentAngle.x - targeAngle.x) > allowAngleError.x || Mathf.Abs(currentAngle.y - targeAngle.y) > allowAngleError.y || Mathf.Abs(currentAngle.z - targeAngle.z) > allowAngleError.z)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
public Vector3 NormalizeEuler(Vector3 rEuler)
|
|
{
|
|
if (rEuler.x < -180f) { rEuler.x = rEuler.x + 360f; }
|
|
else if (rEuler.x > 180f) { rEuler.x = rEuler.x - 360f; }
|
|
|
|
if (rEuler.y < -180f) { rEuler.y = rEuler.y + 360f; }
|
|
else if (rEuler.y > 180f) { rEuler.y = rEuler.y - 360f; }
|
|
|
|
if (rEuler.z < -180f) { rEuler.z = rEuler.z + 360f; }
|
|
else if (rEuler.z > 180f) { rEuler.z = rEuler.z - 360f; }
|
|
return rEuler;
|
|
}
|
|
}
|