- Home /
Lerping from one position to another in a specific amount of time, no matter the distance
I'm playing around with a top down thingy where I want my character to control in a very specific way. The idea is that once I indicate a direction, the character starts moving in that direction until it hits a wall.
My approach is: Have it shoot out a ray and note the hit point where it collides with an object that I've tagged as "wall".
Once it hits a wall, it starts lerping towards that hit point.
My problem is, I seem to be missing something about how lerping works and I can't seem to wrap my head around the logic. It will only lerp part of the way instead of lerping smoothly all the way.
Here's my code:
public class PlayerController : MonoBehaviour {
public float speed = 30f;
public float rotateSpeed = 15f;
//Creating an enum to store my directional constants. I really need to learn about enums because I don't know what I'm doing exactly.
enum Direction{North, NorthEast, East, SouthEast, South, SouthWest, West, NorthWest};
private Direction playerDir;
private string direction; //A number based on hDirection and vDirection to let me set rotation to a single number
private Vector3 fromPosition;
private Vector3 targetPosition;
private bool moving;
private float moveCool;
private float nextMove;
RaycastHit hit; //Okay, so I create a Ray called "hit"
void Start ()
{
playerDir = Direction.North;
moving = false;
moveCool = 0.5f;
}
void FixedUpdate ()
{
float moveHorizontal = Input.GetAxisRaw ("Horizontal");
float moveVertical = Input.GetAxisRaw ("Vertical");
//Detect input and start rotating the player if there is movement input
if (moving == false)
{
if (moveHorizontal == 0 && moveVertical == 1)
{
playerDir = Direction.North;
moving = true;
Rotation (playerDir);
}
else if (moveHorizontal == 1 && moveVertical == 1)
{
playerDir = Direction.NorthEast;
moving = true;
Rotation (playerDir);
}
else if (moveHorizontal == 1 && moveVertical == 0)
{
playerDir = Direction.East;
moving = true;
Rotation (playerDir);
}
else if (moveHorizontal == 1 && moveVertical == -1)
{
playerDir = Direction.SouthEast;
moving = true;
Rotation (playerDir);
}
else if (moveHorizontal == 0 && moveVertical == -1)
{
playerDir = Direction.South;
moving = true;
Rotation (playerDir);
}
else if (moveHorizontal == -1 && moveVertical == -1)
{
playerDir = Direction.SouthWest;
moving = true;
Rotation (playerDir);
}
else if (moveHorizontal == -1 && moveVertical == 0)
{
playerDir = Direction.West;
moving = true;
Rotation (playerDir);
}
else if (moveHorizontal == -1 && moveVertical == 1)
{
playerDir = Direction.NorthWest;
moving = true;
Rotation (playerDir);
}
}
if (moving == true)
{
if (Time.time > nextMove)
{
moving = false;
Debug.Log (moving);
}
}
}
void Movement ()
{
nextMove = Time.time + moveCool;
nextMove = Time.time + moveCool;
//I shoot the ray forward (this will always be after I have rotated, so that's fine) and let it continue until it hits something.
//Maybe read up on "out hit" at some point. You don't know what you did there.
if (Physics.Raycast(transform.position, transform.forward, out hit))
{
//okay so when it hits something, it's gonna set the update fromPosition with the player's current position and then use the impact point from the ray
//as the value in targetPosition. So far so good.
print (hit.point);
fromPosition = transform.position;
targetPosition = hit.point;
}
transform.position = Vector3.Lerp (fromPosition,targetPosition,Time.deltaTime * speed);
}
void Rotation (Direction playerDir)
{
//switch statement - checks against multiple cases of a single variable (playerDir in this case) and takes actions based on different values of the variable.
switch((Direction)playerDir)
{
case Direction.North:
transform.eulerAngles = new Vector3(0f,0f,0f);
Debug.Log (playerDir);
Movement();
break;
case Direction.NorthEast:
transform.eulerAngles = new Vector3(0f,45f,0f);
Debug.Log (playerDir);
Movement();
break;
case Direction.East:
transform.eulerAngles = new Vector3(0f,90f,0f);
Debug.Log (playerDir);
Movement();
break;
case Direction.SouthEast:
transform.eulerAngles = new Vector3(0f,135f,0f);
Debug.Log (playerDir);
Movement();
break;
case Direction.South:
transform.eulerAngles = new Vector3(0f,180f,0f);
Debug.Log (playerDir);
Movement();
break;
case Direction.SouthWest:
transform.eulerAngles = new Vector3(0f,225f,0f);
Debug.Log (playerDir);
Movement();
break;
case Direction.West:
transform.eulerAngles = new Vector3(0f,270f,0f);
Debug.Log (playerDir);
Movement();
break;
case Direction.NorthWest:
transform.eulerAngles = new Vector3(0f,315f,0f);
Debug.Log (playerDir);
Movement();
break;
}
}
Also, I am very much a newbie at this, so feel free to also point out any redundancies or sub optimal practices. :) Thanks
Without looking into that (sorry, is a lot), I would recommend to use $$anonymous$$oveTowards. It'll work more like you'd expect. Pass in player position, target position and the amount it shall go. Done
Thank you, $$anonymous$$oveTowards makes more sense for my game. I still have the same problem, however. Sorry about the wall of code, I can try to highlight the most important part here:
So, whenever the game gets any directional input it calls my movement function:
void $$anonymous$$ovement ()
{
fromPosition = transform.position;
if (Physics.Raycast(transform.position, transform.forward, out hit))
{
targetPosition = hit.point;
}
moving = true;
}
Then, in FixedUpdate() I do this:
if (moving)
{
transform.position = Vector3.$$anonymous$$oveTowards(fromPosition,targetPosition,Time.deltaTime * speed);
if (transform.position == targetPosition)
{
moving = false;
}
}
The problem is that my guy only moves for one frame! I have no idea why it just stops. I tried to make it print out my "moving", "fromPosition" and "targetPosition" variables to see if that was the problem, but it see$$anonymous$$gly isn't.
At first look I can not answer why it only moves for one frame, but what you must change is the line :
if (transform.position == targetPosition)
because the chances of it being exactly the same can be very small. Rather do this :
if((targetPosition - transform.position).magnitude < 0.1f)
{
moving = false;
}
The major problem with the code
transform.position = Vector3.$$anonymous$$oveTowards(fromPosition,targetPosition,Time.deltaTime * speed);
is that you don't seem to change the value of fromPosition. That means that Vector3.$$anonymous$$oveTowards will return roughly the same value. If you are using Vector3.$$anonymous$$oveTowards you don't even need to store the original position and can just use the current position. Try using the following
transform.position = Vector3.$$anonymous$$oveTowards(transform.position,targetPosition,Time.deltaTime* speed);
Your answer
Follow this Question
Related Questions
Smooth Camera/Object Movement 1 Answer
Input.GetAxis not being called every called every frame 1 Answer
Make Lerp or other more fluid or continuous 3 Answers
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
How do I smooth the movement of three transforms moving at different rates along a single axis? 2 Answers