Files
2026-03-04 10:03:45 +08:00

214 lines
6.5 KiB
C#

using System;
using RootMotion.FinalIK;
using UnityEngine;
namespace RootMotion.Demos
{
public class TouchWalls : MonoBehaviour
{
[Serializable]
public class EffectorLink
{
public bool enabled = true;
public FullBodyBipedEffector effectorType;
public InteractionObject interactionObject;
public Transform spherecastFrom;
public float spherecastRadius = 0.1f;
public float minDistance = 0.3f;
public LayerMask touchLayers;
public float lerpSpeed = 10f;
public float minSwitchTime = 0.2f;
public float releaseDistance = 0.4f;
public bool sliding;
private Vector3 raycastDirectionLocal;
private float raycastDistance;
private bool inTouch;
private RaycastHit hit;
private Vector3 targetPosition;
private Quaternion targetRotation;
private bool initiated;
private float nextSwitchTime;
private float speedF;
public void Initiate(InteractionSystem interactionSystem)
{
raycastDirectionLocal = spherecastFrom.InverseTransformDirection(interactionObject.transform.position - spherecastFrom.position);
raycastDistance = Vector3.Distance(spherecastFrom.position, interactionObject.transform.position);
interactionSystem.OnInteractionStart = (InteractionSystem.InteractionDelegate)Delegate.Combine(interactionSystem.OnInteractionStart, new InteractionSystem.InteractionDelegate(OnInteractionStart));
interactionSystem.OnInteractionResume = (InteractionSystem.InteractionDelegate)Delegate.Combine(interactionSystem.OnInteractionResume, new InteractionSystem.InteractionDelegate(OnInteractionResume));
interactionSystem.OnInteractionStop = (InteractionSystem.InteractionDelegate)Delegate.Combine(interactionSystem.OnInteractionStop, new InteractionSystem.InteractionDelegate(OnInteractionStop));
hit.normal = Vector3.forward;
targetPosition = interactionObject.transform.position;
targetRotation = interactionObject.transform.rotation;
initiated = true;
}
private bool FindWalls(Vector3 direction)
{
if (!enabled)
{
return false;
}
bool result = Physics.SphereCast(spherecastFrom.position, spherecastRadius, direction, out hit, raycastDistance, touchLayers);
if (hit.distance < minDistance)
{
result = false;
}
return result;
}
public void Update(InteractionSystem interactionSystem)
{
if (!initiated)
{
return;
}
Vector3 vector = spherecastFrom.TransformDirection(raycastDirectionLocal);
hit.point = spherecastFrom.position + vector;
bool flag = FindWalls(vector);
if (!inTouch)
{
if (flag && Time.time > nextSwitchTime)
{
interactionObject.transform.parent = null;
interactionSystem.StartInteraction(effectorType, interactionObject, interrupt: true);
nextSwitchTime = Time.time + minSwitchTime / interactionSystem.speed;
targetPosition = hit.point;
targetRotation = Quaternion.LookRotation(-hit.normal);
interactionObject.transform.position = targetPosition;
interactionObject.transform.rotation = targetRotation;
}
}
else
{
if (!flag)
{
StopTouch(interactionSystem);
}
else if (!interactionSystem.IsPaused(effectorType) || sliding)
{
targetPosition = hit.point;
targetRotation = Quaternion.LookRotation(-hit.normal);
}
if (Vector3.Distance(interactionObject.transform.position, hit.point) > releaseDistance)
{
if (flag)
{
targetPosition = hit.point;
targetRotation = Quaternion.LookRotation(-hit.normal);
}
else
{
StopTouch(interactionSystem);
}
}
}
float b = ((!inTouch || (interactionSystem.IsPaused(effectorType) && interactionObject.transform.position == targetPosition)) ? 0f : 1f);
speedF = Mathf.Lerp(speedF, b, Time.deltaTime * 3f * interactionSystem.speed);
float t = Time.deltaTime * lerpSpeed * speedF * interactionSystem.speed;
interactionObject.transform.position = Vector3.Lerp(interactionObject.transform.position, targetPosition, t);
interactionObject.transform.rotation = Quaternion.Slerp(interactionObject.transform.rotation, targetRotation, t);
}
private void StopTouch(InteractionSystem interactionSystem)
{
interactionObject.transform.parent = interactionSystem.transform;
nextSwitchTime = Time.time + minSwitchTime / interactionSystem.speed;
if (interactionSystem.IsPaused(effectorType))
{
interactionSystem.ResumeInteraction(effectorType);
return;
}
speedF = 0f;
targetPosition = hit.point;
targetRotation = Quaternion.LookRotation(-hit.normal);
}
private void OnInteractionStart(FullBodyBipedEffector effectorType, InteractionObject interactionObject)
{
if (effectorType == this.effectorType && !(interactionObject != this.interactionObject))
{
inTouch = true;
}
}
private void OnInteractionResume(FullBodyBipedEffector effectorType, InteractionObject interactionObject)
{
if (effectorType == this.effectorType && !(interactionObject != this.interactionObject))
{
inTouch = false;
}
}
private void OnInteractionStop(FullBodyBipedEffector effectorType, InteractionObject interactionObject)
{
if (effectorType == this.effectorType && !(interactionObject != this.interactionObject))
{
inTouch = false;
}
}
public void Destroy(InteractionSystem interactionSystem)
{
if (initiated)
{
interactionSystem.OnInteractionStart = (InteractionSystem.InteractionDelegate)Delegate.Remove(interactionSystem.OnInteractionStart, new InteractionSystem.InteractionDelegate(OnInteractionStart));
interactionSystem.OnInteractionResume = (InteractionSystem.InteractionDelegate)Delegate.Remove(interactionSystem.OnInteractionResume, new InteractionSystem.InteractionDelegate(OnInteractionResume));
interactionSystem.OnInteractionStop = (InteractionSystem.InteractionDelegate)Delegate.Remove(interactionSystem.OnInteractionStop, new InteractionSystem.InteractionDelegate(OnInteractionStop));
}
}
}
public InteractionSystem interactionSystem;
public EffectorLink[] effectorLinks;
private void Start()
{
EffectorLink[] array = effectorLinks;
for (int i = 0; i < array.Length; i++)
{
array[i].Initiate(interactionSystem);
}
}
private void FixedUpdate()
{
for (int i = 0; i < effectorLinks.Length; i++)
{
effectorLinks[i].Update(interactionSystem);
}
}
private void OnDestroy()
{
if (interactionSystem != null)
{
for (int i = 0; i < effectorLinks.Length; i++)
{
effectorLinks[i].Destroy(interactionSystem);
}
}
}
}
}