- Home /
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!
Answer by aldonaletto · Jun 22, 2012 at 03:03 AM
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)); } }
Thanks for your contribution Aldo. You have certainly taught me something new. However, it does not fix the core of the problem. As I have tried to explain, the point of this move is that the main character must stop at a precise and consistent location. This way, the player can learn to predict the outcome of using this move. In the Translate equation, if I change the speed variable, the destination also changes.
Well, if you don't need the physics behavior while doing the movement, use Lerp in a coroutine - take a look at my edited answer.
Answer by hackete · Jun 22, 2012 at 11:45 PM
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.
Oh great catch! Not having a program$$anonymous$$g background, sometimes I zone out and forget the most basic things. Like Update running every frame. I have moved oldpos to a place where it will declare only once as he starts the dash kick. Unfortunately, this still doesn't solve the problem as now the main character teleports to the destination ins$$anonymous$$d of dashing smoothly. I have updated the OP to reflect the changes.
Answer by Mizuho · Jun 25, 2012 at 05:31 AM
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);
Your answer
Follow this Question
Related Questions
How do I prevent characters from being able to land on each others heads? 1 Answer
Make an object that moves relative to the touch more natural 0 Answers
Move an object using GetKeyDown gradually 4 Answers
How to move an object along x-axis between two points? 5 Answers
How can I make 2D movement less jerky on a controller, with velocity and such? 0 Answers