Confused about Playing sound when Brick Destroyed?

Hello everyone,

I’ve listened to Lecture 87 a number of times and I’m really confused - can I programmatically play a sound only when the brick is destroyed or not? I couldn’t seem to find a definitive answer in the video. It seems like he says that you can and then, later in the same video he seems to be saying that you can’t. So I tried just playing a sound just before the destruction and as expected the compiler throws up an error after the game has started saying something along the lines of: “hey you idiot something is trying to play the sound but that object doesn’t exist anymore so I’m going to stop you right there”.

The only real way I found to play a sound on destruction would is using a sound in the instantiated prefab a couple of lectures on either on awake or through a small script - it seems to work ok?!? But is there another better way?

You could achieve this in a few ways I believe…

You could amend the Destory() method call to include a period of time before it should be destroyed, would make sense to perhaps get this from the audio being played, e.g. it’s duration, that way if you change the sound effect later on it would still work rather than with a hard code value of say 2 seconds.

You could use a coroutine, you fire the method call, it waits until a specific yield is returned, then it fires the next statement… so it may be something like “play this sound effect”, “yield = duration of sound effect”, “now destroy me”. Not really a lot different to the above but with more code.

You could consider moving all of the sound effects out of the actual objects (paddle, ball, block etc) and have another object solely responsible for playing the sound effects. Within your objects (paddle, ball, block etc) you could just make calls to the appropriate method in this new object, before calling Destroy(), thus you hand over the responsibility for the actual playing of the audio to something else.

Pros and cons perhaps with all of the above, but hopefully a few ideas for you to consider :slight_smile:

2 Likes

Aha, yes I could see how that would work. That might be a good way to go about it, keep all the sound FX in one place and use a consistent method for calling and playing them. Instead of using different methods (adding audiosource, getcomponents, audioclips) like I am doing at the moment and Play,PlayOneShot, playAtClipPoint and others and setting volume levels - leaving audiosources as 3D and setting the pan level at zero and with programmatically added audio having to set sound at 2D - it gets overwhelming quickly. Especially with me not being the sharpest tool in the shed and after many years in martial arts not helping.

2 Likes

As with anything, if it’s something your new to there will be a learning curve, I’m sure this was the case with your martial arts too :slight_smile:

You may want to do a little research on this before changing things dramatically, or, if you are using source control, create a branch in your repository before making significant changes. You could place multiple AudioSources on a GameObject, but as there is no way to name them, knowing which is for what can become a little, interesting… equally an AudioSource can play more than one clip, but there is a limit I believe, around 10-12, I think this is due to the number of channels or something for mobile devices.

As always, multiple ways to the skin the cat… bad day to be a cat! :slight_smile:

1 Like

One of those ways being a nicely sharpened katana - not that I’ve tried it myself :grinning:.

2 Likes

… cat-ana :smiley:

1 Like

ROTFL - well played sir :laughing:.

1 Like

…I’m here all week! :wink:

1 Like

What’s wrong with the method suggested in Video 87, to use the AudioClip and AudioSource.PlayClipAtPoint method? :slight_smile:
See changes in the Brick.cs file here: https://github.com/CompleteUnityDeveloper/05-Block-Breaker/commit/978c2640cc32088a8f2dff5b29f872c0befab158

1 Like

Well, if I remember correctly, he was saying that you can’t really use the audio.Play() sound on the destroyed brick, because the brick no longer exists so we need to use PlayClipAtPoint, but, we are using this to play the sound whenever the ball hits it. Then Ben said you might want to have a different sound when the brick is destroyed - I did. So how do we play a different sound when the brick is destroyed, when we are playing a sound already for when the brick is being hit? You can’t use PlayClipAtPoint just before the brick is destroyed because the brick won’t be there, and I couldn’t figure out another method of doing this - it’s probably a really simplex problem, but, I couldn’t see a solution! Then again I’ve had too many hits in the head from Karate and Jujutsu, landing on my back hard in Judo and playing Rugby, it reduces mental acuity :stuck_out_tongue:. So, I thought about it in between Jujutsu lessons, and came up with putting the different sound in the prefab, this new sound covers the PlayClipAtPoint and it not doing anything else except making cool some smoke particles, so, why not.

I’m just weird like that :stuck_out_tongue_closed_eyes:.

1 Like

Ok, now it is clear. :slight_smile:
I would use the approach Rob suggested: to create a separate object SoundEffects, create a method play(SoundClip clip) inside it and call it before the Destroy() in the Brick.
To avoid creating hundreds of sound clips I would create some public fields inside that SoundEffects class and allow to drag the clips in Editor to it. Then the Brick code could be something like this:

soundEffects.play(soundEffects.crack);
soundEffects.play(soundEffects.splash);
// etc

I will go through that myself soon, so I can post some code here when I’m done.

1 Like

I liked the approach @Rob has as well, taking ALLL the sound fx out of the equation and having a separate class handle just the sounds.

So, as you specified you could have whatever sound you wanted for any state within the game, within a reasonable limit as Rob pointed out, and call them consistently with the same code.

