Forum rules - please read before posting.

Changing AC Footsteps based on Materials and Terrain.

Changing AC Footsteps based on Materials and Terrain.

I’m looking for a method to change the Adventure Creators footsteps.

I looked at the method using Physic collider materials via a custom script on also on the wiki - "Sync footstep sounds with collider materials" but that won't work on a Terrain.

I’m looking to do similar, but by detecting the Material the player is standing on rather than a Physic collider, so that I can have footstep sounds groups change when on a listed objects or Terrain material alike. I just haven’t a clue how to do that.

Several First Person Controller’s set ups have this feature, but stuck in with lots of other elements I don’t need and which then conflict with AC, especially when switching between 1st person and Point and Click modes.

I’ve been using the perfectly excellent AC First Person prefab.

Any suggestions on what to do?

Comments

  • edited January 7

    Generally Footsteps can be any generic system that you can find because they always play. It's just your character casting a ray and checking the Texture. You only need to integrate it with AC if you want to use the Sound Component, but that could easily be done seperately, too.

    This seems to work, just fill out all the fields accordingly. The Index is the order in which you put in your textures in the Terrain Layers, you can just put in the Sounds as they fit in the order:


    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using AC;

    public class AutoSetFootstepTerrain : MonoBehaviour
    {
    [SerializeField] private Terrain terrain;
    [SerializeField] private LayerMask layerMask = new LayerMask();
    [SerializeField] private float rayLength = 2f;
    [SerializeField] private FootstepTexture[] footstepTextures = new FootstepTexture[0];
    [SerializeField] private FootstepMaterial[] footstepMaterials = new FootstepMaterial[0];

    private Char character;
    private FootstepSounds footstepSounds;
    private int standingOnTextureIndex = -1; // Initialize to an invalid index
    private PhysicMaterial standingOnMaterial;
    
    private void Awake()
    {
        character = GetComponent<Char>();
        footstepSounds = GetComponentInChildren<FootstepSounds>();
        InitializeFootstepSounds();
    }
    
    private void LateUpdate()
    {
        UpdateFootstepSounds();
    }
    
    private void InitializeFootstepSounds()
    {
        // Call this method to initialize footstep sounds based on the starting surface
        UpdateFootstepSounds(forceUpdate: true);
    }
    
    private void UpdateFootstepSounds(bool forceUpdate = false)
    {
        Vector3 rayStart = transform.position + (0.5f * rayLength * Vector3.up);
        RaycastHit hitInfo;
        if (Physics.Raycast(rayStart, Vector3.down, out hitInfo, rayLength, layerMask))
        {
            if (terrain && hitInfo.collider.gameObject == terrain.gameObject)
            {
                // Terrain logic
                Vector3 terrainLocalPos = terrain.transform.InverseTransformPoint(transform.position);
                int mapX = (int)((terrainLocalPos.x / terrain.terrainData.size.x) * terrain.terrainData.alphamapWidth);
                int mapZ = (int)((terrainLocalPos.z / terrain.terrainData.size.z) * terrain.terrainData.alphamapHeight);
                float[,,] alphaMap = terrain.terrainData.GetAlphamaps(mapX, mapZ, 1, 1);
                int maxTextureIndex = 0;
                float maxAlpha = 0;
                for (int i = 0; i < terrain.terrainData.alphamapLayers; i++)
                {
                    if (alphaMap[0, 0, i] > maxAlpha)
                    {
                        maxAlpha = alphaMap[0, 0, i];
                        maxTextureIndex = i;
                    }
                }
                if (forceUpdate || standingOnTextureIndex != maxTextureIndex)
                {
                    standingOnTextureIndex = maxTextureIndex;
                    OnStandTexture(standingOnTextureIndex);
                }
            }
            else if (hitInfo.collider.sharedMaterial)
            {
                // Physics material logic
                if (forceUpdate || standingOnMaterial != hitInfo.collider.sharedMaterial)
                {
                    standingOnMaterial = hitInfo.collider.sharedMaterial;
                    OnStandMaterial(standingOnMaterial);
                }
            }
        }
    }
    
    
    private void OnStandTexture(int textureIndex)
    {
        foreach (FootstepTexture footstepTexture in footstepTextures)
        {
            if (footstepTexture.TextureIndex == textureIndex)
            {
                footstepTexture.Apply(footstepSounds);
                return;
            }
        }
    }
    
    private void OnStandMaterial(PhysicMaterial material)
    {
        foreach (FootstepMaterial footstepMaterial in footstepMaterials)
        {
            if (footstepMaterial.Material == material)
            {
                footstepMaterial.Apply(footstepSounds);
                return;
            }
        }
    }
    
    [System.Serializable]
    private class FootstepTexture
    {
        [SerializeField] private int textureIndex = 0;
        [SerializeField] private AudioClip[] walkSounds = new AudioClip[0];
        [SerializeField] private AudioClip[] runSounds = new AudioClip[0];
    
        public void Apply(FootstepSounds footstepSounds)
        {
            if (walkSounds.Length > 0)
            {
                footstepSounds.footstepSounds = walkSounds;
            }
            if (runSounds.Length > 0)
            {
                footstepSounds.runSounds = runSounds;
            }
            if (!footstepSounds.character.IsGrounded() && walkSounds.Length > 0)
            {
                footstepSounds.soundToPlayFrom.audioSource.clip = walkSounds[0];
            }
        }
    
        public int TextureIndex { get { return textureIndex; } }
    }
    
    [System.Serializable]
    private class FootstepMaterial
    {
        [SerializeField] private PhysicMaterial material = null;
        [SerializeField] private AudioClip[] walkSounds = new AudioClip[0];
        [SerializeField] private AudioClip[] runSounds = new AudioClip[0];
    
        public void Apply(FootstepSounds footstepSounds)
        {
            if (walkSounds.Length > 0)
            {
                footstepSounds.footstepSounds = walkSounds;
            }
            if (runSounds.Length > 0)
            {
                footstepSounds.runSounds = runSounds;
            }
            if (!footstepSounds.character.IsGrounded() && walkSounds.Length > 0)
            {
                footstepSounds.soundToPlayFrom.audioSource.clip = walkSounds[0];
            }
        }
    
        public PhysicMaterial Material { get { return material; } }
    }
    

    }


  • edited January 8

    Improvements to AC's footstep sounds system are certainly on my todo list.

    @snan is quite right in that this is a topic that's generic enough to be added onto your game without needing it to directly integrate with AC.

    If I understand the Terrain system correctly though, a Terrain uses a single Material with multiple Textures - you'd need to detect the Texture itself rather than the Material you're standing on.

    A guide to playing different footsteps with Terrain texture can be found here:
    https://johnleonardfrench.com/terrain-footsteps-in-unity-how-to-detect-different-textures/

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.