Rework diapason with octo arms
This commit is contained in:
@@ -0,0 +1,461 @@
|
||||
using UnityEngine;
|
||||
|
||||
public enum ArmState
|
||||
{
|
||||
Environmental,
|
||||
TransitionToEquipped,
|
||||
Equipped,
|
||||
TransitionToEnvironmental
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class ArmEquipment
|
||||
{
|
||||
[Header("Arm References")]
|
||||
public OctoIkLimb IkLimb;
|
||||
public Transform HandSocket;
|
||||
|
||||
[Header("Bone References (for procedural animation)")]
|
||||
[Tooltip("Shoulder bone (optional)")]
|
||||
public Transform ShoulderBone;
|
||||
|
||||
[Tooltip("Elbow bone (optional)")]
|
||||
public Transform ElbowBone;
|
||||
|
||||
[Tooltip("Wrist bone (required for rotation)")]
|
||||
public Transform WristBone;
|
||||
|
||||
[Header("Equipped Pose Settings")]
|
||||
[Tooltip("Rotation to apply to shoulder when equipped")]
|
||||
public Vector3 ShoulderRotationOffset = Vector3.zero;
|
||||
|
||||
[Tooltip("Rotation to apply to elbow when equipped")]
|
||||
public Vector3 ElbowRotationOffset = Vector3.zero;
|
||||
|
||||
[Tooltip("Rotation to apply to wrist when equipped")]
|
||||
public Vector3 WristRotationOffset = new Vector3(0, 0, 90);
|
||||
|
||||
[Tooltip("Speed of rotation lerp")]
|
||||
[Range(1f, 20f)]
|
||||
public float RotationSpeed = 10f;
|
||||
|
||||
[Tooltip("Duration of IK blend after unequip transition")]
|
||||
[Range(0.1f, 1f)]
|
||||
public float IkBlendDuration = 0.3f;
|
||||
|
||||
[Header("Transition Settings")]
|
||||
[Tooltip("Position offset where arm exits camera view")]
|
||||
public Vector3 TransitionOffset = new Vector3(0.5f, -0.3f, 0.2f);
|
||||
|
||||
[Tooltip("Duration for arm to move out of view")]
|
||||
public float TransitionOutDuration = 0.3f;
|
||||
|
||||
[Tooltip("Duration for arm to return to view")]
|
||||
public float TransitionInDuration = 0.3f;
|
||||
|
||||
[Tooltip("Curve for transition movement")]
|
||||
public AnimationCurve TransitionCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
||||
|
||||
[Header("Tap Animation")]
|
||||
[Tooltip("Elbow rotation during windup (degrees)")]
|
||||
public float TapWindupRotation = 15f;
|
||||
|
||||
[Tooltip("Duration of windup (pull back)")]
|
||||
public float TapWindupDuration = 0.1f;
|
||||
|
||||
[Tooltip("Duration of strike (forward snap)")]
|
||||
public float TapStrikeDuration = 0.05f;
|
||||
|
||||
[Tooltip("Wrist snap rotation during strike (degrees)")]
|
||||
public float TapWristSnapRotation = 10f;
|
||||
|
||||
[Tooltip("Shake intensity during vibration")]
|
||||
public float ShakeIntensity = 2f;
|
||||
|
||||
[Tooltip("Shake speed (frequency)")]
|
||||
public float ShakeSpeed = 30f;
|
||||
|
||||
[HideInInspector] public ArmState State = ArmState.Environmental;
|
||||
[HideInInspector] public Vector3 OriginalTargetPosition;
|
||||
[HideInInspector] public Quaternion OriginalTargetRotation;
|
||||
[HideInInspector] public GameObject EquippedObject;
|
||||
[HideInInspector] public float IkWeight = 1f;
|
||||
|
||||
[HideInInspector] public Quaternion OriginalShoulderRotation;
|
||||
[HideInInspector] public Quaternion OriginalElbowRotation;
|
||||
[HideInInspector] public Quaternion OriginalWristRotation;
|
||||
|
||||
private int _transitionTweenId = -1;
|
||||
private int _ikWeightTweenId = -1;
|
||||
private int _ikBlendTweenId = -1;
|
||||
private bool _isBlendingToIk = false;
|
||||
|
||||
private int _tapTweenId = -1;
|
||||
private bool _isShaking = false;
|
||||
|
||||
private Quaternion _transitionStartShoulder;
|
||||
private Quaternion _transitionStartElbow;
|
||||
private Quaternion _transitionStartWrist;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (IkLimb != null && IkLimb.Target != null)
|
||||
{
|
||||
OriginalTargetPosition = IkLimb.Target.localPosition;
|
||||
OriginalTargetRotation = IkLimb.Target.localRotation;
|
||||
}
|
||||
|
||||
if (ShoulderBone != null)
|
||||
OriginalShoulderRotation = ShoulderBone.localRotation;
|
||||
|
||||
if (ElbowBone != null)
|
||||
OriginalElbowRotation = ElbowBone.localRotation;
|
||||
|
||||
if (WristBone != null)
|
||||
OriginalWristRotation = WristBone.localRotation;
|
||||
|
||||
State = ArmState.Environmental;
|
||||
IkWeight = 1f;
|
||||
}
|
||||
|
||||
public void StartTransitionToEquipped(GameObject objectToEquip, System.Action onTransitionComplete)
|
||||
{
|
||||
if (State != ArmState.Environmental)
|
||||
return;
|
||||
|
||||
State = ArmState.TransitionToEquipped;
|
||||
EquippedObject = objectToEquip;
|
||||
|
||||
CancelActiveTweens();
|
||||
|
||||
if (IkLimb == null || IkLimb.Target == null)
|
||||
{
|
||||
CompleteEquip(onTransitionComplete);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 transitionTarget = OriginalTargetPosition + TransitionOffset;
|
||||
|
||||
_transitionTweenId = LeanTween.value(IkLimb.gameObject, 0f, 1f, TransitionOutDuration)
|
||||
.setEase(TransitionCurve)
|
||||
.setOnUpdate((float t) => {
|
||||
if (IkLimb != null && IkLimb.Target != null)
|
||||
{
|
||||
IkLimb.Target.localPosition = Vector3.Lerp(IkLimb.Target.localPosition, transitionTarget, t);
|
||||
}
|
||||
})
|
||||
.setOnComplete(() => {
|
||||
_transitionTweenId = -1;
|
||||
CompleteEquip(onTransitionComplete);
|
||||
}).id;
|
||||
|
||||
_ikWeightTweenId = LeanTween.value(IkLimb.gameObject, IkWeight, 0f, TransitionOutDuration * 0.5f)
|
||||
.setOnUpdate((float val) => {
|
||||
IkWeight = val;
|
||||
})
|
||||
.setOnComplete(() => {
|
||||
_ikWeightTweenId = -1;
|
||||
}).id;
|
||||
}
|
||||
|
||||
private void CompleteEquip(System.Action onComplete)
|
||||
{
|
||||
State = ArmState.Equipped;
|
||||
|
||||
if (IkLimb != null)
|
||||
{
|
||||
IkLimb.enabled = false;
|
||||
}
|
||||
|
||||
if (EquippedObject != null && HandSocket != null)
|
||||
{
|
||||
EquippedObject.transform.SetParent(HandSocket, false);
|
||||
EquippedObject.transform.localPosition = Vector3.zero;
|
||||
EquippedObject.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
|
||||
public void UpdateEquippedPose()
|
||||
{
|
||||
if (State != ArmState.Equipped && !_isBlendingToIk)
|
||||
return;
|
||||
|
||||
if (_isShaking)
|
||||
{
|
||||
UpdateShake();
|
||||
return;
|
||||
}
|
||||
|
||||
if (State == ArmState.Equipped)
|
||||
{
|
||||
float deltaTime = UnityEngine.Time.deltaTime;
|
||||
float lerpSpeed = 1f - Mathf.Exp(-RotationSpeed * deltaTime);
|
||||
|
||||
if (ShoulderBone != null)
|
||||
{
|
||||
Quaternion targetRot = OriginalShoulderRotation * Quaternion.Euler(ShoulderRotationOffset);
|
||||
ShoulderBone.localRotation = Quaternion.Slerp(ShoulderBone.localRotation, targetRot, lerpSpeed);
|
||||
}
|
||||
|
||||
if (ElbowBone != null)
|
||||
{
|
||||
Quaternion targetRot = OriginalElbowRotation * Quaternion.Euler(ElbowRotationOffset);
|
||||
ElbowBone.localRotation = Quaternion.Slerp(ElbowBone.localRotation, targetRot, lerpSpeed);
|
||||
}
|
||||
|
||||
if (WristBone != null)
|
||||
{
|
||||
Quaternion targetRot = OriginalWristRotation * Quaternion.Euler(WristRotationOffset);
|
||||
WristBone.localRotation = Quaternion.Slerp(WristBone.localRotation, targetRot, lerpSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void StartTransitionToEnvironmental(System.Action onTransitionComplete)
|
||||
{
|
||||
if (State != ArmState.Equipped)
|
||||
return;
|
||||
|
||||
State = ArmState.TransitionToEnvironmental;
|
||||
|
||||
CancelActiveTweens();
|
||||
|
||||
_transitionStartShoulder = ShoulderBone != null ? ShoulderBone.localRotation : Quaternion.identity;
|
||||
_transitionStartElbow = ElbowBone != null ? ElbowBone.localRotation : Quaternion.identity;
|
||||
_transitionStartWrist = WristBone != null ? WristBone.localRotation : Quaternion.identity;
|
||||
|
||||
if (IkLimb == null || IkLimb.Target == null)
|
||||
{
|
||||
CompleteUnequip(onTransitionComplete);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 currentPosition = IkLimb.Target.localPosition;
|
||||
Vector3 transitionTarget = OriginalTargetPosition + TransitionOffset;
|
||||
|
||||
_ikWeightTweenId = LeanTween.value(IkLimb.gameObject, IkWeight, 0f, TransitionInDuration * 0.5f)
|
||||
.setOnUpdate((float val) => {
|
||||
IkWeight = val;
|
||||
})
|
||||
.setOnComplete(() => {
|
||||
_ikWeightTweenId = -1;
|
||||
}).id;
|
||||
|
||||
_transitionTweenId = LeanTween.value(IkLimb.gameObject, 0f, 1f, TransitionInDuration)
|
||||
.setEase(TransitionCurve)
|
||||
.setOnUpdate((float t) => {
|
||||
if (IkLimb != null && IkLimb.Target != null)
|
||||
{
|
||||
IkLimb.Target.localPosition = Vector3.Lerp(currentPosition, transitionTarget, t);
|
||||
}
|
||||
|
||||
if (ShoulderBone != null)
|
||||
ShoulderBone.localRotation = Quaternion.Slerp(_transitionStartShoulder, OriginalShoulderRotation, t);
|
||||
|
||||
if (ElbowBone != null)
|
||||
ElbowBone.localRotation = Quaternion.Slerp(_transitionStartElbow, OriginalElbowRotation, t);
|
||||
|
||||
if (WristBone != null)
|
||||
WristBone.localRotation = Quaternion.Slerp(_transitionStartWrist, OriginalWristRotation, t);
|
||||
})
|
||||
.setOnComplete(() => {
|
||||
_transitionTweenId = -1;
|
||||
StartIkBlend(onTransitionComplete);
|
||||
}).id;
|
||||
}
|
||||
|
||||
private void StartIkBlend(System.Action onTransitionComplete)
|
||||
{
|
||||
if (IkLimb != null)
|
||||
{
|
||||
IkLimb.enabled = true;
|
||||
}
|
||||
|
||||
if (EquippedObject != null)
|
||||
{
|
||||
if (HandSocket != null)
|
||||
EquippedObject.transform.SetParent(null);
|
||||
|
||||
UnityEngine.Object.Destroy(EquippedObject);
|
||||
EquippedObject = null;
|
||||
}
|
||||
|
||||
_isBlendingToIk = true;
|
||||
|
||||
Quaternion startShoulder = ShoulderBone != null ? ShoulderBone.localRotation : Quaternion.identity;
|
||||
Quaternion startElbow = ElbowBone != null ? ElbowBone.localRotation : Quaternion.identity;
|
||||
Quaternion startWrist = WristBone != null ? WristBone.localRotation : Quaternion.identity;
|
||||
Vector3 startTargetPos = IkLimb != null && IkLimb.Target != null ? IkLimb.Target.localPosition : Vector3.zero;
|
||||
Quaternion startTargetRot = IkLimb != null && IkLimb.Target != null ? IkLimb.Target.localRotation : Quaternion.identity;
|
||||
|
||||
if (IkLimb != null && IkLimb.gameObject != null)
|
||||
{
|
||||
_ikBlendTweenId = LeanTween.value(IkLimb.gameObject, 0f, 1f, IkBlendDuration)
|
||||
.setEase(LeanTweenType.easeOutQuad)
|
||||
.setOnUpdate((float t) => {
|
||||
if (ShoulderBone != null)
|
||||
ShoulderBone.localRotation = Quaternion.Slerp(startShoulder, OriginalShoulderRotation, t);
|
||||
|
||||
if (ElbowBone != null)
|
||||
ElbowBone.localRotation = Quaternion.Slerp(startElbow, OriginalElbowRotation, t);
|
||||
|
||||
if (WristBone != null)
|
||||
WristBone.localRotation = Quaternion.Slerp(startWrist, OriginalWristRotation, t);
|
||||
|
||||
if (IkLimb != null && IkLimb.Target != null)
|
||||
{
|
||||
IkLimb.Target.localPosition = Vector3.Lerp(startTargetPos, OriginalTargetPosition, t);
|
||||
IkLimb.Target.localRotation = Quaternion.Slerp(startTargetRot, OriginalTargetRotation, t);
|
||||
}
|
||||
|
||||
IkWeight = t;
|
||||
})
|
||||
.setOnComplete(() => {
|
||||
_ikBlendTweenId = -1;
|
||||
CompleteUnequip(onTransitionComplete);
|
||||
}).id;
|
||||
}
|
||||
else
|
||||
{
|
||||
CompleteUnequip(onTransitionComplete);
|
||||
}
|
||||
}
|
||||
|
||||
private void CompleteUnequip(System.Action onComplete)
|
||||
{
|
||||
State = ArmState.Environmental;
|
||||
_isBlendingToIk = false;
|
||||
|
||||
if (IkLimb != null && IkLimb.Target != null)
|
||||
{
|
||||
IkLimb.Target.localPosition = OriginalTargetPosition;
|
||||
IkLimb.Target.localRotation = OriginalTargetRotation;
|
||||
}
|
||||
|
||||
if (ShoulderBone != null)
|
||||
ShoulderBone.localRotation = OriginalShoulderRotation;
|
||||
|
||||
if (ElbowBone != null)
|
||||
ElbowBone.localRotation = OriginalElbowRotation;
|
||||
|
||||
if (WristBone != null)
|
||||
WristBone.localRotation = OriginalWristRotation;
|
||||
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
|
||||
public void CancelActiveTweens()
|
||||
{
|
||||
if (_transitionTweenId != -1)
|
||||
{
|
||||
LeanTween.cancel(_transitionTweenId);
|
||||
_transitionTweenId = -1;
|
||||
}
|
||||
|
||||
if (_ikWeightTweenId != -1)
|
||||
{
|
||||
LeanTween.cancel(_ikWeightTweenId);
|
||||
_ikWeightTweenId = -1;
|
||||
}
|
||||
|
||||
if (_ikBlendTweenId != -1)
|
||||
{
|
||||
LeanTween.cancel(_ikBlendTweenId);
|
||||
_ikBlendTweenId = -1;
|
||||
}
|
||||
|
||||
if (_tapTweenId != -1)
|
||||
{
|
||||
LeanTween.cancel(_tapTweenId);
|
||||
_tapTweenId = -1;
|
||||
}
|
||||
|
||||
_isBlendingToIk = false;
|
||||
_isShaking = false;
|
||||
}
|
||||
|
||||
public void PlayTapAnimation()
|
||||
{
|
||||
if (State != ArmState.Equipped)
|
||||
return;
|
||||
|
||||
if (_tapTweenId != -1)
|
||||
{
|
||||
LeanTween.cancel(_tapTweenId);
|
||||
}
|
||||
|
||||
Quaternion elbowStart = ElbowBone != null ? ElbowBone.localRotation : Quaternion.identity;
|
||||
Quaternion wristStart = WristBone != null ? WristBone.localRotation : Quaternion.identity;
|
||||
|
||||
Quaternion elbowWindup = elbowStart * Quaternion.Euler(0, 0, -TapWindupRotation);
|
||||
Quaternion elbowStrike = elbowStart * Quaternion.Euler(0, 0, TapWindupRotation * 0.3f);
|
||||
|
||||
Quaternion wristWindup = wristStart;
|
||||
Quaternion wristStrike = wristStart * Quaternion.Euler(0, 0, -TapWristSnapRotation);
|
||||
|
||||
_tapTweenId = LeanTween.value(IkLimb.gameObject, 0f, 1f, TapWindupDuration)
|
||||
.setOnUpdate((float t) => {
|
||||
if (ElbowBone != null)
|
||||
{
|
||||
ElbowBone.localRotation = Quaternion.Slerp(elbowStart, elbowWindup, t);
|
||||
}
|
||||
if (WristBone != null)
|
||||
{
|
||||
WristBone.localRotation = Quaternion.Slerp(wristStart, wristWindup, t);
|
||||
}
|
||||
})
|
||||
.setOnComplete(() => {
|
||||
_tapTweenId = LeanTween.value(IkLimb.gameObject, 0f, 1f, TapStrikeDuration)
|
||||
.setOnUpdate((float t) => {
|
||||
if (ElbowBone != null)
|
||||
{
|
||||
ElbowBone.localRotation = Quaternion.Slerp(elbowWindup, elbowStrike, t);
|
||||
}
|
||||
if (WristBone != null)
|
||||
{
|
||||
WristBone.localRotation = Quaternion.Slerp(wristWindup, wristStrike, t);
|
||||
}
|
||||
})
|
||||
.setOnComplete(() => {
|
||||
_tapTweenId = LeanTween.value(IkLimb.gameObject, 0f, 1f, 0.1f)
|
||||
.setOnUpdate((float t) => {
|
||||
if (ElbowBone != null)
|
||||
{
|
||||
ElbowBone.localRotation = Quaternion.Slerp(elbowStrike, elbowStart, t);
|
||||
}
|
||||
if (WristBone != null)
|
||||
{
|
||||
WristBone.localRotation = Quaternion.Slerp(wristStrike, wristStart, t);
|
||||
}
|
||||
})
|
||||
.setOnComplete(() => {
|
||||
_tapTweenId = -1;
|
||||
}).id;
|
||||
}).id;
|
||||
}).id;
|
||||
}
|
||||
|
||||
public void StartShake()
|
||||
{
|
||||
_isShaking = true;
|
||||
}
|
||||
|
||||
public void StopShake()
|
||||
{
|
||||
_isShaking = false;
|
||||
}
|
||||
|
||||
public void UpdateShake()
|
||||
{
|
||||
if (!_isShaking || State != ArmState.Equipped || WristBone == null)
|
||||
return;
|
||||
|
||||
float shake = Mathf.Sin(UnityEngine.Time.time * ShakeSpeed) * ShakeIntensity;
|
||||
Quaternion shakeRotation = Quaternion.Euler(shake, shake * 0.5f, 0);
|
||||
|
||||
Quaternion targetRot = OriginalWristRotation * Quaternion.Euler(WristRotationOffset) * shakeRotation;
|
||||
WristBone.localRotation = targetRot;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80d59ec0ac09852429c56ca6c42464c2
|
||||
@@ -0,0 +1,357 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using Unheimlich.Audio;
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
public class DiapasonEquipmentManager : MonoBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private OctoIkArmsImproved _armsSystem;
|
||||
[SerializeField] private GameObject _diapasonPrefab;
|
||||
[SerializeField] private int _equipmentArmIndex = 1;
|
||||
|
||||
[Header("Detection Settings")]
|
||||
[SerializeField] private LayerMask _soundEmitterLayer;
|
||||
[SerializeField] private float _detectionRadius = 0.15f;
|
||||
[SerializeField] private Transform[] _detectionPoints;
|
||||
|
||||
[Header("Visual Feedback")]
|
||||
[SerializeField] private GameObject _contactFeedbackPrefab;
|
||||
|
||||
[Header("Diapason Animation")]
|
||||
[SerializeField] private string _vibratingBoolParam = "IsVibrating";
|
||||
[SerializeField] private string _tapTriggerParam = "Tap";
|
||||
|
||||
[Header("Tap Settings")]
|
||||
[SerializeField] private AudioClip _tapSound;
|
||||
[SerializeField] [Range(0f, 1f)] private float _tapVolume = 1f;
|
||||
[SerializeField] private float _vibrationDuration = 15f;
|
||||
|
||||
public bool IsEquipped => _isEquipped;
|
||||
public AudioListenable CurrentDetectedEmitter => _currentDetectedEmitter;
|
||||
public bool CanTap => _isEquipped && _currentDetectedEmitter != null && !_isVibrating && !_currentDetectedEmitter.HasBeenTapped;
|
||||
|
||||
public event Action<AudioListenable> OnEmitterDetected;
|
||||
public event Action<AudioListenable> OnEmitterLost;
|
||||
|
||||
private GameObject _spawnedDiapason;
|
||||
private bool _isEquipped = false;
|
||||
private AudioListenable _currentDetectedEmitter;
|
||||
private GameObject _contactFeedback;
|
||||
private bool _isVibrating = false;
|
||||
private AudioSource _audioSource;
|
||||
private Coroutine _vibrationCoroutine;
|
||||
private Animator _diapasonAnimator;
|
||||
private ParticleSystem _diapasonParticles;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (_armsSystem == null)
|
||||
{
|
||||
_armsSystem = GetComponent<OctoIkArmsImproved>();
|
||||
if (_armsSystem == null)
|
||||
{
|
||||
Debug.LogError("[DiapasonEquipment] OctoIkArmsImproved not found!");
|
||||
}
|
||||
}
|
||||
|
||||
_audioSource = GetComponent<AudioSource>();
|
||||
if (_audioSource == null)
|
||||
{
|
||||
_audioSource = gameObject.AddComponent<AudioSource>();
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_isEquipped && _armsSystem.GetArmState(_equipmentArmIndex) == ArmState.Equipped)
|
||||
{
|
||||
CheckForSoundEmitters();
|
||||
|
||||
if (Mouse.current != null && Mouse.current.leftButton.wasPressedThisFrame)
|
||||
{
|
||||
if (CanTap)
|
||||
{
|
||||
TapDiapason();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EquipDiapason()
|
||||
{
|
||||
if (_isEquipped)
|
||||
{
|
||||
Debug.LogWarning("[DiapasonEquipment] Diapason already equipped!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_diapasonPrefab == null)
|
||||
{
|
||||
Debug.LogError("[DiapasonEquipment] Diapason prefab not assigned!");
|
||||
return;
|
||||
}
|
||||
|
||||
_spawnedDiapason = Instantiate(_diapasonPrefab);
|
||||
_spawnedDiapason.SetActive(true);
|
||||
|
||||
_diapasonAnimator = _spawnedDiapason.GetComponentInChildren<Animator>(true);
|
||||
if (_diapasonAnimator == null)
|
||||
{
|
||||
Debug.LogWarning("[DiapasonEquipment] No Animator found on spawned diapason");
|
||||
}
|
||||
else
|
||||
{
|
||||
_diapasonAnimator.enabled = false;
|
||||
}
|
||||
|
||||
_diapasonParticles = _spawnedDiapason.GetComponentInChildren<ParticleSystem>(true);
|
||||
if (_diapasonParticles == null)
|
||||
{
|
||||
Debug.LogWarning("[DiapasonEquipment] No ParticleSystem found on spawned diapason");
|
||||
}
|
||||
|
||||
_armsSystem.EquipObjectOnArm(_equipmentArmIndex, _spawnedDiapason, () => {
|
||||
_isEquipped = true;
|
||||
OnDiapasonEquipped();
|
||||
});
|
||||
}
|
||||
|
||||
public void UnequipDiapason()
|
||||
{
|
||||
if (!_isEquipped)
|
||||
{
|
||||
Debug.LogWarning("[DiapasonEquipment] Diapason not equipped!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_vibrationCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_vibrationCoroutine);
|
||||
_vibrationCoroutine = null;
|
||||
}
|
||||
|
||||
if (_currentDetectedEmitter != null)
|
||||
{
|
||||
_currentDetectedEmitter.SetConcentrating(false);
|
||||
_currentDetectedEmitter.StopListening(cancelConcentrationFade: false);
|
||||
_currentDetectedEmitter = null;
|
||||
}
|
||||
|
||||
_armsSystem.UnequipObjectFromArm(_equipmentArmIndex, () => {
|
||||
_isEquipped = false;
|
||||
_spawnedDiapason = null;
|
||||
OnDiapasonUnequipped();
|
||||
});
|
||||
}
|
||||
|
||||
private void CheckForSoundEmitters()
|
||||
{
|
||||
if (_detectionPoints == null || _detectionPoints.Length == 0)
|
||||
return;
|
||||
|
||||
AudioListenable closestEmitter = null;
|
||||
float closestDistance = float.MaxValue;
|
||||
|
||||
foreach (Transform detectionPoint in _detectionPoints)
|
||||
{
|
||||
if (detectionPoint == null)
|
||||
continue;
|
||||
|
||||
Collider[] hits = Physics.OverlapSphere(detectionPoint.position, _detectionRadius, _soundEmitterLayer);
|
||||
|
||||
foreach (Collider hit in hits)
|
||||
{
|
||||
AudioListenable emitter = hit.GetComponent<AudioListenable>();
|
||||
|
||||
if (emitter != null)
|
||||
{
|
||||
float distance = Vector3.Distance(detectionPoint.position, hit.transform.position);
|
||||
|
||||
if (distance < closestDistance)
|
||||
{
|
||||
closestDistance = distance;
|
||||
closestEmitter = emitter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closestEmitter != _currentDetectedEmitter)
|
||||
{
|
||||
if (_currentDetectedEmitter != null)
|
||||
{
|
||||
OnEmitterExited(_currentDetectedEmitter);
|
||||
}
|
||||
|
||||
_currentDetectedEmitter = closestEmitter;
|
||||
|
||||
if (_currentDetectedEmitter != null)
|
||||
{
|
||||
OnEmitterEntered(_currentDetectedEmitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDiapasonEquipped()
|
||||
{
|
||||
if (_diapasonAnimator != null)
|
||||
{
|
||||
_diapasonAnimator.enabled = true;
|
||||
_diapasonAnimator.SetBool(_vibratingBoolParam, false);
|
||||
}
|
||||
|
||||
if (_diapasonParticles != null)
|
||||
{
|
||||
_diapasonParticles.Stop();
|
||||
var emission = _diapasonParticles.emission;
|
||||
emission.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDiapasonUnequipped()
|
||||
{
|
||||
_isVibrating = false;
|
||||
_diapasonAnimator = null;
|
||||
_diapasonParticles = null;
|
||||
}
|
||||
|
||||
public void TapDiapason()
|
||||
{
|
||||
if (!CanTap)
|
||||
{
|
||||
Debug.LogWarning("[DiapasonEquipment] Cannot tap: not equipped, no contact, or already tapped");
|
||||
return;
|
||||
}
|
||||
|
||||
ArmEquipment equipment = _armsSystem.GetArmEquipment(_equipmentArmIndex);
|
||||
if (equipment != null)
|
||||
{
|
||||
equipment.PlayTapAnimation();
|
||||
equipment.StartShake();
|
||||
}
|
||||
|
||||
if (_tapSound != null && _audioSource != null)
|
||||
{
|
||||
_audioSource.PlayOneShot(_tapSound, _tapVolume);
|
||||
}
|
||||
|
||||
if (_diapasonAnimator != null)
|
||||
{
|
||||
_diapasonAnimator.SetTrigger(_tapTriggerParam);
|
||||
_diapasonAnimator.SetBool(_vibratingBoolParam, true);
|
||||
}
|
||||
|
||||
if (_diapasonParticles != null)
|
||||
{
|
||||
var emission = _diapasonParticles.emission;
|
||||
emission.enabled = true;
|
||||
_diapasonParticles.Play();
|
||||
}
|
||||
|
||||
_isVibrating = true;
|
||||
|
||||
if (_currentDetectedEmitter != null)
|
||||
{
|
||||
_currentDetectedEmitter.StartListening(transform.position);
|
||||
}
|
||||
|
||||
if (_vibrationCoroutine != null)
|
||||
StopCoroutine(_vibrationCoroutine);
|
||||
_vibrationCoroutine = StartCoroutine(StopVibrationAfterDuration());
|
||||
}
|
||||
|
||||
private IEnumerator StopVibrationAfterDuration()
|
||||
{
|
||||
yield return new WaitForSeconds(_vibrationDuration);
|
||||
|
||||
if (_diapasonAnimator != null)
|
||||
{
|
||||
_diapasonAnimator.SetBool(_vibratingBoolParam, false);
|
||||
}
|
||||
|
||||
if (_diapasonParticles != null)
|
||||
{
|
||||
_diapasonParticles.Stop();
|
||||
var emission = _diapasonParticles.emission;
|
||||
emission.enabled = false;
|
||||
}
|
||||
|
||||
if (_currentDetectedEmitter != null)
|
||||
{
|
||||
_currentDetectedEmitter.StopListening();
|
||||
}
|
||||
|
||||
ArmEquipment equipment = _armsSystem.GetArmEquipment(_equipmentArmIndex);
|
||||
if (equipment != null)
|
||||
{
|
||||
equipment.StopShake();
|
||||
}
|
||||
|
||||
_isVibrating = false;
|
||||
_vibrationCoroutine = null;
|
||||
}
|
||||
|
||||
private void OnEmitterEntered(AudioListenable emitter)
|
||||
{
|
||||
|
||||
emitter.SetConcentrating(true);
|
||||
|
||||
if (_contactFeedbackPrefab != null && _contactFeedback == null)
|
||||
{
|
||||
_contactFeedback = Instantiate(_contactFeedbackPrefab, emitter.transform);
|
||||
_contactFeedback.transform.localPosition = Vector3.zero;
|
||||
}
|
||||
|
||||
OnEmitterDetected?.Invoke(emitter);
|
||||
}
|
||||
|
||||
private void OnEmitterExited(AudioListenable emitter)
|
||||
{
|
||||
emitter.SetConcentrating(false);
|
||||
|
||||
if (!emitter.HasBeenTapped)
|
||||
{
|
||||
emitter.StopListening();
|
||||
}
|
||||
|
||||
if (_contactFeedback != null)
|
||||
{
|
||||
Destroy(_contactFeedback);
|
||||
_contactFeedback = null;
|
||||
}
|
||||
|
||||
if (_diapasonAnimator != null)
|
||||
{
|
||||
_diapasonAnimator.SetBool(_vibratingBoolParam, false);
|
||||
}
|
||||
|
||||
if (_diapasonParticles != null)
|
||||
{
|
||||
_diapasonParticles.Stop();
|
||||
var emission = _diapasonParticles.emission;
|
||||
emission.enabled = false;
|
||||
}
|
||||
|
||||
_isVibrating = false;
|
||||
|
||||
OnEmitterLost?.Invoke(emitter);
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
if (_detectionPoints == null || !_isEquipped)
|
||||
return;
|
||||
|
||||
Gizmos.color = Color.yellow;
|
||||
|
||||
foreach (Transform detectionPoint in _detectionPoints)
|
||||
{
|
||||
if (detectionPoint != null)
|
||||
{
|
||||
Gizmos.DrawWireSphere(detectionPoint.position, _detectionRadius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38b80731eb88f834ab3d79a566e40b48
|
||||
@@ -0,0 +1,41 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class DiapasonEquipmentTester : MonoBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private DiapasonEquipmentManager _equipmentManager;
|
||||
|
||||
[Header("Input")]
|
||||
[SerializeField] private Key _equipKey = Key.E;
|
||||
[SerializeField] private Key _unequipKey = Key.R;
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_equipmentManager == null)
|
||||
return;
|
||||
|
||||
if (Keyboard.current[_equipKey].wasPressedThisFrame)
|
||||
{
|
||||
_equipmentManager.EquipDiapason();
|
||||
}
|
||||
|
||||
if (Keyboard.current[_unequipKey].wasPressedThisFrame)
|
||||
{
|
||||
_equipmentManager.UnequipDiapason();
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
GUILayout.BeginArea(new Rect(10, 10, 350, 150));
|
||||
GUILayout.Label("=== Diapason Equipment System ===");
|
||||
GUILayout.Label($"Press {_equipKey} to Equip Diapason");
|
||||
GUILayout.Label($"Press {_unequipKey} to Unequip Diapason");
|
||||
GUILayout.Label("");
|
||||
GUILayout.Label("When equipped:");
|
||||
GUILayout.Label("• Move LEFT hand to touch AudioListenable");
|
||||
GUILayout.Label("• LEFT CLICK to tap and activate");
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9279e0fb73118d14ba6f2cf05170a660
|
||||
@@ -0,0 +1,175 @@
|
||||
using UnityEngine;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class DiapasonPoseTweaker : MonoBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private OctoIkArmsImproved _armsSystem;
|
||||
[SerializeField] private int _armIndex = 1;
|
||||
|
||||
[Header("Quick Presets")]
|
||||
[SerializeField] private bool _applyPreset1 = false;
|
||||
[SerializeField] private bool _applyPreset2 = false;
|
||||
[SerializeField] private bool _applyPreset3 = false;
|
||||
|
||||
[Header("Live Tweaking (Runtime Only)")]
|
||||
[SerializeField] private Vector3 _shoulderRotation = new Vector3(20, 0, -10);
|
||||
[SerializeField] private Vector3 _elbowRotation = new Vector3(0, 0, 0);
|
||||
[SerializeField] private Vector3 _wristRotation = new Vector3(0, 0, 90);
|
||||
|
||||
[Header("Preview")]
|
||||
[SerializeField] private bool _previewPose = false;
|
||||
|
||||
private ArmEquipment _equipment;
|
||||
private bool _wasPreviewActive = false;
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
return;
|
||||
|
||||
if (_armsSystem == null)
|
||||
return;
|
||||
|
||||
if (_equipment == null)
|
||||
{
|
||||
var armRigField = typeof(OctoIkArmsImproved).GetField("_rightArm",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
|
||||
if (armRigField != null)
|
||||
{
|
||||
var armRig = armRigField.GetValue(_armsSystem);
|
||||
var equipmentField = armRig.GetType().GetField("Equipment");
|
||||
if (equipmentField != null)
|
||||
{
|
||||
_equipment = (ArmEquipment)equipmentField.GetValue(armRig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_equipment == null)
|
||||
return;
|
||||
|
||||
if (_previewPose && _equipment.State == ArmState.Environmental)
|
||||
{
|
||||
ApplyRotations();
|
||||
_wasPreviewActive = true;
|
||||
}
|
||||
else if (_wasPreviewActive && !_previewPose)
|
||||
{
|
||||
ResetRotations();
|
||||
_wasPreviewActive = false;
|
||||
}
|
||||
|
||||
if (_equipment.State == ArmState.Equipped)
|
||||
{
|
||||
_equipment.ShoulderRotationOffset = _shoulderRotation;
|
||||
_equipment.ElbowRotationOffset = _elbowRotation;
|
||||
_equipment.WristRotationOffset = _wristRotation;
|
||||
}
|
||||
}
|
||||
|
||||
void OnValidate()
|
||||
{
|
||||
if (_applyPreset1)
|
||||
{
|
||||
_applyPreset1 = false;
|
||||
ApplyPreset1();
|
||||
}
|
||||
|
||||
if (_applyPreset2)
|
||||
{
|
||||
_applyPreset2 = false;
|
||||
ApplyPreset2();
|
||||
}
|
||||
|
||||
if (_applyPreset3)
|
||||
{
|
||||
_applyPreset3 = false;
|
||||
ApplyPreset3();
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyPreset1()
|
||||
{
|
||||
_shoulderRotation = new Vector3(30, 0, -15);
|
||||
_elbowRotation = new Vector3(0, 10, 0);
|
||||
_wristRotation = new Vector3(0, 0, 90);
|
||||
Debug.Log("[DiapasonPose] Applied Preset 1: Close to body, slight inward");
|
||||
}
|
||||
|
||||
private void ApplyPreset2()
|
||||
{
|
||||
_shoulderRotation = new Vector3(20, -10, -20);
|
||||
_elbowRotation = new Vector3(0, 0, 0);
|
||||
_wristRotation = new Vector3(0, -15, 90);
|
||||
Debug.Log("[DiapasonPose] Applied Preset 2: Further from left hand, angled");
|
||||
}
|
||||
|
||||
private void ApplyPreset3()
|
||||
{
|
||||
_shoulderRotation = new Vector3(15, 0, -25);
|
||||
_elbowRotation = new Vector3(0, 15, 0);
|
||||
_wristRotation = new Vector3(0, 0, 85);
|
||||
Debug.Log("[DiapasonPose] Applied Preset 3: Natural grip, centered");
|
||||
}
|
||||
|
||||
private void ApplyRotations()
|
||||
{
|
||||
if (_equipment.ShoulderBone != null)
|
||||
{
|
||||
_equipment.ShoulderBone.localRotation = _equipment.OriginalShoulderRotation * Quaternion.Euler(_shoulderRotation);
|
||||
}
|
||||
|
||||
if (_equipment.ElbowBone != null)
|
||||
{
|
||||
_equipment.ElbowBone.localRotation = _equipment.OriginalElbowRotation * Quaternion.Euler(_elbowRotation);
|
||||
}
|
||||
|
||||
if (_equipment.WristBone != null)
|
||||
{
|
||||
_equipment.WristBone.localRotation = _equipment.OriginalWristRotation * Quaternion.Euler(_wristRotation);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetRotations()
|
||||
{
|
||||
if (_equipment.ShoulderBone != null)
|
||||
{
|
||||
_equipment.ShoulderBone.localRotation = _equipment.OriginalShoulderRotation;
|
||||
}
|
||||
|
||||
if (_equipment.ElbowBone != null)
|
||||
{
|
||||
_equipment.ElbowBone.localRotation = _equipment.OriginalElbowRotation;
|
||||
}
|
||||
|
||||
if (_equipment.WristBone != null)
|
||||
{
|
||||
_equipment.WristBone.localRotation = _equipment.OriginalWristRotation;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
return;
|
||||
|
||||
GUILayout.BeginArea(new Rect(10, 150, 350, 250));
|
||||
GUILayout.Label("=== Diapason Pose Tweaker ===");
|
||||
|
||||
GUILayout.Label($"Shoulder: {_shoulderRotation}");
|
||||
GUILayout.Label($"Elbow: {_elbowRotation}");
|
||||
GUILayout.Label($"Wrist: {_wristRotation}");
|
||||
|
||||
GUILayout.Space(10);
|
||||
GUILayout.Label("Tips:");
|
||||
GUILayout.Label("• Shoulder X: + = down, - = up");
|
||||
GUILayout.Label("• Shoulder Y: + = inward, - = outward");
|
||||
GUILayout.Label("• Shoulder Z: + = twist out, - = twist in");
|
||||
GUILayout.Label("• Elbow Y: + = bend out, - = bend in");
|
||||
GUILayout.Label("• Wrist Z: rotation du diapason");
|
||||
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d1a1f500877b404fa6d23dff3bfa8c8
|
||||
@@ -0,0 +1,32 @@
|
||||
using UnityEngine;
|
||||
|
||||
[System.Serializable]
|
||||
public class TapAnimationSettings
|
||||
{
|
||||
[Header("Tap Motion")]
|
||||
[Tooltip("Elbow rotation during windup (degrees)")]
|
||||
public float WindupRotation = 15f;
|
||||
|
||||
[Tooltip("Duration of windup (pull back)")]
|
||||
public float WindupDuration = 0.1f;
|
||||
|
||||
[Tooltip("Duration of strike (forward snap)")]
|
||||
public float StrikeDuration = 0.05f;
|
||||
|
||||
[Tooltip("Wrist snap rotation during strike (degrees)")]
|
||||
public float WristSnapRotation = 10f;
|
||||
|
||||
[Header("Vibration Shake")]
|
||||
[Tooltip("Shake intensity during vibration")]
|
||||
public float ShakeIntensity = 2f;
|
||||
|
||||
[Tooltip("Shake speed (frequency)")]
|
||||
public float ShakeSpeed = 30f;
|
||||
}
|
||||
|
||||
public class EquippableTapSettings : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TapAnimationSettings _tapSettings = new TapAnimationSettings();
|
||||
|
||||
public TapAnimationSettings TapSettings => _tapSettings;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b46af809fa8f34d49b3dec606a505c5e
|
||||
@@ -27,6 +27,9 @@ public class OctoIkArmsImproved : MonoBehaviour
|
||||
public OctoIkLimb Arm;
|
||||
public Vector3 RotationOffset;
|
||||
public RaycastRig[] Raycasts;
|
||||
|
||||
[Header("Equipment System")]
|
||||
public ArmEquipment Equipment;
|
||||
|
||||
[HideInInspector] public Vector3 TargetOriginPos;
|
||||
[HideInInspector] public Quaternion TargetOriginRot;
|
||||
@@ -47,6 +50,27 @@ public class OctoIkArmsImproved : MonoBehaviour
|
||||
PoleOriginPos = Arm.Pole.localPosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (Equipment != null)
|
||||
{
|
||||
Equipment.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnvironmentalIkActive()
|
||||
{
|
||||
if (Equipment == null)
|
||||
return Enabled;
|
||||
|
||||
return Enabled && Equipment.State == ArmState.Environmental;
|
||||
}
|
||||
|
||||
public float GetEnvironmentalIkWeight()
|
||||
{
|
||||
if (Equipment == null)
|
||||
return 1f;
|
||||
|
||||
return Equipment.IkWeight;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +172,19 @@ public class OctoIkArmsImproved : MonoBehaviour
|
||||
PerformRaycasts();
|
||||
FindNearestHits();
|
||||
UpdateArmPositions();
|
||||
UpdateEquippedPoses();
|
||||
}
|
||||
|
||||
private void UpdateEquippedPoses()
|
||||
{
|
||||
for (int i = 0; i < _arms.Length; i++)
|
||||
{
|
||||
ArmRig armRig = _arms[i];
|
||||
if (armRig.Equipment != null)
|
||||
{
|
||||
armRig.Equipment.UpdateEquippedPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cast all configured raycasts and store results
|
||||
@@ -157,7 +194,7 @@ public class OctoIkArmsImproved : MonoBehaviour
|
||||
{
|
||||
ArmRig armRig = _arms[i];
|
||||
|
||||
if (!armRig.Enabled || armRig.Raycasts == null)
|
||||
if (!armRig.IsEnvironmentalIkActive() || armRig.Raycasts == null)
|
||||
continue;
|
||||
|
||||
for (int u = 0; u < armRig.Raycasts.Length; u++)
|
||||
@@ -247,24 +284,23 @@ public class OctoIkArmsImproved : MonoBehaviour
|
||||
{
|
||||
ArmRig armRig = _arms[i];
|
||||
if (armRig.Arm == null || armRig.Arm.Target == null) continue;
|
||||
|
||||
if (!armRig.IsEnvironmentalIkActive())
|
||||
continue;
|
||||
|
||||
RaycastInfos raycastInfos = _nearestHitRaycasts[i];
|
||||
|
||||
// Default to origin position/rotation
|
||||
Vector3 targetPos = armRig.TargetOriginPos;
|
||||
Quaternion targetRot = armRig.TargetOriginRot;
|
||||
|
||||
bool shouldStick = false;
|
||||
|
||||
// Check if we should stick to surface
|
||||
if (raycastInfos.HasHit && _noHitFrameCount[i] < _settings.StabilityFrames)
|
||||
{
|
||||
if (IsValidSurface(raycastInfos, i))
|
||||
{
|
||||
// Calculate target position on surface
|
||||
targetPos = armRig.Arm.Target.parent.InverseTransformPoint(raycastInfos.Position);
|
||||
|
||||
// Calculate target rotation aligned to surface
|
||||
targetRot = Quaternion.LookRotation(
|
||||
-armRig.Arm.Target.parent.InverseTransformDirection(raycastInfos.Normal),
|
||||
transform.up
|
||||
@@ -274,12 +310,10 @@ public class OctoIkArmsImproved : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
// Smooth stickiness transition
|
||||
float targetStickiness = shouldStick ? 1f : 0f;
|
||||
float stickinessSpeed = shouldStick ? _settings.StickSpeed : _settings.ReleaseSpeed;
|
||||
_currentStickiness[i] = Mathf.MoveTowards(_currentStickiness[i], targetStickiness, stickinessSpeed * Time.deltaTime);
|
||||
|
||||
// Apply distance-based stickiness factor (hysteresis)
|
||||
float distanceFactor = 0f;
|
||||
if (shouldStick && raycastInfos.HasHit)
|
||||
{
|
||||
@@ -287,17 +321,14 @@ public class OctoIkArmsImproved : MonoBehaviour
|
||||
distanceFactor = Mathf.Clamp01(distanceFactor);
|
||||
}
|
||||
|
||||
float finalStickiness = _currentStickiness[i] * distanceFactor;
|
||||
float finalStickiness = _currentStickiness[i] * distanceFactor * armRig.GetEnvironmentalIkWeight();
|
||||
|
||||
// Calculate interpolation speeds
|
||||
float posSpeed = Mathf.Lerp(_settings.ReleaseSpeed, _settings.StickSpeed, finalStickiness);
|
||||
float rotSpeed = _settings.RotationSpeed * Mathf.Deg2Rad;
|
||||
|
||||
// Exponential smoothing for natural movement
|
||||
float tPos = 1f - Mathf.Exp(-posSpeed * Time.deltaTime);
|
||||
float tRot = 1f - Mathf.Exp(-rotSpeed * Time.deltaTime);
|
||||
|
||||
// Apply smooth interpolation
|
||||
armRig.Arm.Target.localPosition = Vector3.Lerp(armRig.Arm.Target.localPosition, targetPos, tPos);
|
||||
armRig.Arm.Target.localRotation = Quaternion.Slerp(armRig.Arm.Target.localRotation, targetRot, tRot);
|
||||
}
|
||||
@@ -327,4 +358,66 @@ public class OctoIkArmsImproved : MonoBehaviour
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void EquipObjectOnArm(int armIndex, GameObject objectToEquip, System.Action onComplete = null)
|
||||
{
|
||||
if (armIndex < 0 || armIndex >= _arms.Length)
|
||||
{
|
||||
Debug.LogError($"[OctoIkArms] Invalid arm index: {armIndex}");
|
||||
return;
|
||||
}
|
||||
|
||||
ArmRig armRig = _arms[armIndex];
|
||||
|
||||
if (armRig.Equipment == null)
|
||||
{
|
||||
Debug.LogError($"[OctoIkArms] Arm {armIndex} has no Equipment system configured!");
|
||||
return;
|
||||
}
|
||||
|
||||
armRig.Equipment.StartTransitionToEquipped(objectToEquip, onComplete);
|
||||
}
|
||||
|
||||
public void UnequipObjectFromArm(int armIndex, System.Action onComplete = null)
|
||||
{
|
||||
if (armIndex < 0 || armIndex >= _arms.Length)
|
||||
{
|
||||
Debug.LogError($"[OctoIkArms] Invalid arm index: {armIndex}");
|
||||
return;
|
||||
}
|
||||
|
||||
ArmRig armRig = _arms[armIndex];
|
||||
|
||||
if (armRig.Equipment == null)
|
||||
{
|
||||
Debug.LogError($"[OctoIkArms] Arm {armIndex} has no Equipment system configured!");
|
||||
return;
|
||||
}
|
||||
|
||||
armRig.Equipment.StartTransitionToEnvironmental(onComplete);
|
||||
}
|
||||
|
||||
public ArmState GetArmState(int armIndex)
|
||||
{
|
||||
if (armIndex < 0 || armIndex >= _arms.Length)
|
||||
return ArmState.Environmental;
|
||||
|
||||
if (_arms[armIndex].Equipment == null)
|
||||
return ArmState.Environmental;
|
||||
|
||||
return _arms[armIndex].Equipment.State;
|
||||
}
|
||||
|
||||
public bool IsArmInEnvironmentalMode(int armIndex)
|
||||
{
|
||||
return GetArmState(armIndex) == ArmState.Environmental;
|
||||
}
|
||||
|
||||
public ArmEquipment GetArmEquipment(int armIndex)
|
||||
{
|
||||
if (armIndex < 0 || armIndex >= _arms.Length)
|
||||
return null;
|
||||
|
||||
return _arms[armIndex].Equipment;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user