- Home /
Play Audio on destroy
I am currently trying to add some soundFX to the projectiles in my game. One on birth, one on impact. The first one is no problem, the second one, however, is.
Things I tried:
audio.PlayOneShot: doesn't work; audio stops as soon as the projectile is destroyed, obviously
delay the destruction of the projectile until audio is finished: does play audio, but adds different problems, like particle effects being spawned again and again and projectile continuing to move after impact
instantiate a soundFX prefab that gets destroyed automatically after sound is played: plays the audio, but has severe impact on framerate, when the game is busy
AudioSource.PlayClipAtPoint: plays audio, but way too quiet (changing the volume doesn't seem to have an effect); also performance issues, not as heavy as instantiate, but close
The only thing I see right now is option 2 when I stop the projectile, disable the particleFX after being spawned once and disable the mesh renderer and collider for the projectile.
Any alternative/better solutions?
For reference, this is the script attached to my projectiles:
#pragma strict
var melee : boolean = false;
var damage : int = 1;
var AoE : int = 0;
var rateOfFire : int = 5;
var projSpeed : int = 1;
var spin : int = 6;
var life : int = 15;
var birthFX : Transform;
var birthSFX : AudioClip;
var impactFX : Transform;
var impactSFX : AudioClip;
var AoEProj: Transform;
var owner : String;
function Awake() {
life *= statics.turnDuration;
if(!melee) {
Instantiate(birthFX, transform.position , Quaternion.LookRotation(Vector3.up, transform.forward));
audio.PlayOneShot(birthSFX);
}
}
function Update() {
transform.Rotate(Vector3.forward, 60 * spin * Time.deltaTime);
}
function FixedUpdate() {
if(statics.turnActive) {
transform.Translate(Vector3.forward * projSpeed);
life--;
}
if(life < 1) {
if(!melee) {
Instantiate(impactFX, transform.position, transform.rotation);
}
if(AoE > 0) {
var tempPos : Vector2 = Vector2(Mathf.Round((transform.position.x / statics.r) - ((statics.g * transform.position.z) / (statics.b * statics.r))), Mathf.Round(transform.position.z / (statics.b * statics.r))); //calculate starting tile
var tempFX : Transform = Instantiate(AoEProj, Vector3((tempPos.x + statics.g * tempPos.y) * statics.r, 0, statics.b * tempPos.y * statics.r), Quaternion.Euler(0, 90, 0));
tempFX.GetComponent(Projectile).damage = AoE;
tempFX.GetComponent(Projectile).owner = owner;
if(owner == "player")
tempFX.GetComponent(Projectile).damage *= PlayerStatus.multiplier;
}
if(!melee)
audio.PlayOneShot(impactSFX);
Destroy(gameObject);
}
}
I handle impact by setting life to 0 through the enemies'/player's scripts.
Additional problem: Background music stops when playing sound fx...
PC standalone. The performance problems with #3 and #4 are severe enough to make the game stutter on my machine (win7 64bit, i7-2600, 8GB RA$$anonymous$$)
Oh...and the music doesn't stop instantly when the first sound is played, but when the sounds 'drown' the music once, it never comes back.
Answer by JohnR · May 18, 2013 at 07:29 PM
I'm just starting out in Unity but the way I handled it was to play the clip, hide the object, and then destroy it after the audio was done. Code would look something like this:
audio.PlayOneShot(aClip);
renderer.enabled = false;
Destroy(gameObject, aClip.length); //waits till audio is finished playing before destroying.
You may also have to disable any colliders you have on the object.
Why the hell hasn't anyone upvoted this? It's a nice solution to the problem.
Sometimes disabling renderer is not flexible, since the gameobject can have children with renderers. I think a most effective way is to send the object to far away transform.position = Vector3.one * 9999999f
.
I have been stuck trying to figure out how to play audio with Unity 5 and for some reason it wasn't working. I commented out the Destroy(gameObject) and it worked except for deleting the object. Your answer helped me a bunch!!! This needs more upvotes.
To expand on the answer provided above:
Typically what I would do is simliar to how I currently handle particle systems on a projectile's death. The particle system/audiosource will reside on a child object of the projectile and on projectile death unparent the child object and have it destroyed a few seconds later, and then immeadiately destroy the original projectile prefab. This way I don't have to worry about any advanced logic in a monobehavior script or collisions with an already dead projectile, only particle effects and audio remains (if only briefly).
the projectile might have a OnTriggerEnter which can fire even if the object is disabled, or it might have a ton of other advanced behavior happening in its own hierarchy. "Splintering off" residue child objects and killing the parent provides consistent behavior across a multitude of Projectile types.
If its a mobile game, then Projectiles are typically pooled, in which case I would disable the object and have extra checks if on OnTrigger was being used.
In this event you can make the audio and particles group a sibling to the projectile model in a wrapper object ins$$anonymous$$d of the children thus they would remain always enabled in a pooled projectile
--Projectile_Prefab(always enabled)
|-- Projectile $$anonymous$$odel and Scripts (disabled on death)
|-- PostDeath (always enabled)
|-- AudioSource Object(s)
|-- Particle System(s)
This disable render solve my problem perfectly! Thanks!
Answer by BHS · May 25, 2012 at 08:57 AM
Here's what I used, there was no frame rate loss and it allows you to play the sound after the game object has been destroyed. Try this instead of what you're doing it should work, just change the named to your audio sound name.
var goldCollect : AudioClip;
//Gold collected, destory self
Destroy(gameObject);
//Your audio name goes here
if (goldCollect) //And here
AudioSource.PlayClipAtPoint(goldCollect, transform.position);
You and the Unity devs who included this method are based! I was contemplating either destroying the components of the GameObject separately and destroying the AudioSource after the sound is done, or Instantiating it which apparently gives an fps drop. This was perfect, thanks again!
If you use na Audio$$anonymous$$ixer, AudioSource.PlayClipAtPoint might not have the expected effects applied, though. Or am I wrong?
Answer by Tseng · May 15, 2012 at 04:10 PM
Create an GameObject with an AudioSource, then instantiate (better way to do is, make a cache which handles the Audio objects and recylce it w/o creating and destroying them all the time) it and set the audio
AudioSource as = Instantiate(audioObjectPrefab, transform.position, Quaternion.identity) as AudioSource;
as.clip = myAduioClip;
as.Play();
Destroy(gameObject)
This will create a new object which only contains an AudioSource which plays the sound. which is independent of your destroyed gameobject. Make sure to destroy it after the audio has stopped playing or put it back to the audio cache.
That was #3. Severe framerate hit due to instantiate. Not sure how I would go about cachig them...
I had a Spawn caching script somewhere, but can't find the link anymore.
I think I found it somewhere on the http://unifycommunity.com/ wiki
Your answer
Follow this Question
Related Questions
Music Visualiser Troubles 0 Answers
Multiple audioSources on same gameObject? 1 Answer
Audio.Play() not showing up 1 Answer
Max amount of simultaneous, hearable sounds? 1 Answer
Audio problems 1 Answer