Hello! I’m working on a 3D endless runner and I’m having some issues getting consistent and smooth character movement with simple custom physics.
Currently, the main character’s movement is jittery and I assume is because the character movement is being applied through FixedUpdate():
(I’m new to Unity and C#, so this code is a mix of code from a tutorial video (that never addresses these obvious issues in their code) and improvisations I have come up with to fix other minor issues I stumbled upon, so I’m sorry if it is messy and confusing.)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public enum SIDE { Left, Mid, Right }
public class Character : MonoBehaviour
{
public SIDE m_Side = SIDE.Mid;
[HideInInspector]
public bool SwipeLeft, SwipeRight, SwipeUp;
public int JumpState = 0;
//JumpState = 0, false
//JumpState = 1, true
//JumpState = 2, interrupted mid-air
float NewXPos = 0f;
float verticalMovement = 0f;
//Speed at which char travels forward
public float ForwardSpeed = 6;
//Distance char travels to the sides
public float SideStepWidth;
//Speed at which char travels to the sides
public float SideStepSpeed;
//Distance char travels up when jumping
public float JumpForce;
private float SideStepMovement;
public float gravity;
private CharacterController m_char;
// Start is called before the first frame update
void Start()
{
m_char = GetComponent<CharacterController>();
transform.position = Vector3.zero;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.A) | Input.GetKeyDown(KeyCode.LeftArrow))
{
SwipeLeft = true;
}
if (Input.GetKeyDown(KeyCode.D) | Input.GetKeyDown(KeyCode.RightArrow))
{
SwipeRight = true;
}
if (Input.GetKeyDown(KeyCode.W) | Input.GetKeyDown(KeyCode.UpArrow))
{
SwipeUp = true;
}
}
private void FixedUpdate()
{
if (SwipeLeft)
{
NewXPos = NewXPos - SideStepWidth;
if (m_Side == SIDE.Right)
{
m_Side = SIDE.Mid;
}
else
{
m_Side = SIDE.Left;
}
SwipeLeft = false;
}
else if (SwipeRight)
{
NewXPos = NewXPos + SideStepWidth;
if (m_Side == SIDE.Left)
{
m_Side = SIDE.Mid;
}
else
{
m_Side = SIDE.Right;
}
SwipeRight = false;
}
SideStepMovement = Mathf.Lerp(SideStepMovement, NewXPos, Time.deltaTime * SideStepSpeed);
Jump();
Vector3 moveVector = new Vector3(SideStepMovement - transform.position.x, verticalMovement, ForwardSpeed * Time.deltaTime);
m_char.Move(moveVector);
}
void Jump()
{
if (m_char.isGrounded)
{
JumpState = 0;
verticalMovement = -gravity * Time.deltaTime;
if (SwipeUp)
{
SwipeUp = false;
verticalMovement = JumpForce;
JumpState = 1;
}
}
else
{
verticalMovement -= gravity * Time.deltaTime;
}
}
I have tried to put this whole code into Update(), however, that causes a different issue where the character’s jump height becomes inconsistent - specifically, it jumps much higher when testing the game in “Maximize on Play” mode, compared to when the game is running in a small window.
I’ve read that the solution to this inconsistent jump is moving the physics calculation to FixedUpdate(), which brings me back to the start with jittery movement.
Is there a way I can calculate the physics in FixedUpdate() and apply the movement on Update() (I’ve tried it myself with no success), or maybe some other solution for this problem?