- Home /
how to make character move smoothly is endless runner game
I am working on an endless runner game, the problem is when I move my character left or right, it teleports to the left or right see:
if (Input.GetKeyDown(KeyCode.RightArrow)) { controller.Move(Vector3.right 200 Time.deltaTime);
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
controller.Move(Vector3.left * 200 * Time.deltaTime);
}
My problem is that the character is teleporting, How do you make the character smoothly move the a designated location the left or right, Please note that I am not want the character to have free rain over there exact position, I want it to have three positions you can be in like normal endless runners.
Answer by cQuence · Jan 28, 2018 at 08:13 PM
Hello, sorry for a bit late response, but it's now that I'm working on a endless runner game for a school project. This could be a bit different approach what you had in mind, but still maybe it will help you.
I'm also posting this for anyone else who is checking the forums that might be having issues with this case and could benefit from my input, since I've looked and found an answer to my problems countless times and I just want to return to community.
I've written this code for moving a character quite smoothish(probably could be even smoother) from point A to B and B to C and vice versa . This code also responds if a player wants to change direction of character when its already moving towards a certain lane. For example he wants to go from lane A to B but while character is moving to B he wants to go back to A. I hope this will help u in any way.
//This is all in Update Function
// I have a 3 lane runner { -1, 0, 1 }, checking so it doesn't gets over that
if (Input.GetKeyDown(moveL) && wantedRow > -1)
{
centeringZero = false;
wantedRow--;
}
if (Input.GetKeyDown(moveR) && wantedRow < 1)
{
centeringZero = false;
wantedRow++;
}
if (wantedRow == -1)
wantedX = -horiDiff;
else if (wantedRow == 0)
wantedX = 0;
else if (wantedRow == 1)
wantedX = horiDiff;
//bool centeringZero is necessary to prevent update of doing a multiple movement changes at once, since update is a bit unpredictable and same thing can be set multiple times. So I find bools quite useful in Update functions.
if (centeringZero)
{
transform.Translate(new Vector3(0, 0, moveSpeed) * Time.deltaTime);
Debug.Log("0, 0, moveSpeed");
}
else if (transform.localPosition.x < wantedX && !centeringZero)
{
transform.Translate(new Vector3(3, 0, moveSpeed) * Time.deltaTime);
Debug.Log("translate 3,0,movespeed");
if (wantedRow == 0)
{
//if statement to check if its close to zero if it is its sets it to zero.
if (transform.localPosition.x >= -0.1f && transform.localPosition.x <= 0.1f && !centeringZero)
{
Vector3 fixX = transform.localPosition;
fixX.x = 0;
transform.localPosition = fixX;
currRow = 0;
centeringZero = true;
Debug.Log("centering 0");
}
}
if(wantedRow == 1)
{
//if statement to check if its close to horiDiff in my case its set to 1.25f and set it to 1.25f
if (transform.localPosition.x < horiDiff && transform.localPosition.x > horiDiff - 0.1f && !centeringZero)
{
Vector3 fixX = transform.localPosition;
fixX.x = horiDiff;
transform.localPosition = fixX;
currRow = 1;
centeringZero = true;
Debug.Log("centering " + horiDiff);
}
}
}
else if(transform.localPosition.x > wantedX && !centeringZero)
{
transform.Translate(new Vector3(-3, 0, moveSpeed) * Time.deltaTime);
Debug.Log("translate -3,0,movespeed");
if (wantedRow == 0)
{
//if statement to check if its close to 0 and sets it to 0
if (transform.localPosition.x >= -0.1f && transform.localPosition.x <= 0.1f && !centeringZero)
{
Vector3 fixX = transform.localPosition;
fixX.x = 0;
transform.localPosition = fixX;
currRow = 0;
centeringZero = true;
Debug.Log("centering " + 0);
}
}
if (wantedRow == -1)
{
//if statement to check if its close to horiDiff in my case its set to 1.25f and set it to 1.25f
if (transform.localPosition.x > -horiDiff && transform.localPosition.x < -horiDiff + 0.1f && !centeringZero)
{
Vector3 fixX = transform.localPosition;
fixX.x = -horiDiff;
transform.localPosition = fixX;
currRow = -1;
centeringZero = true;
Debug.Log("centering " + -horiDiff);
}
}
}
If you want smoother transitions from one lane to another, only thing that could be causing uneven transition is when function fixes character position to its lane. You can play around with if statements where it checks if its close to desired character X position and then set its position.
//try changing this to even closer to horiDiff, perhaps 0.01f - could be better but not sure
if (transform.localPosition.x < horiDiff && transform.localPosition.x > horiDiff - 0.1f && !centeringZero)
{
Vector3 fixX = transform.localPosition;
fixX.x = horiDiff;
transform.localPosition = fixX;
currRow = 1;
centeringZero = true;
Debug.Log("centering " + horiDiff);
}
I've tried to explain the code and logic best as I can, but if there is still anything unclear, please tell me where and I'll try to explain it as best as I can. Again this could be probably done smoother/better and definitely cleaner, but I'm kinda rushing to finish it as fast as I can, since project due is closing in fast, so this will work for me.
Answer by tadejP · Aug 16, 2017 at 08:14 AM
The character is teleporting because you're multiplying by 200. And using a coroutine just seems like a bad idea. Instead of using keys to move the character, use them to change the the target row and make character move to it.
Try this:
using UnityEngine;
public class Derp : MonoBehaviour {
public int[] rows = new int[] { -1, 0, 1 }; // x position of each row
private int targetRow = 0;
private CharacterController charController;
private void Awake () {
charController = GetComponent<CharacterController>();
transform.position = new Vector3(rows[targetRow], 0, 0);
}
void Update () {
if (Input.GetKeyDown(KeyCode.LeftArrow) && targetRow > 0) {
targetRow--;
}
if (Input.GetKeyDown(KeyCode.RightArrow) && targetRow < rows.Length - 1) {
targetRow++;
}
//Move Character Controller towards target row when distance is greater than 0.05
if (Mathf.Abs(transform.position.x - rows[targetRow]) > 0.05f) {
if (transform.position.x < rows[targetRow]) {
charController.Move(Vector3.right * Time.deltaTime);
}
else if (transform.position.x > rows[targetRow]) {
charController.Move(Vector3.left * Time.deltaTime);
}
}
//Lerp transform to position when character controller is close enough
else {
transform.position = Vector3.Lerp(transform.position, new Vector3(rows[targetRow], 0, 0), Time.deltaTime);
}
}
}
Ok, but can you speed up the movement at which the player changes rows?
Well, the question is why did you have to multiply by 200 before, it seems like a lot. Not sure how what your project world scale is. Is it not enough if you use a smaller number? Also, considering you're probably not using Nav$$anonymous$$esh, you could use a kinematic rigidbody ins$$anonymous$$d of CharacterController.
I've changed the code to work with rigidbody if you want to try it:
using UnityEngine;
public class $$anonymous$$ovement : $$anonymous$$onoBehaviour {
public int[] rows = new int[] { -1, 0, 1 }; // x position of each row
private int targetRow = 0;
private Rigidbody rb;
public int speed;
private void Awake () {
rb = GetComponent<Rigidbody>();
transform.position = new Vector3(rows[targetRow], 0, 0);
}
void Update () {
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.LeftArrow) && targetRow > 0) {
targetRow--;
}
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.RightArrow) && targetRow < rows.Length - 1) {
targetRow++;
}
}
void FixedUpdate () {
Vector3 movement = new Vector3(rows[targetRow], 0, 0) - transform.position;
if (movement.magnitude > speed * Time.fixedDeltaTime) {
movement = movement.normalized * speed;
rb.$$anonymous$$ovePosition(transform.position + movement * Time.fixedDeltaTime);
}
else
rb.$$anonymous$$ovePosition(new Vector3(rows[targetRow], 0, 0));
}
}
So are suggesting that the simple fix to changing the speed when changing rows is to scale the world down?
Answer by Destolos · Aug 15, 2017 at 01:35 PM
I don't know if smooth movement is possible with controller.Move. I would use a coroutine:
bool isMovinLeft = false;
void Update ()
{
if (Input.GetKeyDown(KeyCode.LeftArrow) && !isMovinLeft)
{
StartCoroutine(LeftMove());
}
}
IEnumerator LeftMove()
{
for (float f = 0; f < 10; f += 0.1f)
{
GetComponent<CharacterController>().Move(Vector3.left * Time.deltaTime);
yield return null;
}
isMovinLeft = false;
}
That sorta works but I need the player to move in rows, like a real endless runner game, do you know how to do that?
No, sorry. But perhaps this Tutorial will show you, how to do it: https://www.youtube.com/watch?v=7jdL5538bEo&list=PLLH3mUGkfFCXps_IYvtPcE9vcvqmG$$anonymous$$pR$$anonymous$$
I know, I have been using that tutorial for a reference for a while now, the problem is that he the player full control over there movement, but I need $$anonymous$$e to act like a real endless runner game
Your answer
Follow this Question
Related Questions
how do I do a 3 way Lane system 0 Answers
cannot build player while editor is importing assets or compiling scripts 7 Answers
C# Script issue with Player 1 Answer
Collision with mesh updated at runtime 0 Answers
How to make a smooth jump? 2 Answers