123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- using UnityEngine;
- using System.Collections;
- using RootMotion.FinalIK;
- namespace RootMotion.Demos {
- /// <summary>
- /// Leg of the Mech spider. Controls stepping and positioning the IK target
- /// </summary>
- public class MechSpiderLeg : MonoBehaviour {
-
- public MechSpider mechSpider; // Reference to the target
- public MechSpiderLeg unSync; // One of the other legs that we dont want to be completely in sync with, that is stepping at the same time
- public Vector3 offset; // Offset from the default position
- public float minDelay = 0.2f, maxOffset = 1.0f, stepSpeed = 5.0f, footHeight = 0.15f, velocityPrediction = 0.2f, raycastFocus = 0.1f; // Parameters for stepping
- public AnimationCurve yOffset;
- public Transform foot;
- public Vector3 footUpAxis;
- public float footRotationSpeed = 10f;
-
- public ParticleSystem sand; // FX for sand
- private IK ik;
- private float stepProgress = 1f, lastStepTime;
- private Vector3 defaultPosition;
- private RaycastHit hit = new RaycastHit();
- private Quaternion lastFootLocalRotation;
- private Vector3 smoothHitNormal = Vector3.up;
- private Vector3 lastStepPosition;
- // Is the leg stepping?
- public bool isStepping {
- get {
- return stepProgress < 1f;
- }
- }
- // Gets and sets the IK position for this leg
- public Vector3 position {
- get {
- return ik.GetIKSolver().GetIKPosition();
- }
- set {
- ik.GetIKSolver().SetIKPosition(value);
- }
- }
-
- void Awake()
- {
- // Find the ik component
- ik = GetComponent<IK>();
- if (foot != null)
- {
- if (footUpAxis == Vector3.zero) footUpAxis = Quaternion.Inverse(foot.rotation) * Vector3.up;
- lastFootLocalRotation = foot.localRotation;
- ik.GetIKSolver().OnPostUpdate += AfterIK;
- }
- }
- private void AfterIK()
- {
- if (foot == null) return;
- foot.localRotation = lastFootLocalRotation;
- smoothHitNormal = Vector3.Slerp(smoothHitNormal, hit.normal, Time.deltaTime * footRotationSpeed);
- Quaternion f = Quaternion.FromToRotation(foot.rotation * footUpAxis, smoothHitNormal);
- foot.rotation = f * foot.rotation;
- }
- void Start() {
- // Workaround for Unity Win Store/Phone serialization bug
- stepProgress = 1f;
-
- hit = new RaycastHit();
-
- var points = ik.GetIKSolver().GetPoints();
- position = points[points.Length - 1].transform.position;
- lastStepPosition = position;
- hit.point = position;
- // Store the default rest position of the leg
- defaultPosition = mechSpider.transform.InverseTransformPoint(position + offset * mechSpider.scale);
- StartCoroutine(Step(position, position));
- }
- // Find the relaxed grounded positon of the leg relative to the body in world space.
- private Vector3 GetStepTarget(out bool stepFound, float focus, float distance) {
- stepFound = false;
- // place hit.point to the default position relative to the body
- Vector3 stepTarget = mechSpider.transform.TransformPoint(defaultPosition);
- //stepTarget += (hit.point - position) * velocityPrediction;
- stepTarget += mechSpider.velocity * velocityPrediction;
- Vector3 up = mechSpider.transform.up;
- // Focus the ray directions towards the spider body
- Vector3 toBody = mechSpider.body.position - position;
- Vector3 axis = Vector3.Cross(up, toBody);
- up = Quaternion.AngleAxis(focus, axis) * up;
- // Raycast to ground the relaxed position
- if (Physics.Raycast(stepTarget + up * mechSpider.raycastHeight * mechSpider.scale, -up, out hit, mechSpider.raycastHeight * mechSpider.scale + distance, mechSpider.raycastLayers)) stepFound = true;
- //return hit.point + mechSpider.transform.up * footHeight * mechSpider.scale;
- return hit.point + hit.normal * footHeight * mechSpider.scale;
- }
- private void UpdatePosition(float distance)
- {
- Vector3 up = mechSpider.transform.up;
-
- if (Physics.Raycast(lastStepPosition + up * mechSpider.raycastHeight * mechSpider.scale, -up, out hit, mechSpider.raycastHeight * mechSpider.scale + distance, mechSpider.raycastLayers))
- {
- position = hit.point + hit.normal * footHeight * mechSpider.scale;
- }
- }
- void Update () {
- UpdatePosition(mechSpider.raycastDistance * mechSpider.scale);
- // if already stepping, do nothing
- if (isStepping) return;
- // Minimum delay before stepping again
- if (Time.time < lastStepTime + minDelay) return;
- // If the unSync leg is stepping, do nothing
- if (unSync != null) {
- if (unSync.isStepping) return;
- }
- // Find the ideal relaxed position for the leg relative to the body
- bool stepFound = false;
- Vector3 idealPosition = GetStepTarget(out stepFound, raycastFocus, mechSpider.raycastDistance * mechSpider.scale);
- if (!stepFound) idealPosition = GetStepTarget(out stepFound, -raycastFocus, mechSpider.raycastDistance * 3f * mechSpider.scale); // Try again with inverted focus
- if (!stepFound) return;
- // If distance to that ideal position is less than the threshold, do nothing
- if (Vector3.Distance(position, idealPosition) < maxOffset * mechSpider.scale * UnityEngine.Random.Range(0.9f, 1.2f)) return;
- // Need to step closer to the ideal position
- StopAllCoroutines();
- StartCoroutine(Step(position, idealPosition));
- }
- // Stepping co-routine
- private IEnumerator Step(Vector3 stepStartPosition, Vector3 targetPosition) {
- stepProgress = 0f;
- // Moving the IK position
- while (stepProgress < 1) {
- stepProgress += Time.deltaTime * stepSpeed;
-
- position = Vector3.Lerp(stepStartPosition, targetPosition, stepProgress);
- position += mechSpider.transform.up * yOffset.Evaluate(stepProgress) * mechSpider.scale;
- lastStepPosition = position;
- yield return null;
- }
- position = targetPosition;
- lastStepPosition = position;
- // Emit sand
- if (sand != null) {
- sand.transform.position = position - mechSpider.transform.up * footHeight * mechSpider.scale;
- sand.Emit(20);
- }
-
- lastStepTime = Time.time;
- }
- }
- }
|