Hi, sorry to revive this post (again!)
I followed all the mentioned steps and now I don’t get any errors or warnings (which is great!).
I’m able to listen to the footsteps, but they’re all playing at once.
My footstep FMOD event has everything set upright with the parameters added to it.
Is there any chance to send an updated version of this footstep script? Quite tricky to get it to work having no programming skills
My Unity is 2021.3.16f1 and my FMOD is 2.02.11
This is what I have atm
/* ======================================================================================== */
/* FMOD Studio - Unity Integration Demo. */
/* Firelight Technologies Pty, Ltd. 2012-2016. */
/* Liam de Koster-Kjaer */
/* */
/* Use this script in conjunction with the Viking Village scene tutorial and Unity 5.4. */
/* http://www.fmod.org/training/ */
/* */
/* 1. Import Viking Village asset package */
/* 2. Import FMOD Studio Unity Integration package */
/* 3. Replace Audio listener with FMOD Studio listener on player controller */
/* (FlyingRigidBodyFPSController_HighQuality) */
/* 4. Add footsteps script to the player controller */
/* 5. Set footsteps script variable ‘Step Distance’ to a reasonable value (2.0f) */
/* 6. Change terrain texture import settings so we can sample pixel values */
/* - terrain_01_m */
/* - terrain_wetmud_01_sg */
/* - Texture Type: Advanced */
/* - Non Power of 2: N/A */
/* - Mapping: None */
/* - Convolution Type: N/A */
/* - Fixup Edge Seams: N/A */
/* - Read/Write Enabled: Yes */
/* - Import Type: Default */
/* - Alpha from Greyscale: No */
/* - Alpha is Transparency: No */
/* - Bypass sRGB sampling: No */
/* - Encode as RGBM: Off */
/* - Sprite Mode: None */
/* - Generate Mip Maps: No */
/* - Wrap Mode: Repeat */
/* - Filter Mode: Bilinear */
/* - Aniso Level: 3 */
/* ======================================================================================== */
using UnityEngine;
using System.Collections;
//This script plays footstep sounds.
//It will play a footstep sound after a set amount of distance travelled.
//When playing a footstep sound, this script will cast a ray downwards.
//If that ray hits the ground terrain mesh, it will retreive material values to determine the surface at the current position.
//If that ray does not hit the ground terrain mesh, we assume it has hit a wooden prop and set the surface values for wood.
public class Footsteps : MonoBehaviour
{
//FMOD Studio variables
//The FMOD Studio Event path.
//This script is designed for use with an event that has a game parameter for each of the surface variables, but it will still compile and run if they are not present.
public FMODUnity.EventReference m_EventPath;
//Surface variables
//Range: 0.0f - 1.0f
//These values represent the amount of each type of surface found when raycasting to the ground.
//They are exposed to the UI (public) only to make it easy to see the values as the player moves through the scene.
public float m_Wood;
public float m_Water;
public float m_Dirt;
public float m_Sand;
//Step variables
//These variables are used to control when the player executes a footstep.
//This is very basic, and simply executes a footstep based on distance travelled.
//Ideally, in this case, footsteps would be triggered based on the headbob script. Or if there was an animated player model it could be triggered from the animation system.
//You could also add variation based on speed travelled, and whether the player is running or walking.
public float m_StepDistance = 2.0f;
float m_StepRand;
Vector3 m_PrevPos;
float m_DistanceTravelled;
//Debug variables
//If m_Debug is true, this script will:
// - Draw a debug line to represent the ray that was cast into the ground.
// - Draw the triangle of the mesh that was hit by the ray that was cast into the ground.
// - Log the surface values to the console.
// - Log to the console when an expected game parameter is not found in the FMOD Studio event.
public bool m_Debug;
Vector3 m_LinePos;
Vector3 m_TrianglePoint0;
Vector3 m_TrianglePoint1;
Vector3 m_TrianglePoint2;
void Start()
{
//Initialise random, set seed
Random.InitState(System.DateTime.Now.Second);
//Initialise member variables
m_StepRand = Random.Range(0.0f, 0.5f);
m_PrevPos = transform.position;
m_LinePos = transform.position;
}
void Update()
{
m_DistanceTravelled += (transform.position - m_PrevPos).magnitude;
if(m_DistanceTravelled >= m_StepDistance + m_StepRand)//TODO: Play footstep sound based on position from headbob script
{
PlayFootstepSound();
m_StepRand = Random.Range(0.0f, 0.5f);//Adding subtle random variation to the distance required before a step is taken - Re-randomise after each step.
m_DistanceTravelled = 0.0f;
}
m_PrevPos = transform.position;
if(m_Debug)
{
Debug.DrawLine(m_LinePos, m_LinePos + Vector3.down * 1000.0f);
Debug.DrawLine(m_TrianglePoint0, m_TrianglePoint1);
Debug.DrawLine(m_TrianglePoint1, m_TrianglePoint2);
Debug.DrawLine(m_TrianglePoint2, m_TrianglePoint0);
}
}
void PlayFootstepSound()
{
//Defaults
m_Water = 0.0f;
m_Dirt = 1.0f;
m_Sand = 0.0f;
m_Wood = 0.0f;
RaycastHit hit;
if(Physics.Raycast(transform.position, Vector3.down, out hit, 1000.0f))
{
if(m_Debug)
m_LinePos = transform.position;
if(hit.collider.gameObject.layer == LayerMask.NameToLayer("Ground"))//The Viking Village terrain mesh (terrain_near_01) is set to the Ground layer.
{
int materialIndex = GetMaterialIndex(hit);
if(materialIndex != -1)
{
Material material = hit.collider.gameObject.GetComponent<Renderer>().materials[materialIndex];
if(material.name == "mat_terrain_near_01 (Instance)")//This texture name is specific to the terrain mesh in the Viking Village scene.
{
if(m_Debug)
{//Calculate the points for the triangle in the mesh that we have hit with our raycast.
MeshFilter mesh = hit.collider.gameObject.GetComponent<MeshFilter>();
if(mesh)
{
Mesh m = hit.collider.gameObject.GetComponent<MeshFilter>().mesh;
m_TrianglePoint0 = hit.collider.transform.TransformPoint(m.vertices[m.triangles[hit.triangleIndex * 3 + 0]]);
m_TrianglePoint1 = hit.collider.transform.TransformPoint(m.vertices[m.triangles[hit.triangleIndex * 3 + 1]]);
m_TrianglePoint2 = hit.collider.transform.TransformPoint(m.vertices[m.triangles[hit.triangleIndex * 3 + 2]]);
}
}
//The mask texture determines how the material's main two textures are blended.
//Colour values from each texture are blended based on the mask texture's alpha channel value.
//0.0f is full dirt texture, 1.0f is full sand texture, 0.5f is half of each.
Texture2D maskTexture = material.GetTexture("_Mask") as Texture2D;
Color maskPixel = maskTexture.GetPixelBilinear(hit.textureCoord.x, hit.textureCoord.y);
//The specular texture maps shininess / gloss / reflection to the terrain mesh.
//We are using it to determine how much water is shown at the cast ray's point of intersection.
Texture2D specTexture2 = material.GetTexture("_SpecGlossMap2") as Texture2D;
//We apply tiling assuming it is not already applied to hit.textureCoord2
float tiling = 40.0f;//This is a public variable set on the material, we could reference the actual variable but I ran out of time.
float u = hit.textureCoord.x % (1.0f / tiling);
float v = hit.textureCoord.y % (1.0f / tiling);
Color spec2Pixel = specTexture2.GetPixelBilinear(u, v);
float specMultiplier = 6.0f;//We use a multiplier to better represent the amount of water.
m_Water = maskPixel.a * Mathf.Min(spec2Pixel.a * specMultiplier, 0.9f);//Only the sand texture has water, so we multiply by the mask pixel alpha value.
m_Dirt = (1.0f - maskPixel.a);
m_Sand = maskPixel.a - m_Water * 0.1f;//Ducking the sand a little for the water
m_Wood = 0.0f;
}
}
}
else//If the ray hits somethign other than the ground, we assume it hit a wooden prop (This is specific to the Viking Village scene) - and set the parameter values for wood.
{
m_Water = 0.0f;
m_Dirt = 0.0f;
m_Sand = 0.0f;
m_Wood = 1.0f;
}
}
if(m_Debug)
Debug.Log("Wood: " + m_Wood + " Dirt: " + m_Dirt + " Sand: " + m_Sand + " Water: " + m_Water);
if(!m_EventPath.IsNull)
{
FMOD.Studio.EventInstance e = FMODUnity.RuntimeManager.CreateInstance(m_EventPath);
e.set3DAttributes(FMODUnity.RuntimeUtils.To3DAttributes(transform.position));
e.setParameterByName("Wood", m_Wood);
e.setParameterByName("Dirt", m_Wood);
e.setParameterByName("Sand", m_Wood);
e.setParameterByName("Water", m_Wood);
e.start();
e.release();//Release each event instance immediately, there are fire and forget, one-shot instances.
}
}
int GetMaterialIndex(RaycastHit hit)
{
Mesh m = hit.collider.gameObject.GetComponent<MeshFilter>().mesh;
int[] triangle = new int[]
{
m.triangles[hit.triangleIndex * 3 + 0],
m.triangles[hit.triangleIndex * 3 + 1],
m.triangles[hit.triangleIndex * 3 + 2]
};
for(int i = 0; i < m.subMeshCount; ++i)
{
int[] triangles = m.GetTriangles(i);
for(int j = 0; j < triangles.Length; j += 3)
{
if(triangles[j + 0] == triangle[0] &&
triangles[j + 1] == triangle[1] &&
triangles[j + 2] == triangle[2])
return i;
}
}
return -1;
}
}