Home > Net >  Why does this not move properly the object?
Why does this not move properly the object?

Time:06-21

Create a new project, add a sphere, a rigidbody and add this small script. Then add 2 points in the points list. This script does nothing but moving the object each points of the list.

using System;
using UnityEngine;

public class MoveAlongPath : MonoBehaviour
{
    public Vector3[] points;
    public float speed = 1.0f;

    public float minDistance = Vector3.kEpsilon;

    [SerializeField] private Vector3 _posCurrent;
    [SerializeField] private Vector3 _posNext;
    [SerializeField] private Vector3 _newPos;
    [SerializeField] private int _currentIndex;
    [SerializeField] private Vector3 _rotate;
    [SerializeField] private Vector3 _oldPosition;
    [SerializeField] private Rigidbody _rigidbody;

    private void NextPoint()
    {
        _posCurrent = points[_currentIndex];
        transform.position = _posCurrent;
        _currentIndex  ;
        if (_currentIndex == points.Length) {
            _currentIndex = 0;
        }
        _posNext = points[_currentIndex];
    }

    private void Start()
    {
        _rigidbody = GetComponent<Rigidbody>();
        NextPoint();
    }

    private void FixedUpdate()
    {
        Transform t = transform;
        _oldPosition = t.position;

        float singleStep = speed * Time.fixedDeltaTime;
        
        _newPos = new Vector3(
            _oldPosition.x   singleStep,
            _oldPosition.y   singleStep,
            _oldPosition.z   singleStep
        );
        _rigidbody.MovePosition(_newPos);

        if (Vector3.Distance(_newPos, _posNext) <= minDistance) {
            /* close enough -> next point: */
            NextPoint();
        }
    }
}

Well... it doesn't work. I've tried many ways:

  • using Update() instead of FixedUpdate() - but AFAIK Update() should only handle inputs and FixedUpdate() should make actual 3D physics computation
  • using transform.position = _newPos; doesn't work, and MovePosition() doesn't work too...

I'm stuck!

CodePudding user response:

You're not moving in a meaningful direction, you're just moving 1 unit per second on each axis.

Try

var direction = _posNext - _posCurrent;

This is the direction, but if you moved that vector you'd be there in one tick. What you want is the normalized unit vector, which has a magnitude of 1, then you can multiply your speed by that.

I'm writing this on a cell phone so I may not have the methods exact:

var singleStep = speed * Time.fixedDeltaTime * direction.normalized;

And now you want to take the SMALLER of your direction or singleStep. It's extremely likely that your singleStep would overshoot the target, and you'll know you're going to overshoot because the singleStep is a bigger step than just going to the target.

if(singleStep.magnitude > direction.magnitude) 
{
    singleStep = direction; // don't overshoot
} 

Then you can move and that should get it :)

_newPos = _oldPosition   singleStep;
_rigidbody.MovePosition(_newPos);

Edited by OP: here's the full code of the working solution, thanks again!

using UnityEngine;

public class MoveAlongPath : MonoBehaviour
{
    public Vector3[] points;
    public float speed = 1.0f;
    public float minDistance = Vector3.kEpsilon;
    private SphereCollider _c;
    [SerializeField] private Vector3 _posStart;
    [SerializeField] private Vector3 _posEnd;
    [SerializeField] private int _currentIndex;
    [SerializeField] private Rigidbody _rigidbody;
    [SerializeField] private Vector3 _direction;

    private void NextPoint()
    {
        _posStart = points[_currentIndex];
        transform.position = _posStart;
        _currentIndex =   _currentIndex % points.Length;
        _posEnd = points[_currentIndex];
        _direction = _posEnd - _posStart;
        _direction = _direction.normalized;
        Debug.Log("Going from " _posStart " -> to -> " _posEnd);
    }

    private void Start()
    {
        _rigidbody = GetComponent<Rigidbody>();
        NextPoint();
    }

    private void FixedUpdate()
    {
        Vector3 step = speed * Time.fixedDeltaTime * _direction.normalized;
        if(step.magnitude > _direction.magnitude) {
            step = _direction; // don't overshoot
        } 
        Vector3 newPos = transform.position   step;
        _rigidbody.MovePosition(newPos);
        if (Vector3.Distance(_posEnd, transform.position) < minDistance) {
            /* close enough -> next point: */
            NextPoint();
        }
    }
}
  • Related