That’s on my TODO list! Right now as I type I have my hands full in Unity docs coming to terms with: “Is Kinematic” or not “Is Kinematic” that is the question, and also whether or not to use CollisionEnter2D or OnTriggerEnter2D for a powerup :cold_sweat:. I really dislike reading Docs :stuck_out_tongue:.

Cheers.

1 Like

Nice discussion over here guys, let us know if you got it working so further students can benefit from it.
PlayClipAtPoint instantiates a new gameobject with an audiosource that plays the clip that you addressed to it in the parenthesis, this is why you can use it in objects under destruction (when you ask it to destroy the brick, it won’t destroy this new instance of sound since it is not the same gameObject), so this code should work by adding multiple clips and then choosing which one you want to play with an if statement and PlayClipAtPoint()

1 Like

Hi guys! I’m really puting my very best trying to learn C# in unity. I think I have an alternative solution to this. I have used this pice of code (very simple, maybe way too simple to be effective coding):

This is in the Brick class script: (I did not declare a Ball object in the header by the way)

void OnCollisionEnter2D (Collision2D collision)
	{
		if (this == null) { // I'm trying to say: "If the object brick is equal to null, then call OnDestroy"
			OnDestroy (); // Calls the OnDestroy below method
		}
		bool isBreakable = (this.tag == "Breakable");
		if (isBreakable) {
			HandleHits ();
		}
	}

public void OnDestroy(){
    // I found this searching for an alternative to stop the audio for the "boing" sound of the ball, works pretty well at  least in this scenario
	GameObject.Find ("Ball").GetComponent<AudioSource> ().Stop (); 
}

void HandleHits(){
		
	timesHit++;
	int maxHits = hitSprites.Length + 1;
	if (timesHit >= maxHits) {
	Destroy (gameObject);
   // And then you just use the PlayClipAtPoint just after the destruction of the brick.
	AudioSource.PlayClipAtPoint (audio, transform.position);
	breakCount--;
	print (breakCount);
	} 
	else
	{
		LoadSprites();
	}

}

I don’t know if this is the best way to solve this, but I think it may be useful.

Cheers!

Now this code surprises me. I would’ve expected that the giving the parameter of “transform.position” in the PlayClipAtPoint would result in an error. Do you have Unity 5 installed on your computer? If so, would you be able to see if that code works when the code in “updated”? Just be sure to make a backup copy of the original code first.

I, for one, would really like to know the answer to that!

Regarding void HandleHits()

From this - “Actual object destruction is always delayed until after the current Update loop, but will always be done before rendering.”

More for @Nachockaxis

Whilst that may well work, I would suggest that not having the Destroy() method as the last statement in that code block could certainly be somewhat confusing, especially to any other developer that may look at the code, or, even yourself after a period away from it, e.g.

“Wait, I use it, then destroy it and then try to access it again - how does that work!?!” etc…

Also, for every block you are having to find the Ball and then get the AudioSource, this could well be costly.

But it is great that you are trying different approaches to resolving a problem, through refining / refactoring you will invariably create a very efficient method.

One final thought…

When the ball in the game makes the final collision with a block, the block is destroyed, what does the ball do? Does it bounce off still or does it fly through the space where the block was?

The reason I ask is because up until the destruction of the block the ball always played a sound for the rebound, when it, well, rebounded… so if the ball is still rebounding on that last collision - why wouldn’t it also play then?

1 Like

I thought that also, but, I didn’t want to say anything. But I thought the idea was indeed interesting, certainly different, and from looking at the code should work. So kudo’s for thinking outside the box! This is something I will have to revisit when I have the powerup code fully finished - shooting done, blocks destroyed, powerups initialized from ball or shot, powerup falling, collision recognized if it hits the bat.

As well as working on ball movement … argh, so many things to do!

2 Likes

Sounds like you’re motoring through really well - well done - keep the momentum going :slight_smile:

I don’t want to totally hijack the thread for something completely OT, but, I did have a little bit of help on that front :sunglasses:.

1 Like

@Rob Well, most of the methods that I showed to you guys, were used basically because I could not find anything that work for me in the moment xD (and I was starting to get desperate… I guess is the lack of experience in programming), nevertheless, I also suspected that OnDestroy() would not be the best way to solve that problem.

I forgot to mention that I’m using the “boing” sfx only when the brick is destroyed, not at every bounce with the bricks (Though I don’t think that is relevant).

And when the brick is destroyed, the ball bounces off again, like if the brick is still there.

@Vaughan_MacEgan Yes, I’m using Unity 5.2.1, and I think if I put the “AudioSource.PlayClip…” in the Update Method, I will never have the sfx of the brick triggered, because (and please correct me if I’m wrong) the script is executed secuentially in each method, so the “AudioSource.PlayClip…” is only executed when the brick is destroyed (which is exactlly what I want).

I’m really slow to learn programming (but I want to become a very good one)so maybe i’m all wrong with this explanations xD

Cheers!

Privacy & Terms