Fmod VikingVillage Footstep integration

Hello, after following the old tutorials on youtube about Fmod Integration on the Unity Viking Village. I’ve spent the last day trying to update the script used in the tutorial to the current Unity version.

My problem here is that I cannot find a way to make this work :

[FMODUnity.EventRef]
	public string m_EventPath;
if(m_EventPath != null)
		{
			FMOD.Studio.EventInstance e = FMODUnity.RuntimeManager.CreateInstance(m_EventPath);
			e.set3DAttributes(FMODUnity.RuntimeUtils.To3DAttributes(transform.position));
			SetParameter(e, "Wood", m_Wood);
			SetParameter(e, "Dirt", m_Dirt);
			SetParameter(e, "Sand", m_Sand);
			SetParameter(e, "Water", m_Water);
			
			e.start();
			e.release();//Release each event instance immediately, there are fire and forget, one-shot instances. 
		}

Everything seems to be working appart from the “[FMODUnity.EventRef]” which is deemed obsolete by Unity, with a message suggering me to “use the EventReference struct instead”. I have been looking around to make that EventReference structure work but to no avail unfortunately.

I also get the same message about [FMODUnity.EventRef] beeing obsolete in the unity inspector where I try to set the EventPath.

We are phasing out the use of EventRef in favour of FMODUnity.EventReference. It currently only throws a warning and the code will still work as expected, but it may be removed in a future update.

In your code it would be public FMODUnity.EventReference m_EventPath;

Thank you for your answer.
This is one of the solutions I tried after looking around a bit on the forums. It however comes with the problem of :
if(m_EventPath != null)

Which is deemed incorect by Unity/C# when using this solution, and which I don’t quite see how to avoid.

Oh, I missed that one, sorry. I believe that should be if(!m_EventPath.IsNull)

Hi! Sorry to resurrect this post. I’m having this issue. Can you post the whole code? I’m not sure if I should replace
[FMODUnity.EventRef] with:
public FMODUnity.EventReference m_EventPath;

Or if it should come after. Where should I put
if(m_EventPath != null)

??

Thank you!

Hi,

You’ll need to do both. EventRef has been replaced by EventReference, so you’ll want to change the definition of m_EventPath to be an EventReference instead of a string. You don’t need the [EventRef] attribute, just the following:

public FMODUnity.EventReference m_EventPath;

Also, if(m_EventPath != null) should be replaced with if(!m_EventPath.IsNull) - EventReference need to be null-checked with .IsNull, as unlike a string it cannot actually be null.

For example, the code posted by Lolour would be changed to the following:

        if(!m_EventPath.IsNull) // <- changed this check
		{
			FMOD.Studio.EventInstance e = FMODUnity.RuntimeManager.CreateInstance(m_EventPath);
			e.set3DAttributes(FMODUnity.RuntimeUtils.To3DAttributes(transform.position));
			SetParameter(e, "Wood", m_Wood);
			SetParameter(e, "Dirt", m_Dirt);
			SetParameter(e, "Sand", m_Sand);
			SetParameter(e, "Water", m_Water);
			
			e.start();
			e.release();//Release each event instance immediately, there are fire and forget, one-shot instances. 
		}

Hope this helps!

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 :frowning:

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;
	}
}

Hi!

Your script is fine for the most part - the only issue is that every parameter is being set using the value ‘m_Wood’.

If you adjust these e.setParameterByName() calls to use the float that corresponds to the parameter being set. i.e.

            e.setParameterByName("Wood", m_Wood);
            e.setParameterByName("Dirt", m_Dirt);
            e.setParameterByName("Sand", m_Sand);
            e.setParameterByName("Water", m_Water);

Then it should all work as expected.

Oh, how did I miss this? :joy:

Thank you!!

1 Like

Hello,
I’m starting Fmod and I’m doing the Viking village tuto.
Thanks for this new version of the code without carsh! I’m noobie …
On the other hand, I can only hear the sound of wood footsteps…
I don’t understand this indication at the beginning of the code:
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

In the parameters of the textures mentioned, I don’t have exactly the same options and the changes I’ve tried don’t work.
I’m on Unity 2022.3.24f1.

Thanks for your answers!

Hi,

The issues you’re running into with the terrain texture import settings are due to Unity changing their texture importing between Unity 5.4 and the present version, and unfortunately I may not be able to be of much help. Are you receiving any specific warnings or errors from unity regarding the Footsteps.cs script?

As an aside, at this point our Viking Village tutorial is extremely old, and uses an outdated version of the FMOD API that, as noted in this thread, has been updated since. Since you’ve said that you’re new, if you haven’t already I would recommend taking a look at our more recent tutorials:

Thank you for your reply.
I don’t have any specific warning about this latest version of the script. I was therefore hoping that the problem would be simple…

Thanks for the other two tutorials, I’ve done the Karting one but not the shooter yet. I’m going to give it a try!
I liked this one on the Viking village because it combines creation in Fmod and integration in Unity! It’s very complete.

Thanks a lot!