first commit
This commit is contained in:
260
Assets/Scripts/HandController.cs
Normal file
260
Assets/Scripts/HandController.cs
Normal file
@@ -0,0 +1,260 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class HandController : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Animator _animator;
|
||||
[SerializeField] private Transform _rightGrabPoint;
|
||||
[SerializeField] private Transform _leftGrabPoint;
|
||||
[SerializeField] private float _interactDistance = 3f;
|
||||
[SerializeField] private float _reachSpeed = 6f;
|
||||
[SerializeField] private float _reachOffset = 0.15f;
|
||||
[SerializeField] private LayerMask _interactMask = ~0;
|
||||
[SerializeField] private float _liquidReturnDistance = 3f;
|
||||
[SerializeField] private float _holdScale = 0.6f;
|
||||
[SerializeField] private Vector3 _liquidLocalOffset = new Vector3(0f, 0.0005f, 0f);
|
||||
|
||||
private Camera _camera;
|
||||
private Transform _rightHeldObject;
|
||||
private Transform _leftHeldObject;
|
||||
private Vector3 _rightGrabStartLocalPos;
|
||||
private Vector3 _leftGrabStartLocalPos;
|
||||
private bool _isAnimating;
|
||||
|
||||
private Dictionary<Transform, Vector3> _originalPositions = new Dictionary<Transform, Vector3>();
|
||||
private Dictionary<Transform, Quaternion> _originalRotations = new Dictionary<Transform, Quaternion>();
|
||||
private Dictionary<Transform, Vector3> _originalScales = new Dictionary<Transform, Vector3>();
|
||||
|
||||
public Transform RightHeldObject => _rightHeldObject;
|
||||
public Transform LeftHeldObject => _leftHeldObject;
|
||||
|
||||
void Start()
|
||||
{
|
||||
_camera = Camera.main;
|
||||
_rightGrabStartLocalPos = _rightGrabPoint.localPosition;
|
||||
_leftGrabStartLocalPos = _leftGrabPoint.localPosition;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_isAnimating) return;
|
||||
if (Input.GetKeyDown(KeyCode.R)) HandleRight();
|
||||
if (Input.GetKeyDown(KeyCode.L)) HandleLeft();
|
||||
}
|
||||
|
||||
void HandleRight()
|
||||
{
|
||||
if (_rightHeldObject != null)
|
||||
{
|
||||
Release(_rightHeldObject, _rightGrabPoint, _rightGrabStartLocalPos, "RightOpen");
|
||||
_rightHeldObject = null;
|
||||
return;
|
||||
}
|
||||
TryGrab(_rightGrabPoint, _rightGrabStartLocalPos, "RightGrab", true);
|
||||
}
|
||||
|
||||
void HandleLeft()
|
||||
{
|
||||
if (_leftHeldObject != null)
|
||||
{
|
||||
Release(_leftHeldObject, _leftGrabPoint, _leftGrabStartLocalPos, "LeftOpen");
|
||||
_leftHeldObject = null;
|
||||
return;
|
||||
}
|
||||
TryGrab(_leftGrabPoint, _leftGrabStartLocalPos, "LeftGrab", false);
|
||||
}
|
||||
|
||||
void TryGrab(Transform grabPoint, Vector3 grabStartLocalPos, string animName, bool isRight)
|
||||
{
|
||||
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
|
||||
RaycastHit[] hits = Physics.RaycastAll(ray, _interactDistance, _interactMask);
|
||||
|
||||
foreach (var hit in hits)
|
||||
{
|
||||
Transform target = FindTarget(hit.collider.transform);
|
||||
if (target == null) continue;
|
||||
StartCoroutine(ReachAndGrab(target, grabPoint, grabStartLocalPos, animName, isRight));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Transform FindTarget(Transform current)
|
||||
{
|
||||
while (current != null)
|
||||
{
|
||||
if (current.CompareTag("Target")) return current;
|
||||
if (current.CompareTag("Liquid")) return current;
|
||||
if (current.CompareTag("Breakable")) return current;
|
||||
current = current.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
IEnumerator ReachAndGrab(Transform target, Transform grabPoint, Vector3 grabStartLocalPos, string animName, bool isRight)
|
||||
{
|
||||
_isAnimating = true;
|
||||
NotifyScaleRemoved(target);
|
||||
|
||||
_originalPositions[target] = target.position;
|
||||
_originalRotations[target] = target.rotation;
|
||||
_originalScales[target] = target.lossyScale;
|
||||
|
||||
Vector3 direction = (target.position - grabPoint.position).normalized;
|
||||
Vector3 reachTargetPos = grabPoint.position + direction * _reachOffset;
|
||||
Vector3 startPos = grabPoint.position;
|
||||
float t = 0f;
|
||||
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime * _reachSpeed;
|
||||
grabPoint.position = Vector3.Lerp(startPos, reachTargetPos, t);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
Vector3 originalScale = target.lossyScale;
|
||||
SetupPhysics(target, true);
|
||||
target.SetParent(grabPoint, true);
|
||||
|
||||
Vector3 parentScale = grabPoint.lossyScale;
|
||||
Vector3 holdScale = originalScale * _holdScale;
|
||||
target.localScale = new Vector3(
|
||||
holdScale.x / parentScale.x,
|
||||
holdScale.y / parentScale.y,
|
||||
holdScale.z / parentScale.z
|
||||
);
|
||||
|
||||
target.rotation = Quaternion.Euler(0f, grabPoint.rotation.eulerAngles.y, 0f);
|
||||
|
||||
if (target.CompareTag("Liquid"))
|
||||
target.localPosition = _liquidLocalOffset;
|
||||
else
|
||||
target.localPosition = Vector3.zero;
|
||||
|
||||
if (isRight) _rightHeldObject = target;
|
||||
else _leftHeldObject = target;
|
||||
|
||||
_animator.Play(animName);
|
||||
yield return ReturnGrabPoint(grabPoint, grabStartLocalPos);
|
||||
_isAnimating = false;
|
||||
}
|
||||
|
||||
IEnumerator ReturnGrabPoint(Transform grabPoint, Vector3 startLocalPos)
|
||||
{
|
||||
Vector3 startPos = grabPoint.localPosition;
|
||||
float t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime * _reachSpeed;
|
||||
grabPoint.localPosition = Vector3.Lerp(startPos, startLocalPos, t);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
void Release(Transform obj, Transform grabPoint, Vector3 grabStartLocalPos, string animName)
|
||||
{
|
||||
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
|
||||
bool placedOnScale = false;
|
||||
|
||||
RaycastHit[] hits = Physics.RaycastAll(ray, _interactDistance);
|
||||
foreach (var hit in hits)
|
||||
{
|
||||
ScaleSurface scale = hit.collider.GetComponentInParent<ScaleSurface>();
|
||||
if (scale != null)
|
||||
{
|
||||
obj.SetParent(null, true);
|
||||
SetupPhysics(obj, false);
|
||||
if (_originalScales.ContainsKey(obj))
|
||||
obj.localScale = _originalScales[obj];
|
||||
scale.PlaceObject(obj);
|
||||
placedOnScale = true;
|
||||
break;
|
||||
}
|
||||
|
||||
BalanceScale balance = hit.collider.GetComponentInParent<BalanceScale>();
|
||||
if (balance != null)
|
||||
{
|
||||
obj.SetParent(null, true);
|
||||
SetupPhysics(obj, false);
|
||||
if (_originalScales.ContainsKey(obj))
|
||||
obj.localScale = _originalScales[obj];
|
||||
bool isLeft = Vector3.Dot(
|
||||
hit.point - balance.transform.position,
|
||||
balance.transform.right) < 0;
|
||||
if (isLeft) balance.PlaceLeft(obj);
|
||||
else balance.PlaceRight(obj);
|
||||
placedOnScale = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!placedOnScale)
|
||||
{
|
||||
obj.SetParent(null, true);
|
||||
SetupPhysics(obj, false);
|
||||
if (_originalScales.ContainsKey(obj))
|
||||
obj.localScale = _originalScales[obj];
|
||||
if (obj.CompareTag("Liquid") && _originalPositions.ContainsKey(obj))
|
||||
{
|
||||
float dist = Vector3.Distance(obj.position, _originalPositions[obj]);
|
||||
if (dist <= _liquidReturnDistance)
|
||||
{
|
||||
obj.position = _originalPositions[obj];
|
||||
obj.rotation = _originalRotations[obj];
|
||||
Rigidbody rb = obj.GetComponent<Rigidbody>();
|
||||
if (rb != null) StartCoroutine(FreezeOnPlace(rb));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_originalPositions.Remove(obj);
|
||||
_originalRotations.Remove(obj);
|
||||
_originalScales.Remove(obj);
|
||||
|
||||
StartCoroutine(ReturnGrabPoint(grabPoint, grabStartLocalPos));
|
||||
_animator.Play(animName);
|
||||
}
|
||||
|
||||
private IEnumerator FreezeOnPlace(Rigidbody rb)
|
||||
{
|
||||
rb.isKinematic = true;
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
rb.isKinematic = false;
|
||||
}
|
||||
|
||||
void NotifyScaleRemoved(Transform obj)
|
||||
{
|
||||
MassController[] allMass = FindObjectsOfType<MassController>();
|
||||
foreach (var mc in allMass)
|
||||
mc.RemoveObject(obj.GetComponent<Rigidbody>());
|
||||
|
||||
ScaleSurface[] allSurfaces = FindObjectsOfType<ScaleSurface>();
|
||||
foreach (var surface in allSurfaces)
|
||||
surface.RemoveObject(obj);
|
||||
|
||||
BalanceScale[] allBalances = FindObjectsOfType<BalanceScale>();
|
||||
foreach (var balance in allBalances)
|
||||
balance.RemoveObject(obj);
|
||||
}
|
||||
|
||||
void SetupPhysics(Transform obj, bool disable)
|
||||
{
|
||||
Rigidbody rb = obj.GetComponent<Rigidbody>();
|
||||
Collider[] colliders = obj.GetComponentsInChildren<Collider>();
|
||||
|
||||
if (rb != null)
|
||||
{
|
||||
rb.isKinematic = disable;
|
||||
rb.useGravity = !disable;
|
||||
}
|
||||
|
||||
foreach (var col in colliders)
|
||||
col.enabled = !disable;
|
||||
}
|
||||
|
||||
public bool IsHoldingAny()
|
||||
{
|
||||
return _rightHeldObject != null || _leftHeldObject != null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user