- Home /
Playing a sound while pushing an object
Hi there,
My problem is that I have an object (a wooden box) in the scene and player can push it around and I have a SFX which plays when the player collides with that wooden box,
The problem is; I want this sound to be played only when the player is pushing it, for example; if the player stands above it or sticks to it, sound still plays which is something I don't want.
I've tried many different solutions and none of them worked so far (checking rigidbody.isSleeping or checking if the object is moving or not with some transform.position etc.) And yes, this wooden box has a rigidbody2D and it's a 2D game.
Hope someone here can help me, thanks in advance!
Answer by highpockets · Aug 17, 2020 at 07:55 PM
I would imagine that this could be done by checking if the collision is happening between the player and the box while simultaneously checking to see if the rigidbody’s velocity vector of the box has a magnitude higher than some amount that you might need to play with to get working for you. On the other hand, if the only time the box is actually moving is when the player moves it and it can’t fall off ledges, than the velocity magnitude check would likely suffice without even checking the collision, but if the box is able to move around by means of other collisions unrelated to the player, that of course wouldn’t work.
I've tried something like this and when I check it in the editor with debug I see that moving bool is working, but I can't hear the sound? :/
void Update()
{
curPos = transform.position;
if(curPos == lastPos)
{
moving = false;
}
else
{
moving = true;
}
lastPos = curPos;
}
private void OnCollisionEnter2D(Collision2D other)
{
if(other.gameObject.tag == "Player" && moving)
{
Audio$$anonymous$$anager.instanceAudio$$anonymous$$anager.PlaySFX(21);
}
}
private void OnCollisionExit2D(Collision2D other)
{
if (other.gameObject.tag == "Player" && !moving)
{
Audio$$anonymous$$anager.instanceAudio$$anonymous$$anager.StopSFX(21);
}
}
Ok, you are doing the moving check in the Update loop. Update could and likely is happening multiple times between fixed update calls. Since the box has a rigidbody, the movement should be happening during the physics loop like all physics related objects, so I would make the check in fixed update.
I've changed it to this, and now when I play the game in the editor, I hear the sfx immediately ,altough I am not pushing the box at that moment, and when I push it with the player, the moving is beco$$anonymous$$g true, but no sound :( Also, I've tried all of it in fixedUptade and with onCollisionEnter2D/onCollisionExit2D but the result is same...
void FixedUpdate()
{
if (moving)
{
Audio$$anonymous$$anager.instanceAudio$$anonymous$$anager.PlaySFX(21);
}
else
{
Audio$$anonymous$$anager.instanceAudio$$anonymous$$anager.StopSFX(21);
}
}
void Update()
{
curPos = transform.position;
if(curPos == lastPos)
{
moving = false;
}
else
{
moving = true;
}
lastPos = curPos;
}
Also with your recommendation I've tried this and unfortunately the result is same, moving bool is beco$$anonymous$$g true when I push the object, but the sfx not playing while pushing, I really don't understand why is this not working :/
void Update()
{
if(theRB.velocity.magnitude > 0.1f)
{
moving = true;
if (moving)
{
Audio$$anonymous$$anager.instanceAudio$$anonymous$$anager.PlaySFX(21);
}
}
else
{
moving = false;
if (!moving)
{
Audio$$anonymous$$anager.instanceAudio$$anonymous$$anager.StopSFX(21);
}
}
}
Just a thought that maybe after the effect is set to play, you might want to give it a second before turning it off to allow for it to play at least some of the effect even if it was just pushed a tad. Again, I would make these checks in fixed update as it is a physics related check. To allow time for the sound fx to play, I would start a coroutine and WaitForSeconds(0.5f) or something before allowing it to stop. Or better yet, something like this:
float secondsToPlay = 0.0f;
Vector3 lastPos;
private void FixedUpdate()
{
if(box.transform.position != lastPos)
{
if( secondsToPlay == 0.0f )
StartCoroutine(PlayEffect());
else if( secondsToPlay < 0.5f )
secondsToPlay = 0.5f;
}
lastPos = box.transform.position;
}
private IEnumerator PlayEffect()
{
secondsToPlay = 0.5f;
//play sound effect
while( secondsToPlay > 0.0f )
{
yield return null;
secondsToPlay -= Time.deltaTime;
}
secondsToPlay = 0.0f;
//stop sound effect
}
I've tried it and it seems like working but there is this odd problem, the sfx is playing sometimes suddenly by itself, while the player is not pushing the box :/
I don't know how, but when I restart the project it works now just as I want it! Thank you so much, I've solved my problem and also learned a lot of things on the way, all because of you, so again, thank you so much :) I am leaving the final version of the script (the one works for me) here if anyone else needs it;
float secondsToPlay = 0.0f;
private Rigidbody2D theRB;
void Start()
{
theRB = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
if (theRB.velocity.magnitude > 2f)
{
if (secondsToPlay == 0.0f)
StartCoroutine(PlayEffect());
else if (secondsToPlay < 0.1f)
secondsToPlay = 0.1f;
}
}
private IEnumerator PlayEffect()
{
secondsToPlay = 0.1f;
Audio$$anonymous$$anager.instanceAudio$$anonymous$$anager.PlaySFX(21);
while (secondsToPlay > 0.0f)
{
yield return null;
secondsToPlay -= Time.deltaTime;
}
secondsToPlay = 0.0f;
Audio$$anonymous$$anager.instanceAudio$$anonymous$$anager.StopSFX(21);
}
Answer by Batuhan13 · Aug 17, 2020 at 08:45 PM
Hi mate as I see from upper answer I think solution way is same and true. You should use Rigidbody2d.Velocity.
if(Cube.velocity!=0) { //Play sound }
In here cube is rigidbody 2d. For playing sound you could use Mathf Lerp method . You could change volume of audio source with mathf.lerp =) I hope these things will help you good luck & have a great day =).
Hi, firstly thanks for the help :) But it seems like this syntax is not correct because unity throws errors when I tried "if(Cube.velocity!=0) { //Play sound}".
Sorry my bad I forget to add .magnitude after .velocity. Here try this same idea.
public class Testt : $$anonymous$$onoBehaviour
{
[SerializeField] private Rigidbody2D _Rb = null;
[SerializeField] private AudioSource _SoundPlayer = null;
[SerializeField] private float _LerpingAmount = 0;
private float _currentVolume = 0;
void Update()
{
PlayPushingSound();
}
private void PlayPushingSound()
{
if (_Rb.velocity.magnitude!=0)
{
_currentVolume = $$anonymous$$athf.Lerp(_currentVolume, 1, _LerpingAmount * Time.deltaTime);
_SoundPlayer.volume = _currentVolume;
}
else
{
_currentVolume = $$anonymous$$athf.Lerp(_currentVolume, 0, _LerpingAmount * Time.deltaTime);
_SoundPlayer.volume = _currentVolume;
}
}
}
Have a great day
No prob. thank you, and I've tried this one but now sfx is not playing at all when I push it around :/
Your answer
Follow this Question
Related Questions
3D Audio Source plays choppy/poping in web player (Video) 1 Answer
Logarithmic Rolloff Sounds Plays After Max Distance 0 Answers
multiple sounds, sound....sucky 0 Answers
How to play two sounds at once on same object 2 Answers
Sound stutters and stops when coming back from background (iOS 7) 1 Answer