123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- using UnityEngine;
- using System.Collections;
- using RootMotion.FinalIK;
- namespace RootMotion.Demos {
- /// <summary>
- /// Demo script for using the Interaction System for touching scene geometry.
- /// </summary>
- public class TouchWalls : MonoBehaviour {
- /// <summary>
- /// Touching functionality for an effector
- /// </summary>
- [System.Serializable]
- public class EffectorLink {
- public bool enabled = true; // Can this effector start touching?
- public FullBodyBipedEffector effectorType; // The type of the effector
- public InteractionObject interactionObject; // The touch interaction object
- public Transform spherecastFrom; // The bone to start the sperecast from
- public float spherecastRadius = 0.1f; // The radius of sperecasting
- public float minDistance = 0.3f; // The minimum spherecast radius to touch
- public float distanceMlp = 1f; // Multiplies the distance of the spherecast
- public LayerMask touchLayers; // The layers to touch
- public float lerpSpeed = 10f; // The speed of lerping the interaction object
- public float minSwitchTime = 0.2f; // The minimum time to switch between touching
- public float releaseDistance= 0.4f; // The distance from the original touch point where the effector will lose contact
- public bool sliding; // Can the effector slide smoothly over the surfaces?
- private Vector3 raycastDirectionLocal;
- private float raycastDistance;
- private bool inTouch;
- private RaycastHit hit = new RaycastHit();
- private Vector3 targetPosition;
- private Quaternion targetRotation;
- private bool initiated;
- private float nextSwitchTime;
- private float speedF;
- // Initiate this instance
- public void Initiate(InteractionSystem interactionSystem) {
- // Find the direction to the interaction objet relative to the sperecastFrom Transform
- raycastDirectionLocal = spherecastFrom.InverseTransformDirection(interactionObject.transform.position - spherecastFrom.position);
- // Find the max distance the sperecast
- raycastDistance = Vector3.Distance(spherecastFrom.position, interactionObject.transform.position);
- // Add to the interaction system delegates
- interactionSystem.OnInteractionStart += OnInteractionStart;
- interactionSystem.OnInteractionResume += OnInteractionResume;
- interactionSystem.OnInteractionStop += OnInteractionStop;
- hit.normal = Vector3.forward;
- targetPosition = interactionObject.transform.position;
- targetRotation = interactionObject.transform.rotation;
- initiated = true;
- }
- // Spherecasting to find the walls
- private bool FindWalls(Vector3 direction) {
- if (!enabled) return false;
- bool found = Physics.SphereCast(spherecastFrom.position, spherecastRadius, direction, out hit, raycastDistance * distanceMlp, touchLayers);
- if (hit.distance < minDistance) found = false;
- return found;
- }
- // Update this instance
- public void Update(InteractionSystem interactionSystem) {
- if (!initiated) return;
- // The default position
- Vector3 direction = spherecastFrom.TransformDirection(raycastDirectionLocal);
- hit.point = spherecastFrom.position + direction;
- // Spherecasting
- bool wallFound = FindWalls(direction);
- // Starting and ending the interactions
- if (!inTouch) {
- if (wallFound && Time.time > nextSwitchTime) {
- interactionObject.transform.parent = null;
- interactionSystem.StartInteraction(effectorType, interactionObject, 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 (!wallFound) {
- // Resume if no wall found
- 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 (wallFound) {
- targetPosition = hit.point;
- targetRotation = Quaternion.LookRotation(-hit.normal);
- } else {
- StopTouch(interactionSystem);
- }
- }
- }
- float speedFTarget = !inTouch || (interactionSystem.IsPaused(effectorType) && interactionObject.transform.position == targetPosition)? 0f: 1f;
- speedF = Mathf.Lerp(speedF, speedFTarget, Time.deltaTime * 3f * interactionSystem.speed);
- // Interpolating the interaction object
- float s = Time.deltaTime * lerpSpeed * speedF * interactionSystem.speed;
- interactionObject.transform.position = Vector3.Lerp(interactionObject.transform.position, targetPosition, s);
- interactionObject.transform.rotation = Quaternion.Slerp(interactionObject.transform.rotation, targetRotation, s);
- }
- // Stop touching the walls
- private void StopTouch(InteractionSystem interactionSystem) {
- interactionObject.transform.parent = interactionSystem.transform;
- nextSwitchTime = Time.time + minSwitchTime / interactionSystem.speed;
- if (interactionSystem.IsPaused(effectorType)) interactionSystem.ResumeInteraction(effectorType);
- else {
- speedF = 0f;
- targetPosition = hit.point;
- targetRotation = Quaternion.LookRotation(-hit.normal);
- }
- }
-
- // Called by the interaction system
- private void OnInteractionStart(FullBodyBipedEffector effectorType, InteractionObject interactionObject) {
- if (effectorType != this.effectorType || interactionObject != this.interactionObject) return;
- inTouch = true;
- }
- // Called by the interaction system
- private void OnInteractionResume(FullBodyBipedEffector effectorType, InteractionObject interactionObject) {
- if (effectorType != this.effectorType || interactionObject != this.interactionObject) return;
- inTouch = false;
- }
- // Called by the interaction system
- private void OnInteractionStop(FullBodyBipedEffector effectorType, InteractionObject interactionObject) {
- if (effectorType != this.effectorType || interactionObject != this.interactionObject) return;
-
- inTouch = false;
- }
- // Cleaning up the delegates
- public void Destroy(InteractionSystem interactionSystem) {
- if (!initiated) return;
- interactionSystem.OnInteractionStart -= OnInteractionStart;
- interactionSystem.OnInteractionResume -= OnInteractionResume;
- interactionSystem.OnInteractionStop -= OnInteractionStop;
- }
- }
- public InteractionSystem interactionSystem; // Reference to the interaciton sytem of the character
- public EffectorLink[] effectorLinks; // The wall touching effectors
- // Initiate the effector links
- void Start() {
- foreach (EffectorLink e in effectorLinks) e.Initiate(interactionSystem);
- }
- // Update touching
- void FixedUpdate() {
- for (int i = 0; i < effectorLinks.Length; i++) effectorLinks[i].Update(interactionSystem);
- }
- // Clean up the delegates
- void OnDestroy() {
- if (interactionSystem != null) {
- for (int i = 0; i < effectorLinks.Length; i++) effectorLinks[i].Destroy(interactionSystem);
- }
- }
- }
- }
|