1
\$\begingroup\$

I need to make realistic human movement (3D) using mouse click.

  1. Get mouse click point using Raycast.
  2. Smoothly Slerp to LookRotation.
  3. Move transform.forward.

Everything works fine, except I have problem with circular movement (close radius).

  1. Example If dont move transform.forward while Slerp to LookRotation or MoveTowards instead of transform.forward it will be spinning like whirligig on circular movement.

  2. Example If do move transform.forward while while Slerp to LookRotation it will distort trajectory of straight direct movement.

Is there any solution to move circular realistic (not spin like whirligig) and move straight direct when needed (not distort trajectory)?

I need straight movement from first example and circular movement from second.

        if (Input.GetMouseButtonDown(1))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            RaycastHit[] hits = Physics.RaycastAll(ray);

            foreach (RaycastHit hit in hits)
            {
                if (hit.transform.tag == "Ground")
                {
                    DestinationPosition = new Vector3(hit.point.x, transform.position.y, hit.point.z);

                    DestinationRotation = Quaternion.LookRotation(DestinationPosition - transform.position);

                    break;
                }
            }
        }

        if (Vector3.Distance(transform.position, DestinationPosition) > 1)
        {
            transform.rotation = Quaternion.Slerp(transform.rotation, DestinationRotation, RotationSpeed * Time.deltaTime);

            transform.position += transform.forward * MovementSpeed * Time.deltaTime;

            //transform.position = Vector3.MoveTowards(transform.position, DestinationPosition, MovementSpeed * Time.deltaTime);

            animation.CrossFade("run");
        }
        else
        {
            animation.CrossFade("idle");
        }
\$\endgroup\$
7
  • \$\begingroup\$ Perhaps you should only move forward when you're actually facing the destination? I'd imagine Quaternion.Slerp isn't rotating you all the way to the destination in one frame, and then you are moving foward regardless. Try replacing transform.forward with ( destinationPosition - transform.position ).normalized in the last line. That will move you towards the destination whether or not you're facing it. \$\endgroup\$
    – Ben
    Oct 6, 2014 at 19:05
  • \$\begingroup\$ I realize that I can move towards destination whether or not I'm facing it using Vector3.MoveTowards (which should be equivalent of (DestinationPosition - transform.position).normalized) instead of transform.towards, but that make circular movement look unnatural (spinning like whirligig). \$\endgroup\$
    – Demion
    Oct 6, 2014 at 19:10
  • \$\begingroup\$ Then why not wait until it's fully rotated before starting to move forward? \$\endgroup\$
    – Ben
    Oct 6, 2014 at 19:14
  • \$\begingroup\$ How natural is staying on same spot and rotating? When moving circular we need move using arc trajectory (which is achieved moving and rotating at same time). But when turn around we need keep linear trajectory. \$\endgroup\$
    – Demion
    Oct 6, 2014 at 19:21
  • \$\begingroup\$ Well you haven't exactly provided any context into what you're actually moving. All I can gather from your post is it's obviously not a "whirligig". \$\endgroup\$
    – Ben
    Oct 6, 2014 at 19:26

1 Answer 1

2
\$\begingroup\$

When facing this problem I found that I wanted the character to move forward at a velocity roughly proportional to how close they are to facing the target.

When facing away from our target we "turn on the spot" (Red), when facing directly towards it we walk straight towards it (Green), when somewhere in between we will may walk slowly while turning (Blue & Purple).

enter image description here

How best to implement this, and the values to use for thresholds, will depend on the other systems already in place.

One approach with Unity that would allow for easy fine tuning would be to use an AnimationCurve.

public AnimationCurve speedAngleCurve;
public float maxSpeed;

private float getTargetSpeed(Vector3 targetPosition) {
    Vector3 targetDirection = targetPosition - transform.position;
    float offsetAngle = Vector3.Angle(transform.forward, targetDirection);
    float normalizedAngle = offsetAngle / 180.0f;
    return speedAngleCurve.Evaluate(normalizedAngle) * maxSpeed;
}

This would allow a developer to rapidly modify behaviour using the Inspector and the Curve Editor.

enter image description here

\$\endgroup\$
2
  • \$\begingroup\$ Movement direction would be always transform.forward? \$\endgroup\$
    – Demion
    Oct 7, 2014 at 23:40
  • \$\begingroup\$ Yeah, this sample is treating forward as the facing/movement direction. It is just a quick example of one method to map the facing/target relationship to a movement speed. Any real implementation will need fleshing out to consider turning, acceleration, animation, applying movement etc. \$\endgroup\$ Oct 8, 2014 at 9:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .