private void OffsetFoot(int limbIndex) { //Offsets foot by basically taking half a step FootIKTarget footIKTarget = footIKTargets[limbIndex]; Vector3 referencePosition = stableFeetPositions[limbIndex]; //Decide where to step RaycastHit nextStep; Vector3 raycastOrigin = referencePosition + transform.forward * stepStride / 2 + transform.up * 100; bool foundStep = Physics.Raycast(raycastOrigin, Vector3.down, out nextStep); if (!foundStep) { return; } footIKTarget.position = nextStep.point; BodyControl(); }
private void MoveFoot(int limbIndex, float time) { FootIKTarget footIKTarget = footIKTargets[limbIndex]; // select the foot we are trying to control Vector3 referencePosition = stableFeetPositions[limbIndex]; // get the grounded position of that foot //Decide where to step using raycast RaycastHit nextStep; Vector3 raycastOrigin = referencePosition + transform.forward * stepStride + transform.up * 100; bool foundStep = Physics.Raycast(raycastOrigin, Vector3.down, out nextStep); if (nextStep.point.y - referencePosition.y > maxStepHeight) { raycastOrigin = referencePosition + transform.up * stepStride - transform.forward * 100; foundStep = Physics.Raycast(raycastOrigin, transform.forward, out nextStep); } if (!foundStep) { return; } /****NOTE!!! The rest of this function is just to control the animation. I did a lot of work to get a nice animation which you can AVOID!****/ /***You could just use Vector3.MoveTowards() to move the feet like in the simpler alternative I worte below to save you from a lot of trouble****/ //*** The simpler alternative code *** P.S. I didn't design the system for this, so the animation looks a bit weird, but technically, it works! //if (time > 0) //{ // if (time < 0.1f) // { // footIKTarget.position = referencePosition + Vector3.up * 0.2f; // } // else // { // footIKTarget.position = Vector3.MoveTowards(footIKTarget.position, nextStep.point, Time.deltaTime * 5); // if (time == 1) footIKTarget.position = nextStep.point; // } //} //*** The more complex but better looking animation code ***/// //Obtain the non-animated world step Vector3 worldStepVector = nextStep.point - referencePosition; float horizontalStepMagnitude = new Vector2(worldStepVector.x, worldStepVector.z).magnitude; //Convert world step vector to a local step vector with local forward direction as reference forward direction float stepAngleOffset = Vector2.SignedAngle(new Vector2(worldStepVector.x, worldStepVector.z), new Vector2(transform.forward.x, transform.forward.z)); Vector3 localStepVector = new Vector3(Mathf.Sin(stepAngleOffset * Mathf.Deg2Rad) * horizontalStepMagnitude, worldStepVector.y, Mathf.Cos(stepAngleOffset * Mathf.Deg2Rad) * horizontalStepMagnitude); //Sample animation curves taking note of the limb side. *The animation curves are designed with the world forward direction as reference forward direction int sideSign = footIKTarget.limbSide == LimbSide.Left ? 1 : -1; Vector3 stepProgress = new Vector3(stepCurveX.Evaluate(time) * sideSign, stepCurveY.Evaluate(time), stepCurveZ.Evaluate(time)); Vector3 stepOffset = new Vector3(stepOffsetCurveX.Evaluate(time) * sideSign, stepOffsetCurveY.Evaluate(time), stepOffsetCurveZ.Evaluate(time)); // The commented out code below simply enables the step spheres and lines you see in the video //if (stepProgress.magnitude > 1.5f) //{ //debugLine.SetPosition(0, raycastOrigin); //debugLine.SetPosition(1, nextStep.point); //debugSphere[0].gameObject.SetActive(true); //debugSphere[0].position = nextStep.point; //} //if (t == 0 || t == 1) //{ // debugSphere[limbIndex].gameObject.SetActive(true); // debugSphere[limbIndex].position = footIKTargets[limbIndex].position; //} //compute the animated step vector from the local step vector Vector3 animatedLocalStepVector = Vector3.Scale(localStepVector, stepProgress) + stepOffset; float animatedHorizontalStepMagnitude = new Vector2(animatedLocalStepVector.x, animatedLocalStepVector.z).magnitude; float animationAngleOffset = Vector2.SignedAngle(new Vector2(animatedLocalStepVector.x, animatedLocalStepVector.z), new Vector2(localStepVector.x, localStepVector.z)); //Obtain the angle between the world forward direction and the local forward direction float forwardAngleOffset = Vector2.SignedAngle(new Vector2(transform.forward.x, transform.forward.z), Vector2.up); float totalAngleOffset = stepAngleOffset + animationAngleOffset + forwardAngleOffset; Vector3 animatedWorldStepVector = new Vector3(Mathf.Sin(totalAngleOffset * Mathf.Deg2Rad) * animatedHorizontalStepMagnitude, animatedLocalStepVector.y, Mathf.Cos(totalAngleOffset * Mathf.Deg2Rad) * animatedHorizontalStepMagnitude); footIKTarget.position = referencePosition + animatedWorldStepVector; BodyControl(); }