Hi everyone, I am working on my first game (a first-person shooter). I’ve got my grounded movement feeling pretty good, but I’m having trouble implementing air control. Does anyone have suggestions to complete my script below (in HandleMovement, the “else” block)?
I’ve listed my requirements in the comments of the script, but for clarification: by “relatively slow” I mean slower than ground control, and by “soft limit” I mean that the air control should not push the player past a max speed, but if the player broke that speed by rocket jumping or some other means I don’t want to take speed away from them.
Thanks in advance!
using System.Collections;
using System.Collections.Generic;
using UnityEngine.InputSystem;
using UnityEngine;
public class SC_FPSController : MonoBehaviour
{
public Camera camera;
private Rigidbody rigidbody;
private CharacterStats characterStats;
private bool isGrounded;
private Vector2 rawMovementVector;
private const float JUMP_FORCE = 10f;
// This raycast length is calculated as half of the character's box collider. This will allow jumping from slopes up to 45 degrees.
private const float JUMP_RAYCAST_LENGTH = 0.5f;
private void Start()
{
characterStats.speed = 40f;
characterStats.airControlSpeed = characterStats.speed/2;
rigidbody = GetComponent<Rigidbody>();
}
private void Update()
{
UpdateIsGrounded();
HandleMovement();
}
private void OnMove(InputValue value)
{
rawMovementVector = value.Get<Vector2>();
}
private void OnJump()
{
if (isGrounded)
rigidbody.AddForce(0, JUMP_FORCE, 0, ForceMode.Impulse);
}
// Get the "forward" vector for movement purposes. In most cases, the is the direction that the camera is facing.
private Vector3 GetCameraForward()
{
// if the camera is pointing straight up, then "down" for the camera is forward
if (camera.transform.forward.normalized.y == 1)
return -1 * camera.transform.up;
// if the camera is pointing straight down, then "up" for the camera is forward
else if (camera.transform.forward.normalized.y == -1)
return camera.transform.up;
// Typical case, return the camera's forward vector
return camera.transform.forward;
}
private void HandleMovement()
{
// Figure out which way the camera is facing in the XZ plane
Vector3 forward = GetCameraForward();
forward.y = 0;
forward.Normalize();
Vector3 right = camera.transform.right;
right.y = 0;
right.Normalize();
Vector3 forceNormal = forward * rawMovementVector.y + right * rawMovementVector.x;
// Update character position based on movement input
if (isGrounded)
{
// Handle input acceleration
rigidbody.AddForce(forceNormal * characterStats.speed, ForceMode.Acceleration);
// Handle friction
rigidbody.AddForce(-1 * rigidbody.velocity, ForceMode.Acceleration);
}
else
{
// Implement air control:
// - relatively slow change in lateral velocity
// - soft limit on lateral velocity
// - no effect on vertical velocity
// - no input = no change to lateral velocity
}
}
private Vector3 PositionOfCharacterFeet()
{
return transform.position - new Vector3(0, transform.lossyScale.y / 2, 0);
}
private void UpdateIsGrounded()
{
isGrounded = false;
if (Physics.Raycast(PositionOfCharacterFeet(), new Vector3(0, -1, 0), JUMP_RAYCAST_LENGTH))
isGrounded = true;
}
public struct CharacterStats
{
public float speed;
public float airControlSpeed;
}
}