I recently made the switch to the unity built in character controller, as it better suited the needs of my project. However, after refactoring my code to work with the character controller I've noticed some irregular behaviour with my jump logic. The character seems jump and once they reach the apex they hang in the air for a few frames longer than they should, resulting in a jump that doesnt follow an arc. Here is a gif to show it in action:
Here is how I calculate my gravity value and jump velocity:
readonly float maxJumpHeight = 10.5f;
readonly float maxJumpTime = .5f;
timeToPeak = maxJumpTime/2;
gravity = (-2 * maxJumpHeight) / Mathf.Pow(timeToPeak,2);
initialJumpVelocity = 2 * maxJumpHeight/timeToPeak;
currentGravity = gravity;
void HandleJump(){
float jumpHeight = 10;
if(_jumpPressed && (_isGrounded) && !_jumping) {
velocity.y = initialJumpVelocity;
_jumping = true;
currentJumps --;
_jumpPressed = false;
_playerSm.jumpDash = false;
//controller.Move(new Vector3(0,velocity.y,0) * Time.deltaTime);
return;
}
else if(_jumpPressed && currentJumps > 0 && _jumping && !_isGrounded){
velocity.y = initialJumpVelocity;
currentJumps --;
_jumpPressed = false;
return;
}
else if((!_jumpPressed && _isGrounded && _jumping) || currentJumps <= 0){
_jumping = false;
}
}
void ApplyGravity(){
bool isFalling = ((velocity.y <= 0.0f) || !_jumpPressed);
float fallMultiplier = 1.0f;
float previousYVelocity = velocity.y;
float nextYvelocity = 0;
float newYVelocity;
if(isFalling){
newYVelocity = velocity.y + currentGravity * fallMultiplier;
nextYvelocity = (previousYVelocity + newYVelocity) * 0.5f;
}
if(!_isGrounded)velocity.y += Mathf.Max(nextYvelocity,-500) * Time.deltaTime; else velocity.y += groundedGravity * Time.deltaTime;
//if (!_isGrounded) velocity.y += currentGravity * Time.deltaTime;
}
//This is my classes update method, it gets run every frame
public void Tick(){
ApplyGravity();
_move = _controls.GroundMove.Move.ReadValue<Vector2>();
currentYSpeed = Vector3.Distance(new Vector3(0,_prevPos.y,0), new Vector3(0, _playerTransform.position.y, 0))/Time.deltaTime;
GroundCheck();
// SlopeCheck();
HandleRotation();
HandleAttack();
if (!lockOnPressed)
{
ApplyRotation();
}
HandleJump();
controller.Move(velocity * Time.deltaTime);
Vector3 currentVelocity = velocity * ( 1 - Time.deltaTime * dragForce);
if (!_isGrounded)
{
velocity = new Vector3(currentVelocity.x, velocity.y, currentVelocity.z);
}
else
{
velocity = currentVelocity;
}
//update the animator on our various attributes
publisher.updateGroundedStatus(_isGrounded);
publisher.updateAimStatus(_aiming);
publisher.updateSpeedStatus(new Vector3(velocity.x,0,velocity.z).magnitude);
publisher.updateYSpeedStatus(velocity.y);
publisher.updateForce(velocity);
publisher.updateVelocity(velocity);
publisher.updateSubmerged(Physics.CheckSphere(_groundCheck.position, 0.25f , _waterLayer));
}
void OnJump(InputAction.CallbackContext context){
Debug.Log("jump performed " + context.performed);
if(currentJumps > 0)
{
_jumpPressed = context.performed;
_playerTransform.parent = null;
if (_jumpPressed && currentJumps > 0)
{
if(_isGrounded)
publisher.updateJumpedStatus(1);
else
publisher.updateJumpedStatus(2);
}
}
}
Its odd as sometimes this code produces a perfect arc and sometimes it doesnt, which leads me to believe it might be an issue with my unity project or something else, if anyone could help or insight I would greatly appreciate it!
_jumpPressed
gets set totrue
then. We can see where it gets set tofalse
, but not the other side, nor whereTick()
gets called, etc. Aim to have a self-contained example in your question, where a reader could paste the code into a new, empty project and have it compile and reproduce the problem. \$\endgroup\$_jumpPressed
is set to true and to clarify the functions, I'm using a state machine soTick()
is myUpdate()
\$\endgroup\$