I’m currently using Unity as my game engine and have been trying to add footsteps in to my script. I’ve been trying to follow this tutorial by Comp-3 Interactive on footsteps but whenever I run my game, the footsteps clip would be very delayed, play multiple times, and even continue while I was not walking or pressing any of the movement keys.
I suspect that the problem may lie in the footStepTimer but I currently am unable to understand how to fix it. The problem may also lie in the fact that my base movement system is slightly different to the way Comp-3 Interactive programmed his own. I have followed most of his tutorials just fine but I am now stuck on this one. So, if anyone could give any insight on to my problem, that would be greatly appreciated. Thx. (I got rid of some of the functions for this questions)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using Random = UnityEngine.Random;
using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3;
public class PlayerMovement : MonoBehaviour
{
[SerializeField] private CharacterController characterController;
[SerializeField] private Camera mainCamera;
[Header("Functional Options/Bools")]
[SerializeField] private bool canSprint = true;
[SerializeField] private bool canJump = true;
[SerializeField] private bool canCrouch = true;
[SerializeField] private bool canUseHeadbob = true;
[SerializeField] private bool canInteract = true;
[SerializeField] private bool useFootsteps = true;
[Header("Temp Controls")]
[SerializeField] private KeyCode sprintKey = KeyCode.LeftShift;
[SerializeField] private KeyCode jumpKey = KeyCode.Space;
[SerializeField] private KeyCode crouchKey = KeyCode.LeftControl;
[SerializeField] private KeyCode interactKey = KeyCode.E;
[Header("Movement Parameters")]
[SerializeField] private float walkSpeed = 4f;
[SerializeField] private float sprintSpeed = 8f;
[SerializeField] private float crouchSpeed = 2.5f;
private bool isSprinting => canSprint && Input.GetKey(sprintKey);
[Header("Jump Parameters")]
[SerializeField] private float gravity = -18f;
[SerializeField] private float jumpHeight = 1.2f;
private bool shouldJump => Input.GetKeyDown(jumpKey) && characterController.isGrounded;
[Header("Crouch Parameters")]
[SerializeField] private float crouchHeight = 0.5f;
[SerializeField] private float standingHeight = 2.0f;
[SerializeField] private float timeToCrouch = 0.25f;
[SerializeField] private Vector3 crouchingCenter = new Vector3(0, 0.5f, 0);
[SerializeField] private Vector3 standingCenter = new Vector3(0, 1, 0);
private bool isCrouching = false;
private bool inCrouchingAnimation = false;
private bool shouldCrouch => canCrouch && Input.GetKeyDown(crouchKey);
[Header("Headbob Parameters")]
[SerializeField] private float walkBobSpeed = 14.0f;
[SerializeField] private float walkBobAmount = 0.05f;
[SerializeField] private float sprintBobSpeed = 18.0f;
[SerializeField] private float sprintBobAmount = 0.11f;
[SerializeField] private float crouchBobSpeed = 8.0f;
[SerializeField] private float crouchBobAmount = 0.025f;
private float defaultCameraYPos = 0;
private float timer;
[Header("Interaction Parameters")]
[SerializeField] Vector3 interactRayPoint = new Vector3(0.5f, 0.5f, 0);
[SerializeField] private float interactDistance = default;
[SerializeField] private LayerMask interactionLayer = default;
private Interactable currentInteractable;
[Header("Footsteps Parameters")]
[SerializeField] private float baseFootstepSpeed = 0.5f;
[SerializeField] private float crouchFootstepMultiplier = 1.5f;
[SerializeField] private float sprintFootstepMulitplier = 0.6f;
[SerializeField] private AudioSource footstepAudioSource = default;
[SerializeField] private AudioClip[] tiledFloorClips = default;
private float footStepTimer = 0;
private float GetCurrentOffset => isCrouching ? baseFootstepSpeed * crouchFootstepMultiplier : isSprinting ? baseFootstepSpeed * sprintFootstepMulitplier : baseFootstepSpeed;
private Vector2 currentInput;
private Vector3 move;
private Vector3 standingCameraPosition;
private Vector3 crouchingCameraPosition;
private Vector3 velocity;
void Awake()
{
standingCameraPosition = mainCamera.transform.localPosition;
crouchingCameraPosition = new Vector3(standingCameraPosition.x, standingCameraPosition.y - (standingHeight - crouchHeight) / 2, standingCameraPosition.z);
defaultCameraYPos = mainCamera.transform.localPosition.y;
}
// Update is called once per frame
void Update()
{
HandleMovement();
if(canJump){
HandleJump();
}
if(canCrouch){
HandleCrouch();
}
if(canUseHeadbob){
HandleHeadbob();
}
if(canInteract){
HandleInteractionCheck();
HandleInteractionInput();
}
if(useFootsteps){
HandleFootsteps();
}
}
void HandleMovement()
{
currentInput = new Vector2(walkSpeed * Input.GetAxis("Horizontal"), walkSpeed * Input.GetAxis("Vertical"));
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
move = transform.right * x + transform.forward * z;
characterController.Move(move * (isCrouching ? crouchSpeed : isSprinting ? sprintSpeed : walkSpeed) * Time.deltaTime);
characterController.Move(velocity * Time.deltaTime);
}
private void HandleFootsteps()
{
if(!characterController.isGrounded) return;
if(currentInput == Vector2.zero) return;
footStepTimer -= Time.deltaTime;
if(footStepTimer <= 0){
if(Physics.Raycast(mainCamera.transform.position, Vector3.down, out RaycastHit hit, 3))
{
switch (hit.collider.tag){
case "Footsteps/TILES":
footstepAudioSource.PlayOneShot(tiledFloorClips[Random.Range(0, tiledFloorClips.Length - 1)]);
break;
case "Footsteps/WOOD":
break;
default:
break;
}
}
footStepTimer = GetCurrentOffset;
}
}
private void HandleJump(){
if (characterController.isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
if(shouldJump){
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
velocity.y += gravity * Time.deltaTime;
}
}
I’ve tried to refactor it by making the footStepTimer distance based with this:
private void HandleFootsteps()
{
if (!characterController.isGrounded) return;
if (move == Vector3.zero) return;
float distanceMoved = Vector3.Distance(transform.position, previousPosition);
footStepTimer += distanceMoved;
if (footStepTimer >= GetCurrentOffset)
{
if (Physics.Raycast(mainCamera.transform.position, Vector3.down, out RaycastHit hit, 3))
{
switch (hit.collider.tag)
{
case "Footsteps/TILES":
footstepAudioSource.PlayOneShot(tiledFloorClips[Random.Range(0, tiledFloorClips.Length)]);
break;
case "Footsteps/WOOD":
break;
default:
break;
}
}
footStepTimer = 0f; // Reset the timer after playing a footstep sound
}
previousPosition = transform.position;
}
But the same problems still arose and then I tried:
private Vector3 previousPosition;
void Awake()
{
// Initialize the previous position
previousPosition = transform.position;
}
private void HandleFootsteps()
{
if (!characterController.isGrounded) return;
if (move == Vector3.zero) return;
// Calculate the distance moved since the last frame
float distanceMoved = Vector3.Distance(transform.position, previousPosition);
// Update footstep timer based on distance moved
footStepTimer -= distanceMoved;
if (footStepTimer <= 0)
{
if (Physics.Raycast(mainCamera.transform.position, Vector3.down, out RaycastHit hit, 3))
{
switch (hit.collider.tag)
{
case "Footsteps/TILES":
footstepAudioSource.PlayOneShot(tiledFloorClips[Random.Range(0, tiledFloorClips.Length)]);
break;
case "Footsteps/WOOD":
// Add wood footstep sound logic here
break;
default:
// Add default footstep sound logic here
break;
}
}
footStepTimer = GetCurrentOffset;
}
// Update the previous position
previousPosition = transform.position;
}
Monscrul is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.