The first two sounds play fully (idleknight and alertknight) but when i get as close as 15(sounddistance2) and later 4.5 (sounddistance3)from the enemy, the sounds continuously plays over it self and not plays through fully.
the script is on a enemy gameobject with an audiosource
I think i am really close to have it working as intended, but i just can’t seem to fix the problem.
will any of you kind souls take a look?
using System.Collections.Generic;
using UnityEngine;
public class AiBasic : MonoBehaviour
{
public Transform player;
public AudioSource knightsound;
public AudioClip idleknight;
public AudioClip alertknight;
public AudioClip walkingknight;
public AudioClip attackingknight;
public float sounddistance1;
// is 20
public float sounddistance2;
// is 15
public float sounddistance3;
// is 4.5
void Start()
{
knightsound = GetComponent<AudioSource>();
anim = GetComponent<Animator>();
knightsound.clip = idleknight;
knightsound.Play();
knightsound.loop = true;
rididbody = GetComponent<Rigidbody>();
}
void Update()
{
if (Vector3.Distance(player.position, transform.position) > sounddistance1)
{
knightsound.clip = idleknight;
if (!knightsound.isPlaying)
{
knightsound.Play();
}
}
if (Vector3.Distance(player.position, transform.position) < sounddistance1)
{
knightsound.clip = alertknight;
if (!knightsound.isPlaying)
{
knightsound.Play();
}
}
if (Vector3.Distance(player.position, transform.position) < sounddistance2)
{
knightsound.clip = walkingknight;
if (!knightsound.isPlaying)
{
knightsound.Play();
}
}
if (Vector3.Distance(player.position, transform.position) < sounddistance3)
{
knightsound.clip = attackingknight;
if (!knightsound.isPlaying)
{
knightsound.Play();
}
}
}
}
First thing I would try is to put Debug.Log() statements right nextto the .Play() calls to see what is happening.
Also, you might want to compute Vector3.Distance() just once and store it in a local variable, then compare it four times. Vector3.Distance() is not a “cheap” function to call. That way you can also print out what the distance is at each Debug.Log() statement you put in!
It could be that you need some latching mechanism that determines which of the four possible conditions you want to be in next, and only triggers audio if it is different from the previous frame, then it “writes down” the new condition so it doesn’t retrigger.
That would also be a great time to double-check the values you have for sounddistance1,2,3 because certain combinations could have multiple ones of those conditions firing each frame.
Hey Kurt, thanks for replying, i tried putting a Debug.Log(“soundisplaying”); which seemed to print with every update
(every frame?) and i printed over 500 times really quick. This makes me think that the it is not checking if a sound is currently being played for some reason. I have put together a picture of the states to show what happens, because its hard for me to explain in words
i will look into storing the distance too, thanks for the tip
I don’t think you want to reassign knightsound.clip multiple times per update like you’re doing. Assuming sounddistance3 is the smallest value (I think you made a mistake in your post regarding this), then when at less distance than sounddistance3 on every update you will assign knightsound.clip as alertKnight, walkingKnight, and attackingKnight all while the clip is playing. My guess is you will just hear the attackingKnight clip continually restart, but not exactly sure.
You should only reassign the clip on state change, not every update. You should also not assign multiple different clips to knightsound.clip while it is playing each update if what you are looking for is a complete play through of a single audio clip.
Hey Joe, So you mean that i only change the clip when player is outside range, inside range1, inside range 2 and inside range 3, and not when looking for the change in states? but how would i do that in the update function?
I didn’t think that i was assigning multiple different clips to knightsound.clip unless the if statements were true. i thought the parts where skipped kind of.
You can also have multiple audio sources and start/stop those, each one assigned to a single sound. That might give a cleaner overall implementation because then in the future you could do cross-fade between them, once you have the core logic detect-change-state going.
Lets say that Vector3.Distance(player.position, transform.position) was equal to 1.0. Now Update() is called, and here is what happens in a single pass through Update:
if (Vector3.Distance(player.position, transform.position) > sounddistance1) is false
if (Vector3.Distance(player.position, transform.position) < sounddistance1) is true, so knightsound.clip is assigned alertknight
if (Vector3.Distance(player.position, transform.position) < sounddistance2) is true, so again we assign knightsound.clip, this time as walkingKnight
if (Vector3.Distance(player.position, transform.position) < sounddistance3) is true, so once more we assign knightsound.clip, this time as attackingKnight.
That’s 3 assignments to knightsound.clip per update loop. You should be using if/else instead of a series of if statements, because multiple if statements can be true at the same time. I’d also track the previous clip set and only update if it changes.
IT*S ALIIIIVEEE!!
wow thanks Joe, I typed in your changes and it works like a charm, it took a while to understand it, but i found the basic unity tutorial on enums and it makes sense now, what a handy feature
the flow of the code also makes more sense now.
So a big thank you to you and Kurt for your time