Hi there,
I’m working on some first person movement code which is based on the Quake 3 source code, which was ported by ‘Zinglish’ here: quake3-movement-unity3d/CPMPlayer.cs at master · WiggleWizard/quake3-movement-unity3d · GitHub
The issue I’m having with my script, is that the player accelerates whilst in the air but if the player hits a wall or object and slows down even so they are not moving except jumping, the previous speed they were travelling before hitting the object is retained, which is unwanted. I want the player to slow down when hitting objects.
Here is the relevant code:
void Update()
{
/* Movement */
QueueJump();
if (characterController.isGrounded)
GroundMove();
if (!characterController.isGrounded)
AirMove();
// Move the player
characterController.Move(playerVelocity * Time.deltaTime);
}
/* Sets the direction based on player input */
private void SetMovementDirection()
{
commands.forwardMove = Input.GetAxisRaw("Vertical");
commands.sideMove = Input.GetAxisRaw("Horizontal");
}
/* If the jump key is pressed while in the air, the player will jump instantly when they hit the ground */
private void QueueJump()
{
if (Input.GetButton("Jump") && !queueJump)
queueJump = true;
if (Input.GetButtonUp("Jump"))
queueJump = false;
}
/* Returns the scale factor to apply to the movement direction */
private float MovementScale()
{
int Maximum;
float Total;
float Scale;
Maximum = (int)Mathf.Abs(commands.forwardMove);
if (Mathf.Abs(commands.sideMove) > Maximum)
Maximum = (int)Mathf.Abs(commands.sideMove);
if (Maximum <= 0)
return 0;
Total = Mathf.Sqrt(commands.forwardMove * commands.forwardMove + commands.sideMove * commands.sideMove);
Scale = movementSpeed * Maximum / (moveScale * Total);
return Scale;
}
private void Accelerate(Vector3 Direction, float Speed, float Acceleration)
{
float AddSpeed;
float AccelerationSpeed;
float CurrentSpeed;
// Stop the player exceeding the speed cap
if (Speed >= playerVelocityCap)
return;
CurrentSpeed = Vector3.Dot(playerVelocity, Direction);
AddSpeed = Speed - CurrentSpeed;
if (AddSpeed <= 0)
return;
AccelerationSpeed = Acceleration * Time.deltaTime * Speed;
if (AccelerationSpeed > AddSpeed)
AccelerationSpeed = AddSpeed;
playerVelocity.x += AccelerationSpeed * Direction.x;
playerVelocity.z += AccelerationSpeed * Direction.z;
}
// This function is called when the player is the on the ground
private void GroundMove()
{
Vector3 Direction;
// If a jump is queued, don't apply friction
if (!queueJump)
ApplyFriction(1f);
else
ApplyFriction(0);
Direction = new Vector3(commands.sideMove, 0, commands.forwardMove);
Direction = transform.TransformDirection(Direction);
moveDirectionNorm = Direction;
var Speed = Direction.magnitude;
Speed *= movementSpeed;
Accelerate(Direction, Speed, runAcceleration);
// Reset gravity velocity
playerVelocity.y = 0;
if (queueJump)
{
playerVelocity.y = jumpSpeed;
PlayJumpSound();
queueJump = false;
landSoundPlayed = false;
}
}
private void AirMove()
{
Vector3 Direction;
float Acceleration;
float Scale = MovementScale();
SetMovementDirection();
// Multiplier applied to the sidemove command to serverly reduce strafing while in the air
Direction = new Vector3(commands.sideMove * airStrafeSpeed, 0, commands.forwardMove);
Direction = transform.TransformDirection(Direction);
float Speed = Direction.magnitude;
Speed *= movementSpeed;
Direction.Normalize();
moveDirectionNorm = Direction;
Speed *= Scale;
/* Air control */
float AirSpeed = Speed;
if (Vector3.Dot(playerVelocity, Direction) < 0f)
Acceleration = airDecceleration;
else
Acceleration = airAcceleration;
// If the player is ONLY strafing left or right
if (commands.forwardMove == 0 && commands.sideMove != 0)
{
if (Speed > airStrafeSpeedGen)
Speed = airStrafeSpeedGen;
Acceleration = airStrafeAcceleration;
}
Accelerate(Direction, Speed, Acceleration);
if (airControlPresicion > 0)
AirControl(Direction, AirSpeed);
// Apply gravity
playerVelocity.y -= gravity * Time.deltaTime;
// If the player jumps or they are falling, the landing sound will play when they hit the ground
if (playerVelocity.y > 1 || playerVelocity.y < -1)
landSoundPlayed = false;
}
private void AirControl(Vector3 Direction, float AirSpeed)
{
float ZSpeed;
float Speed;
float Dot;
float K;
// Air control only works when moving forward or backwards
if (Mathf.Abs(commands.forwardMove) < 0.001 || Mathf.Abs(AirSpeed) < 0.001)
return;
// Air control stops working if a strafe key is pressed
if (Mathf.Abs(commands.sideMove) > 0)
return;
ZSpeed = playerVelocity.y;
playerVelocity.y = 0;
Speed = playerVelocity.magnitude;
playerVelocity.Normalize();
Dot = Vector3.Dot(playerVelocity, Direction);
K = 32;
K *= airControlPresicion * Dot * Dot * Time.deltaTime;
// Change direction while slowing down
if (Dot > 0)
{
playerVelocity.x = playerVelocity.x * Speed + Direction.x * K;
playerVelocity.y = playerVelocity.y * Speed + Direction.y * K;
playerVelocity.z = playerVelocity.z * Speed + Direction.z * K;
playerVelocity.Normalize();
moveDirectionNorm = playerVelocity;
}
playerVelocity.x *= Speed;
playerVelocity.y = ZSpeed;
playerVelocity.z *= Speed;
}
There must be some issue in the code which is making the player retain their speed even after slowing down, but I have tried for days to fix this issue with no results, I’m quite desperate now! Please help. Thanks in advance!