{"id":56,"date":"2022-05-24T15:26:03","date_gmt":"2022-05-24T19:26:03","guid":{"rendered":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/?p=56"},"modified":"2022-05-24T15:26:03","modified_gmt":"2022-05-24T19:26:03","slug":"day-7-easy-pong-2-collisions-sound","status":"publish","type":"post","link":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/?p=56","title":{"rendered":"Day 7: Easy Pong 2 (Collisions &#038; Sound)"},"content":{"rendered":"\n<p>Today we take a look at collisions &#8211; when objects bump into one another.  These are some of the most commonly used events because so much of our game mechanics depend on whether or not two things have touched.   We use them to determine if a hit was successful, if an enemy has touched us, if we are on the ground, if we should be making a sound.  Understanding how collision events are generated and how to interpret them is incredibly important.   And today, we will use them to generate game feedback in the form of sounds.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>It\u2019s fun to watch our ball bounce around, but we should add some sound to really make this pop.\u00a0 I\u2019ve uploaded\u00a0a few sounds to use for this demo (you can find them on Canvas), feel free to use those or a noise of your own creation.\u00a0 Just remember, the sound should be quick, and the noise should start at the very beginning of the file, otherwise you\u2019ll have a brief period of dead air and it will appear as though the sound is delayed.\u00a0 Import your sounds using\u00a0<strong>Assets > Import New Asset\u2026<\/strong>, or simply drag the files into the Assets folder.<\/p>\n\n\n\n<p>Since the only thing in our current design that should make a noise is when the ball collides with something, I\u2019ve decided to assign all noise making duties to the ball itself.&nbsp;&nbsp;<\/p>\n\n\n\n<p>In order to make sounds, an object must have the&nbsp;<strong>AudioSource Component<\/strong>&nbsp;attached to it, so I add one to the \u201cball\u201d object.&nbsp; When you add this component, you will notice an empty&nbsp;<strong>AudioClip<\/strong>&nbsp;property which is the audio file to be played \u2013 leave this empty, as we will fill it later using our script.You will also notice that, by default,&nbsp;<strong>Play On Awake<\/strong>&nbsp;is checked.&nbsp; De-select this option, as we will control when we want things to play.<\/p>\n\n\n\n<p>We want our clip to play whenever the ball hits the paddle, so we need to figure out when that event occurs.&nbsp; To do this, we will test every collision that the ball experiences.&nbsp; &nbsp;<\/p>\n\n\n\n<p>Whenever a collision occurs, the game generates a&nbsp;<strong>Collision Event<\/strong>.&nbsp; We can set our scripts to listen for these events and use them to perform actions, in this case playing our sound.&nbsp; Add a new script to the Ball object (I called mine&nbsp;<strong>BallScript<\/strong>.&nbsp; &nbsp;Add the following code for the variable declaration and&nbsp;<strong>Start ( )<\/strong>&nbsp;function:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">private AudioSource audio;\n\/\/ Start is called before the first frame update\nvoid Start()\n{\n    audio = GetComponent&lt;AudioSource>();\n}<\/pre>\n\n\n\n<p>Just like we created a&nbsp;Rigidbody typed variable, here we create an&nbsp;<strong>AudioSource<\/strong>&nbsp;type variable and assign it using&nbsp;<strong>GetComponent&lt;AudioSource&gt; ( )<\/strong>.&nbsp; &nbsp; Notice, however, that before we used a reference to a separate game object (\u201cballobject\u201d) as our source, and here we simply use \u201cthis\u201d.&nbsp;&nbsp;<strong>This<\/strong>&nbsp;gives us access to the object which it is running through.&nbsp; It is self-referential, so no extra association steps required.<\/p>\n\n\n\n<p>Our next step is to identify when a collision occurs, then look to see if we have hit the right&nbsp;<em>type<\/em>&nbsp;of collision.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">private void OnCollisionEnter(Collision collision)\n{\n    if(collision.gameObject.tag == \"Wall\")\n    {\n        audio.Play();\n    }\n}<\/pre>\n\n\n\n<p><strong>OnCollisionEnter ( )<\/strong>&nbsp;runs when a collision event occurs involving this object \u2013 meaning that this object\u2019s collider has initiated contact with another object\u2019s collider. It is only called one time per collision.&nbsp; When the objects separate \/ stop touching, there is an&nbsp;<strong>OnCollisionExit ( )<\/strong>&nbsp;message that will be called.&nbsp; If objects remain in contact,&nbsp;<strong>OnCollisionStay ( )<\/strong>&nbsp;messages will issue once per frame.<\/p>\n\n\n\n<p>Our collision event has a parameter that is of the type&nbsp;<strong>Collision<\/strong>, which here we assign to a variable \u201ccollision\u201d.&nbsp; This Collision object contains data about the collision, such as the point of contact, the object that was hit, and the relative velocity of the two objects.&nbsp; Here we test the&nbsp;<strong>Tag<\/strong>&nbsp;of the other object against a known value, and if it returns as true, we tell the audioSource to run the&nbsp;<strong>Play( )&nbsp;<\/strong>command. &nbsp;&nbsp;<\/p>\n\n\n\n<p>Unity projects have a few pre-existing tags that you can use, but I recommend creating your own.<\/p>\n\n\n\n<p>Select your paddle prefab, and in the inspector look for the&nbsp;<strong>Tag<\/strong>&nbsp;dropdown near the top.&nbsp; In there, select&nbsp;<strong>Add New Tag\u2026<\/strong>&nbsp;and add a new named tag.&nbsp; Call this one \u201cWall\u201d.&nbsp; Now select your paddle again and from the dropdown give it the tag&nbsp;<strong>Wall<\/strong>.&nbsp; &nbsp; Now play your game and you should get a satisfying \u201cbonk\u201d noise when your ball hits a wall.  Let&#8217;s look a little closer at the Audio Source component:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/courses.ideate.cmu.edu\/53-353\/m2020\/wp-content\/uploads\/2020\/05\/image-4.png\" alt=\"\" class=\"wp-image-60\"\/><\/figure><\/div>\n\n\n\n<p>As the name suggests, this component makes our object the &#8220;source&#8221; of a bit of audio, by having it emit a sound.   The sound that will be emitted is defined using the <strong>AudioClip<\/strong> setting, which gives us access to the <strong>AudioSource.clip<\/strong> property.   Once a clip has been set, we can use <strong>AudioSource.Play( )<\/strong> to play the sound, and <strong>AudioSource.Stop( )<\/strong> to stop it.  <\/p>\n\n\n\n<p>But the AudioSource is only one half of the equation.  We also need to have an <a href=\"https:\/\/docs.unity3d.com\/Manual\/class-AudioListener.html\"><strong>AudioListener<\/strong> <\/a>in our scene, to act as our &#8220;ears&#8221;.   By default, the AudioListener is added as component on the Main Camera.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/courses.ideate.cmu.edu\/53-353\/m2020\/wp-content\/uploads\/2020\/05\/image-6.png\" alt=\"\" class=\"wp-image-62\"\/><figcaption>That&#8217;s it.  No properties  to mess around with.  Just a single line in your inspector.<\/figcaption><\/figure><\/div>\n\n\n\n<p>The reason this configuration makes sense is that your Main Camera is usually your best representation of where you as the observer are in relation to the world of the game itself.  The <strong>Spatial<\/strong> slider in your AudioSource component allows you to set the sound to be:<\/p>\n\n\n\n<ul><li><strong>&#8220;3D&#8221;<\/strong> &#8211; meaning that the sound is interpreted as emitting from that point in space in relation to your camera.  Volume is attenuated based upon distance to the source, and the balance between your speakers is based upon the heading. (Unity&#8217;s audio source is set to Stereo by default, but can support other configurations such as Mono or 5.1 Surround Sound.)   This is useful for <strong>diegetic<\/strong> sounds &#8211; those that are happening inside our game like enemy footsteps or a character voice calling to you.<\/li><li><strong>&#8220;2D&#8221;<\/strong> &#8211; meaning that the sounds emanates from everywhere, or according to the balance set in the source such as through Stereo Pan. This is useful for non-diegetic sounds &#8211; those that are not implied to occur inside the game world such as background music, or voice-overs, or UI sounds.  <\/li><li><strong>Blend<\/strong> &#8211; the slider lets you adjust your sound to a combination of these.  This is especially useful if you want something to always be audible at a certain level even if the source is distant.  Important character dialogue may fall into this category.<\/li><\/ul>\n\n\n\n<p>One important note about an AudioSource &#8211; it can only play one clip at a time.  If you have multiple clips that need to play simultaneously, you need multiple AudioSources, which means multiple objects.<\/p>\n\n\n\n<p>In a future class, I will show you methods for creating a more sophisticated Sound Manager, but for now, we are going to make our different sounds by switching the clip on our ball&#8217;s AudioSource.<\/p>\n\n\n\n<p>In our BallScript.cs script, we declare the following public <strong>AudioClip<\/strong> variables.  This will create three audio clip slots in our script component in the Inspector, which we will fill with sounds from our Assets folder.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public AudioClip wallSound;\npublic AudioClip paddleSound;\npublic AudioClip deathSound;<\/pre>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/courses.ideate.cmu.edu\/53-353\/m2020\/wp-content\/uploads\/2020\/05\/image-7.png\" alt=\"\" class=\"wp-image-63\"\/><\/figure><\/div>\n\n\n\n<p>Next, we create a script to play the Paddle sound (as opposed to the default Wall sound)<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">private void MakeWallSound()\n{\n    audio.Stop(); \/\/ stop the audio if it is already playing\n    audio.clip = wallSound; \/\/ set the new clip\n    audio.Play(); \/\/ play the new clip\n}<\/pre>\n\n\n\n<p>Here we first issue a&nbsp;<strong>Stop( )<\/strong>&nbsp;command, in case something else is already playing.&nbsp; Next we set the&nbsp;<strong>clip<\/strong>&nbsp;for this AudioSource to be the sound we wish it to make, in this case the paddle sound.&nbsp; Finally, we issue the&nbsp;<strong>Play( )<\/strong>&nbsp;command which will cause the sound to start playback at the beginning.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">private void OnCollisionEnter(Collision collision)\n{\n    if (collision.gameObject.tag == \"Wall\")\n    {\n        \/\/ make the paddle sound\n        MakeWallSound();\n    } \n}<\/pre>\n\n\n\n<p>Next we add similar functions for the paddle and back wall sounds.   For these functions, we will use another method of AudioSource &#8211; <strong><a href=\"https:\/\/docs.unity3d.com\/2017.3\/Documentation\/ScriptReference\/AudioSource.PlayOneShot.html\">PlayOneShot( )<\/a><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"false\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">private void MakePaddleSound()\n{\n    audio.PlayOneShot(paddleSound); \/\/ play the paddle sound once\n}\npublic void MakeDeathSound()\n{\n    audio.PlayOneShot(deathSound); \/\/ play the death sound once\n}<\/pre>\n\n\n\n<p>PlayOneShot( ) will load and play the included clip one time and immediately stop once it is complete.  It is important to note that this will NOT change the value of our AudioSource.clip.  If you ran the <strong>Play( )<\/strong> command after <strong>PlayOneShot( )<\/strong> the audio clip playing would be the same clip that was loaded before.<\/p>\n\n\n\n<p>Finally, just for fun, we added increase in the <strong>Rigidbody.velocity<\/strong> of our ball object so that the ball speeds up each time it is hit by a paddle, and we also increased the value of <strong>AudioSource.pitch<\/strong> which will make the sounds move to a higher tone and reinforce that effect of more speed.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<pre class=\"wp-block-preformatted\">BallScript.cs<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\n\npublic class BallScript : MonoBehaviour\n{\n    private AudioSource audio;\n    private Rigidbody rb;\n\n    public AudioClip wallSound;\n    public AudioClip paddleSound;\n    public AudioClip deathSound;\n\n    \/\/ Start is called before the first frame update\n    void Start()\n    {\n        audio = GetComponent&lt;AudioSource>();\n        rb = GetComponent&lt;Rigidbody>();\n    }\n\n    private void OnCollisionEnter(Collision collision)\n    {\n        if (collision.gameObject.tag == \"Wall\")\n        {\n            MakeWallSound();\n\n        } else if (collision.gameObject.tag == \"Paddle\")\n        {\n            MakePaddleSound();\n\n            if (audio.pitch &lt;= 2.0f) { \n                \/\/ increase the pitch\n                audio.pitch += 0.1f;\n\n                \/\/ increase the speed\n                rb.velocity *= 1.1f;\n            }\n\n        } else if (collision.gameObject.tag == \"BackWall\")\n        {\n            \/\/ audio.pitch = 1.0f;\n            \/\/ MakeDeathSound();\n        }\n\n    }\n\n    private void MakeWallSound() \n    {\n        audio.PlayOneShot(wallSound);\n    }\n\n    private void MakeDeathSound()\n    {\n        audio.PlayOneShot(deathSound);\n    }\n\n    private void MakePaddleSound()\n    {\n        audio.PlayOneShot(paddleSound);\n    }\n\n\n}\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p><a class=\"more-link\"  href=\"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/?p=56\"><span class=\"more-text\"><\/span><\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"greenlet_layout":[]},"categories":[6],"tags":[],"_links":{"self":[{"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/index.php?rest_route=\/wp\/v2\/posts\/56"}],"collection":[{"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=56"}],"version-history":[{"count":3,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/index.php?rest_route=\/wp\/v2\/posts\/56\/revisions"}],"predecessor-version":[{"id":59,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/index.php?rest_route=\/wp\/v2\/posts\/56\/revisions\/59"}],"wp:attachment":[{"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=56"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=56"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2022\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=56"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}