Changing speed without changing Destination

Hello all,

I am making a 2D action/beat-em-up game and having a bit of trouble with the air movement scripts. I already have all the appropriate physics systems in place to ensure gravity, jumping etc.

Right now, I am attempting to make an air dragon-kick type move that will propel the player forward by a set amount while killing all enemies he passes through. The input for this move is: Direction you want to kick (left or right) + heavy attack button.

Let me very very clear about this: I am not having trouble making him move. I am having trouble making him stop at the right place. I only want him to move a certain amount of units away from his starting position. As an example, let’s say 5 ft or something. He should only fly forward 5 ft worth of Vector units and STOP.

I’ve used Rigidbody.velocity to move stuff a fair bit. But I don’t want to mess with it in this case, as there are already a bunch of things in the game that alter your velocity. I want to keep velocity as a purely physics controller, hence, away from input stuff.

I have tried both transform.translate and Vector3.Lerp. I cannot seem to increase the speed of the move without either making him teleport directly to the destination or the destination changing. Here is what I am currently using:

Getting the input:

if (Input.GetAxis("Horizontal") > 0 && !doingheavy)
					{
						gravity = 0;
						if (linkwindow)
							StartCoroutine ( quickright () );
						else
							StartCoroutine ( heavyright () );
					}

The Kick animation

IEnumerator heavyright()
	{
        oldpos = transform.position;
		animating = true;
		doingheavy = true;
		StartCoroutine( kickright () );
		
		yield return new WaitForSeconds(1f);
		
		gravity = -0.7f;
		rightkick = false;
		animating = false;
		
	}

Finally, here is the part I am having trouble with:

if (animating && rightkick)
		{
			transform.position = Vector3.Lerp(oldpos,
		new Vector3(oldpos.x + 4, oldpos.y + 1, oldpos.z), Time.deltaTime * 4);
		
		}

The only problem with the above one is that teleports him to the destination point. I have tried changing the time.deltatime multiplier to all different types of values but there doesn’t seem to be something that smooths out the movement the way transform.translate does. I have also tried using transform.Translate:

if (animating && leftkick)
			{
				transform.Translate(new Vector3(-200, 0, 0) * Time.deltaTime, Space.World);
			}

And another variation of translate:

if (animating && leftkick)
    			{
    				transform.Translate(40 * new Vector3(-1, 0, 0) * Time.deltaTime, Space.World);
    			}

As I have said, when the multiplier or the Vector3 x value are manipulated in translate, it changes both the speed and distance traveled. I just want to make a move that looks very fast, but does not travel a huge distance. Lerp gets the destination point right, but it fails at producing smooth movement. Translate fails at stopping at the right destination point but it is smooth.

Am I on the right track? Perhaps I should add a condition that makes him stop? Any tips would be appreciated!

If the object is a rigidbody, you should not move its transform directly - this may confuse the collision detection system. You should use AddForce instead, like this:

  // apply the force each time the button is pressed:
  if (Input.GetButtonDown("HeavyAttackButton")){ 
    // apply the force in the object's forward direction:
    rigidbody.AddForce(transform.forward * force, ForceMode.Impulse);
  }

This code accelerates the rigidbody as if a force force was applied during one second - supposing rigidbody.mass = 1 and force = 10, for instance, the rigidbody velocity would be instantly increased in its forward direction by force/mass meters/second - 10m/s, in this case.

But if you really want to move the object’s transform, use Translate in Update or FixedUpdate:

var speed: float = 20;

function Update(){
  // apply the velocity "speed" while the button is held pressed:
  if (Input.GetButton("HeavyAttackButton")){
    // the velocity "speed" is in the object's forward direction
    transform.Translate(speed * Vector3.forward * Time.deltaTime);
  }
}

EDITED: Ok, if you want to precisely go from one point to another at constant speed, Lerp in a coroutine is what you need (in C#):

public Vector3 offset = new Vector3(4, 1, 0); // define the offset in the Inspector
public float duration = 0.5f; // duration in seconds
bool moving = false; // helps avoiding a new kick while the previous hasn't finished

IEnumerator DragonKick(Vector3 offset){
  moving = true; // movement started - don't start another movement!
  Vector3 org = transform.position; // define origin...
  Vector3 dest = org+offset; // and destination
  float t = 0;
  while (t < 1){
    // t moves towards 1 in duration seconds
    t += Time.deltaTime/duration;
    // move in direction to dest according to t
    transform.position = Vector3.Lerp(org, dest, t);
    yield; // return to the loop next frame
  }
  moving = false; // movement ended
}
  ...
  // when doing the movement:
  if (animating && !moving){ // don't start another kick while the current one is running
    if (rightKick){
      StartCoroutine(DragonKick(offset));
    }
    if (leftKick){
      StartCoroutine(DragonKick(-offset));
    }
  }

Ignoring the physics stuff, it is your code that keeps changing the destination. Remember that
this code gets run many times. On each update you are changing the position, then using the
changed position as the origin in the next update. You need to save the original position at the start of the move and use the saved position in your Lerp.

If we just need to move to a destination:

protected Vector3 destination = Vector3.zero;

void Update() {
    if(this.animating && this.rightkick) {
        Vector3 oldPosition = this.transform.position;
        // Multiply Time.deltaTime by a factor to increase speed (divide to decrease)
        Vector3 change = (this.transform.position - this.destination) * Time.deltaTime;
        Vector3 position = this.transform.position + change;
        if(oldPosition.x != position.x && oldPosition.x < position.x && this.destination.x < position.x
        || oldPosition.y != position.y && oldPosition.y < position.y && this.destination.y < position.y
        || oldPosition.z != position.z && oldPosition.z < position.z && this.destination.z < position.z) {
            position = = this.destination;
            this.animating = false;
        }
        this.transform.position = position;
    }
}

// Somewhere else in code, probably where you set animating or rightkick to true
this.destination = this.transform.position + new Vector3(4, 1, 0);