{"id":54,"date":"2026-09-02T15:36:40","date_gmt":"2026-09-02T15:36:40","guid":{"rendered":"https:\/\/courses.etc.cmu.edu\/53-353\/?p=54"},"modified":"2026-09-02T15:36:40","modified_gmt":"2026-09-02T15:36:40","slug":"lesson-3-pong-the-easy-way","status":"publish","type":"post","link":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/2026\/09\/02\/lesson-3-pong-the-easy-way\/","title":{"rendered":"Lesson 3: Pong (the easy way)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This week, we replicate last week&#8217;s accomplishments in a matter of minutes by using the tools that Unity affords us.  This frees up extra time to build out even more of our game, and allow us to start working on the logic of moving through the stages of gameplay.  This week we work with Physics, Collisions, Sounds, Scripting Prefabs, Enumeration, Coroutines, and take an early look at Unity&#8217;s UI system.  Let&#8217;s jump in!<\/p>\n\n\n\n<!--more-->\n\n\n\n<h3 class=\"wp-block-heading\">Part 1: Starting Over with Rigidbody Physics<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Our first step for today was to recreate our efforts from last week with a more efficient solution, Unity&#8217;s built-in Physics system.   We used <strong>Save Scene As&#8230; <\/strong> to generate a new version of this same object, and removed our HardPong script from the main camera.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Physics in Unity rely on three main components.&nbsp; The \u201cRigidbody\u201d, which gives control of the object over to the physics system and allows forces such as collisions and gravity to apply;&nbsp; the \u201cCollider\u201d:&nbsp; a procedural or mesh volume that determines the physical \u201cshape\u201d of an object for collision detection; and the Physic Material which defines the physical properties of objects and determines how they should react during collisions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In Unity, most meshes (including all primitive objects) come with a Collider component already defined.&nbsp; This allows objects that are controlled by the physics systems to react and respond to the rest of our world, without having to subject them to the arduous calculations that would be required if they were moveable objects, each subject to forces and gravity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In our case, we only need to apply physics to one object here, our ball.&nbsp; We do this by adding a&nbsp;<strong>Rigidbody component<\/strong>, available by selecting&nbsp;<strong>Add Component &gt; Physics &gt; Rigidbody<\/strong>.&nbsp; As soon as we add this, we can run our game and if our ball is located outside of our plane, we see it fall away very slowly.&nbsp; (Or at least, it feels slow.&nbsp; The speed here is accurate as Unity\u2019s default gravity accelerates at 9.8 m\/s<sup>2<\/sup>&nbsp;just like real life.&nbsp; The \u201cslow\u201d here comes from our expectations of size \u2013 remember that our ball is 3 units in diameter, meaning it is ~10 feet high \u2013 but we expect it to be small like a ping pong ball and so our visual perception is that it is falling slowly).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now, reposition the ball to the origin point (0,0,0) and run the game again.&nbsp; Hmm\u2026 it just sits there.&nbsp; And of course it does \u2013 we haven\u2019t done anything to make it move.&nbsp; Previously, we had to tell the ball to move in every frame.&nbsp; This time, we are going to give the ball one big push and let physics do the rest.&nbsp; Time to start a new script, but this time I placed it on an empty game object I created&nbsp;<strong>(GameObject &gt; Create Empty).<\/strong>&nbsp; I named the object \u201cGameManager\u201d and called this script&nbsp;<strong>EasyPong<\/strong>, but you can name it whatever you want.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n    public GameObject ballObject;\n    private Rigidbody ballRigidbody;\n    public float force;\n    public Vector3 direction;\n\n    \/\/ Start is called before the first frame update\n    void Start()\n    {\n        ballRigidbody = ballObject.GetComponent&lt;Rigidbody&gt;(); \/\/ assign the rigidbody\n        direction.Normalize();  \/\/ make the direction vector a heading \n        ballRigidbody.AddForce(direction * force);\n    }\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">In this script, we declare a public GameObject variable so that we can make the assignment of the ball object to our script through the Inspector.&nbsp; Then we declare a private&nbsp;<strong>Rigidbody<\/strong>&nbsp;variable which will get the ball\u2019s Rigidbody component using the appropriately named <strong>GetComponent&lt;Rigidbody&gt; ( )<\/strong>.&nbsp; &nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At the end of our <strong>Start( ) <\/strong>function we call the&nbsp;<strong>AddForce( )&nbsp;<\/strong>command to give our ball\u2019s rigidbody a push.&nbsp; &nbsp;Our variables for \u201cforce\u201d and \u201cdirection\u201d are also made public, so that we can adjust the force of that push in our Inspector.&nbsp; You might soon notice that your force requires a significantly high value in order to set the ball in motion.   This is because there are different &#8220;force modes&#8221; that describe the manner which the force is being applied to the object.  There are important distinctions to these, so it is important to understand when you might want to choose a particular option.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>ForceMode <\/strong>is an enumeration of the options for applying a force to an object.  Some use the object mass, while others treat all objects equally (like the accelerative force of gravity).   The default option for <strong>AddForce <\/strong>is <strong>ForceMode.Force<\/strong>, where mass matters, and the force is applied over time, meaning that a single call of AddForce only sends a fraction of the value based upon the short time of frame.  For our purposes, it is best to use an Instant force like <strong>ForceMode.Impulse<\/strong> or <strong>ForceMode.VelocityChange<\/strong>.  <\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>ForceMode Options<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">From the Unity Scripting API<\/p>\n<cite><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/ForceMode.Force.html\">Force<\/a><br>Add a continuous force to the rigidbody, using its mass.<br><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/ForceMode.Acceleration.html\">Acceleration<\/a><br>Add a continuous acceleration to the rigidbody, ignoring its mass.<br><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/ForceMode.Impulse.html\">Impulse<\/a><br>Add an instant force impulse to the rigidbody, using its mass.<br><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/ForceMode.VelocityChange.html\">VelocityChange<\/a><br>Add an instant velocity change to the rigidbody, ignoring its mass.<\/cite><\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">We declare that like this: <code>ballRigidbody.AddForce(direction * force, ForceMode.Impulse);<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When we hit play, the ball starts moving.&nbsp; It collides with the paddle, then sort of sits there.&nbsp; If you watch this through the side view (I recommend selecting the ball object so that you can use the collision sphere widget to see how it is moving) you\u2019ll notice it is rolling over to the paddle, then gaining some friction and rolling slightly up the side of the paddle before falling down and coming to rest.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Obviously this is not the behavior we want, so we need to make a few changes.&nbsp; First, we should restrict the motion of our ball to the XZ plane to make sure we don\u2019t fly off the board. Do this by setting the&nbsp;<strong>Constraints<\/strong>&nbsp;in the Rigidbody controller of the ball.&nbsp; While you are there, restrict all rotation as well.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"479\" height=\"576\" src=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image.png\" alt=\"\" class=\"wp-image-510\" style=\"width:381px;height:auto\" srcset=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image.png 479w, https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-249x300.png 249w\" sizes=\"auto, (max-width: 479px) 100vw, 479px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Next, we need to control how our object interacts with others.&nbsp; We do this by creating a&nbsp;<strong>Physic Material&nbsp;<\/strong>(in&nbsp;<strong>Assets &gt; Create &gt; Physic Material<\/strong>).&nbsp;&nbsp;&nbsp;Friction is what made the ball move, so we want to get rid of both&nbsp;<strong>Dynamic Friction<\/strong>&nbsp;(the friction that slows objects in motion) and the&nbsp;<strong>Static Friction<\/strong>&nbsp;(the friction that prevents objects from moving in the first place).&nbsp; Set both of these values to&nbsp;<strong>0<\/strong>.&nbsp; Next, set our \u201cBounciness\u201d to&nbsp;<strong>1<\/strong>, and our \u201cFriction Combine\u201d to&nbsp;<strong>Minimum<\/strong>&nbsp;and our \u201cBounce Combine\u201d to&nbsp;<strong>Maximum<\/strong>.&nbsp; The \u201cCombines\u201d are used to determine how to calculate these forces when multiple materials are present.&nbsp; \u201cMinimum\u201d uses the smaller value of the two, \u201cMaximum\u201d uses the larger.&nbsp; \u201cAverage\u201d and \u201cMultiply\u201d apply a combination of both.&nbsp; Apply this Physic Material to the ball by dragging it into the&nbsp;<strong>Material<\/strong>&nbsp;slot in the&nbsp;<strong>Sphere Collider<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"484\" height=\"236\" src=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-1.png\" alt=\"\" class=\"wp-image-511\" style=\"width:376px;height:auto\" srcset=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-1.png 484w, https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-1-300x146.png 300w\" sizes=\"auto, (max-width: 484px) 100vw, 484px\" \/><figcaption class=\"wp-element-caption\">This is the ultimate bouncy-slidey ball!<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Now when we hit play, our ball slides smoothly from paddle to paddle.&nbsp; Changing our direction lets us try a few more scenarios.&nbsp; Looking good!&nbsp; Now all we need to do is move the paddles<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Part 2: Prefabs and Overrides<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For our paddle object, we create a <strong>Prefab<\/strong> object by dragging one of our paddles into the <strong>Assets<\/strong> folder.  This converts it into a saved object that we can Instantiate as a clone in our scene.  We can make changes to the instances of a prefab that exist in our scene, or we can make edits to the original Prefab object that will propagate to the instances in our scene, unless the instance in the scene has modified that property or component.  Modifications to the scene instances are called <strong>Overrides<\/strong>, and you can use the Inspector to visualize the difference between instance and source, and you can revert the instance or push your change back to the prefab if you choose to do so.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Prefabs are especially useful when we want to create instances of objects, and in this case we will use it to create two paddles that respond to input, rather than creating a master script to handle all inputs.&nbsp; This script we create will perform the same task, using the&nbsp;<strong>Update( )&nbsp;<\/strong>method to test to see whether a particular set of buttons is being pressed, and then move the object accordingly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, I define two public strings, to hold the key codes for the keyboard buttons I intend to use for \u201cup\u201d and \u201cdown\u201d motion.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\npublic string upButton;\npublic string downButton;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Next I define two private variables \u2013 one to regulate the speed of the paddles, and the other to create an offset value to restrict movement beyond a certain amount.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\nprivate float speed = 50.0f;\nprivate float offset = 18.0f;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Then I edit the&nbsp;<strong>Update( )<\/strong>&nbsp;method to include the following code:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\nvoid Update()\n{\n    Vector3 currentPosition = transform.position;\n\n    if (Input.GetKey(upButton))\n    {\n        currentPosition.z += speed * Time.deltaTime;\n    }\n\n    if (Input.GetKey(downButton))\n    {\n        currentPosition.z -= speed * Time.deltaTime;\n    }\n\n    currentPosition.z = Mathf.Clamp(currentPosition.z, -offset, offset);\n\n    transform.position = currentPosition;\n\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Walking through this line by line, first we get the position of the paddle by creating a&nbsp;<strong>Vector3&nbsp;<\/strong>&nbsp;called&nbsp;<strong>currentPosition<\/strong>&nbsp;and assign it a value of \u201ctransform.position\u201d which is shorthand for \u201cthis.transform.position\u201d.&nbsp; This returns the current XYZ coordinates of the object.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, we test to see if the \u201cupButton\u201d and \u201cdownButton\u201d keys are pressed.\u00a0 We test both, using separate if statements, to make sure that we capture situations where both up and down are pressed at the same time.\u00a0 (If they are, their movements will cancel each other out and the paddle will remain still.)\u00a0 \u00a0 If we determine one of the buttons to be pressed, we either increase or decrease the \u201cz\u201d value of the position by an increment of\u00a0<strong>(<\/strong><strong>speed * Time.deltaTime).\u00a0 \u00a0<\/strong>If you are curious why we do not just multiply by speed, it is because this script works like our ball and paddle movement in the previous week &#8211; we are manually moving every frame and framerates are not steady, so &#8220;deltaTime&#8221; converts our &#8220;speed&#8221; value into a distance that would be traveled at that speed.\u00a0 <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Closing this out, we have this line:&nbsp;<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\ncurrentPosition.z = Mathf.Clamp(currentPosition.z, -offset, offset);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Here we introduce the&nbsp;<strong>Mathf<\/strong>&nbsp;library (a library of math functions for floating point numbers) and the&nbsp;<strong>Clamp<\/strong>&nbsp;method, which allows us to set a minimum and maximum value and see if our value falls within that range, and if not returns one of those values instead.&nbsp; Now the paddle position will be constrained to move no farther than \u201coffset\u201d number of units from the 0 position.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, we set\u00a0<strong>transform.position\u00a0<\/strong>to be equal to currentPosition. Note that we have to pass this value back \u2013 transform.position is not an object that can be held onto as a reference, it is a one-time get or set.   Additionally, this can only be received or passed as a <strong>Vector3<\/strong> type, because that is what it is.  We cannot set the individual parts of the <strong>struct<\/strong>, so trying to set &#8220;transform.position.x &#8221; directly will return an error.   For our script we must get it, adjust it, and then set it to our updated Vector3. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now in your paddles, assign the left paddles buttons to \u201cw\u201d and \u201cs\u201d, and the right paddle to \u201cup\u201d and \u201cdown\u201d (which translate to the up and down arrows on the keypad), and we should be good to go.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Part 3: Detecting collisions and making noise<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">It\u2019s fun to watch our ball bounce around, but we should add some sound to really make this pop.\u00a0 I\u2019ve uploaded\u00a0<a href=\"https:\/\/cmu.box.com\/s\/r8r7ogewy0addp33bof7xuhi5dfr0e4g\" data-type=\"post\">a few sounds to use for this demo<\/a>, 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 sound using\u00a0<strong>Assets > Import New Asset\u2026<\/strong>, or simply drag the files into the Assets folder.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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 class=\"wp-block-paragraph\">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 class=\"wp-block-paragraph\">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 class=\"wp-block-paragraph\">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<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\nprivate AudioSource audio;\n\n\/\/ Start is called before the first frame update\nvoid Start()\n{\n    audio = GetComponent&lt;AudioSource&gt;();\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">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 class=\"wp-block-paragraph\">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<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\nprivate void OnCollisionEnter(Collision collision)\n{\n    if(collision.gameObject.tag == &quot;Wall&quot;)\n    {\n        audio.Play();\n    }\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><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 class=\"wp-block-paragraph\">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 class=\"wp-block-paragraph\">Unity projects have a few pre-existing tags that you can use, but I recommend creating your own.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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<figure class=\"wp-block-image aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"473\" height=\"488\" src=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-2.png\" alt=\"\" class=\"wp-image-512\" style=\"width:303px;height:auto\" srcset=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-2.png 473w, https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-2-291x300.png 291w\" sizes=\"auto, (max-width: 473px) 100vw, 473px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">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>Audio Resource<\/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 class=\"wp-block-paragraph\">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<figure class=\"wp-block-image aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"490\" height=\"276\" src=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-4.png\" alt=\"\" class=\"wp-image-514\" style=\"width:350px;height:auto\" srcset=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-4.png 490w, https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-4-300x169.png 300w\" sizes=\"auto, (max-width: 490px) 100vw, 490px\" \/><figcaption class=\"wp-element-caption\">Just a big old empty component.  Actual audio settings (like global volume and output speaker modes) can be found in the Project Settings<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">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 class=\"wp-block-list\">\n<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>\n\n\n\n<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>\n\n\n\n<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>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">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 class=\"wp-block-paragraph\">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 class=\"wp-block-paragraph\">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<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n    public AudioClip wallSound;\n    public AudioClip paddleSound;\n    public AudioClip deathSound;\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"488\" height=\"134\" src=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-5.png\" alt=\"\" class=\"wp-image-515\" style=\"width:372px;height:auto\" srcset=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-5.png 488w, https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2024\/09\/image-5-300x82.png 300w\" sizes=\"auto, (max-width: 488px) 100vw, 488px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Next, we create a script to play the Paddle sound (as opposed to the default Wall sound)<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n    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    }\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">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<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n    private void OnCollisionEnter(Collision collision)\n    {\n        if (collision.gameObject.tag == &quot;Wall&quot;)\n        {\n            \/\/ make the paddle sound\n            MakeWallSound();\n        } \n    }\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">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<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n    private void MakePaddleSound()\n    {\n        audio.PlayOneShot(paddleSound); \/\/ play the paddle sound once\n    }\n\n    public void MakeDeathSound()\n    {\n        audio.PlayOneShot(deathSound); \/\/ play the death sound once\n    }\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">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 class=\"wp-block-paragraph\">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<h3 class=\"wp-block-heading\">Part 4: The Finite State Engine<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Right now our \u201cgame\u201d isn\u2019t much of a game yet. We are lacking the basic components of a game such as rules and objectives. We need to add the steps and stages and rules and mechanics that make this a game of Pong! rather than a really basic screensaver.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The goal of our game is for one player to win, which they do by scoring more points than their opponent. This objective implies that we need a method by which to score points, and multiple opportunities for players to score. A score is registered when the ball gets past and hits the wall behind the opposing player\u2019s paddle. In order to have multiple attempts, we need to create \u201crounds\u201d of playing through our core bouncing ball mechanic. Each round starts with the ball reset to the center, and ends when a score is registered.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Given that, we can generate a diagram of the \u201cflow\u201d of our game as such:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"798\" height=\"740\" src=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2023\/09\/image.png\" alt=\"\" class=\"wp-image-58\" style=\"width:559px;height:518px\" srcset=\"https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2023\/09\/image.png 798w, https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2023\/09\/image-300x278.png 300w, https:\/\/courses.etc.cmu.edu\/53-353\/wp-content\/uploads\/2023\/09\/image-768x712.png 768w\" sizes=\"auto, (max-width: 798px) 100vw, 798px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This is an example of a&nbsp;<strong>Finite State Machine<\/strong>&nbsp;\u2013 a model of our the logic of our game, where our game will inhabit only one state at a time, and certain conditions must be met to move or transition from state to state.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In our model, we can see the need for a few particular stages as we progress. First we have to set up or initialize a new game. This is where we will set our initial score of 0-0 and initialize all of the objects back into their start state. Next we have to set up the individual round. This state is separate from the initialize game state because we will return to this frequently as each new round begins. Here we expect to see behaviors like putting the ball back at the origin, and resetting any modifications that we made to the pitch of the sound or speed of the ball. Once the round begins, we enter the actual gameplay state, which continues until one side scores. Once a point is scored, we need to register that event and determine if someone has won the game, or if we need to reset our board and start a new round. If the objective number of points have been scored, it\u2019s time to declare a winner and move to a \u201cgame over\u201d state.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It is important to note that this is an abstract machine \u2013 we will use this model to code the states and transitions and object behaviors, but these components will be assembled through composite parts so that the preferred action occurs, rather than coding everything into one giant instruction set in one particular function.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Enumeration<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Since we will share the responsibility for moving between states across the objects in our scene, we need a reliable method to get and set our current state. Traditionally one might use a string to hold a value so that it hold an easy to read value, or one might use an integer and assign values to each index so that the lookup is fast. Instead, we will use a method that combines the advantages of both \u2013&nbsp;<strong>Enumeration<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Enumeration lets us define all of the possible values for a set, which fits very well when working with a finite number of states. An commonly given example of this would be to create an enumerated set of directions (north, east, south, west) so that the values are plain English, but are also the only possible values for the type.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In our case, we want to define some states for our game \u2013 setting up the game, getting a round ready, the actual gameplay itself, and finally the game over state. We define our enumeration by declaring a public\u00a0<strong>enum<\/strong>\u00a0outside of the <strong>GameManager <\/strong>class declaration in our project. This will make the type available to use across all scripts in our scene.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; highlight: [5]; title: ; quick-code: false; notranslate\" title=\"\">\nusing System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\n\npublic enum GameState { None, PreRound, Playing, PostRound, GameOver};\n\npublic class GameManager: MonoBehaviour\n{\n    public GameObject ballObject;\n    private Rigidbody ballRigidbody;\n    ...\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Now that I\u2019ve declare the enumerations, I can declare my own variable in the class and by default put it in the \u201cSetup\u201d state\u2026<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n    \/\/ define my gamestate variable\n    public GameState state = GameState.None;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Now we have something that we can test. Let\u2019s hop over to the PaddleScript  to see an example of how we can use this\u2026<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Last time, we left the instructions for moving the paddle inside of the Update( ) method, meaning that it would be called once per frame. But paddles should only move while the game is in play, not before or after the round. We want to constrict the paddle movement to only occur when the game state is set to \u201cplaying\u201d.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, we take the contents of the Update( ) method and move them into a new void function called&nbsp;<strong>MovePaddle( )<\/strong>. We rewrite Update( ) to feature a check to see if the game state is set to \u201cGameState.Playing\u201d, and if it is, we run the MovePaddle( ) command.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n    void Update()\n    {\n        if (game.state == GameState.Playing)\n        {\n            MovePaddles();\n        }\n    }\n\n    private void MovePaddles()\n    {\n        Vector3 currentPosition = transform.position; \/\/ get my position\n\n        if (Input.GetKey(upButton))\n        {\n            currentPosition.z += speed * Time.deltaTime;\n        }\n\n        if (Input.GetKey(downButton))\n        {\n            currentPosition.z -= speed * Time.deltaTime;\n        }\n\n        currentPosition.z = Mathf.Clamp(currentPosition.z, -offset, offset);\n\n        transform.position = currentPosition;\n    }\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">If we try to run this now, Unity will be cross with us and we will get a Null Reference Exception, because we have no connection to the Game Manager object reference to the game manager to access the \u201cstate\u201d variable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We could build a public GameObject variable and use our drag-and-drop method to connect the Game Manager object, but let\u2019s try another useful method \u2013&nbsp;<a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/GameObject.Find.html\">the&nbsp;<\/a><strong><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/GameObject.Find.html\">Find( )<\/a><\/strong><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/GameObject.Find.html\">&nbsp;command<\/a>.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n    private EasyPong gameManager;\n\n    \/\/ Start is called before the first frame update\n    void Start()\n    {\n        \/\/ get the game manager object\n        game = GameObject.Find(&quot;GameManagerObject&quot;).GetComponent&lt;GameManager&gt;(;\n    }\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Here, we define a private object \u2013 an <strong>GameManager <\/strong>variable which we name <strong>game<\/strong> &#8211; this cleverly named variable will hold the reference to our Game Manager&#8217;s GameManager script. This is because we are specifically looking for the script component attached to the \u201cGameManagerObject\u201d object, and we need a place to hold it. The script is of the class GameManager, so the type we declare here has to match that.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Inside of the Start( ) method, we start to assign gameManager with <strong>GameObject.Find(\u201cGameManagerObject\u201d)<\/strong>, which\u00a0will return the first object in the scene that it finds with a matching name, and then we add <strong>GetComponent&lt;GameManager>()<\/strong> on that result, and now we have direct access into the public variables and methods of that script.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Armed with this new information, we update our Update( ) \u201cif\u201d statement to read as follows:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\nif (game.state == GameState.Playing)\n<\/pre><\/div>\n\n\n<p class=\"has-very-light-gray-background-color has-background has-small-font-size wp-block-paragraph\"><strong>NOTE:<\/strong><br>Although we used a single variable here, we could have also done this by declaring a GameObject variable that we find, and then a second variable that uses GetComponent&lt;&gt; on the object we just retrieved.  Both are valid methods, ours here just shortened the trip.<\/p>\n\n\n\n<p class=\"has-very-light-gray-background-color has-background has-small-font-size wp-block-paragraph\"><strong>NOTE:<\/strong><br>You may have noticed the&nbsp;<strong>Debug.Log( )<\/strong>&nbsp;commands also used here. This is a function that allows you to print a message directly to the Log and the Console Window for debugging purposes. I tend to have these scattered throughout my code as they are useful for tracking down whether or not a particular function is being called, and what values are set at different locations. Note the use of the \u201c+\u201d symbol to concatenate a string with another value.&nbsp;<a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Debug.Log.html\">More on Debug.Log( )\u2026<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now go back to Unity and hit play to see what happens. If you have done this correctly, nothing should occur \u2013 the paddles should stay in the same place and be unresponsive to key presses. This is because our <strong>currentState <\/strong>value is not set to <strong>GameState.Playing<\/strong>.   Because we made this public, we can change the setting in our Editor.  You will see a dropdown for the Game State &#8211; set that to &#8220;Playing&#8221; and click on your game window and now your paddles should move.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Part 5:  Moving Through States<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Initializing the Game<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Most games that we play in life will require some sort of preparation before the game itself can begin.  Bases must be placed, cards must be dealt, game pieces must be distributed.   Our game is no different &#8211; before we can play our game, we need to set the objects and attributes and place them into a ready state for play to begin.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In order for our game to have a winner, we need to be able to keep score.  We also should have some definition of what &#8220;winning&#8221; is.  (Here it will be the first player to reach 3 points.)<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n\/\/ score tracking\nprivate int playerOneScore, playerTwoScore;\n\nprivate int scoreLimit = 3;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Here I set two float values for the player scores (putting both declarations on one line with a comma will create two variables of the same time) and a float variable the score limit. Our player one and two scores I will set in our <strong>Start( )<\/strong> menu because these could reset again, for instance when we restart the game.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\nvoid Start()\n{\n    ballRigidbody = ballObject.GetComponent&lt;Rigidbody&gt;(); \/\/ assign the rigidbody\n\n    \/\/ initialize the score\n    playerOneScore = 0;\n    playerTwoScore = 0;\n\n    \/\/ get the start position of the ball\n    ballStartPosition = ballObject.transform.position;\n\n    \/\/ set the game state\n    state = GameState.PreRound;\n\n    \/\/ start the first round\n    InitializeRound();\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">In our start we reset the scores to 0, fetch the position of the ball object (so that we have a reference point to use once a round is over), and make sure the GameState is at &#8220;PreRound&#8221;.  Finally, move to our next stage &#8211; starting an individual round, which we do with our new method <strong>InitializeRound( )<\/strong><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Starting the Round<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The start of a new round, whether it is the first round or comes after a scoring event, consists of two primary steps:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Resetting the ball to the start position<\/li>\n\n\n\n<li>Starting the round by pushing the ball into motion<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">To handle this, we created three new functions &#8211; <strong>InitializeRound( ), ResetBall( ), <\/strong>and <strong>StartBall( )<\/strong>.   InitializeRound( ) will handle our initial setup of a new round. Here we should start in the \u201csetup\u201d stage. It will call ResetBall( ) for us, which will move the ball back to the origin, and reset any other modifications we made such as pitch modulation.  Finally StartBall( ) will put the ball into motion.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\nprivate void InitializeRound()\n{\n    \/\/ set the state\n    state = GameState.PreRound;\n\n    \/\/ Reset Ball\n    ResetBall();\n\n    \/\/ Start Ball\n    StartBall();\n}\n\nprivate void ResetBall()\n{\n    \/\/ make sure we have control of the ball, not physics\n    ballRigidbody.isKinematic = true;\n\n    \/\/ move the ball to the start position\n    ballObject.transform.position = ballStartPosition;\n\n}\n\nprivate void StartBall()\n{\n    \/\/ turn kinematics off\n    ballRigidbody.isKinematic = false;\n\n    \/\/ make the direction vector a heading\n    direction.Normalize();   \n\n    \/\/ move the ball by adding force\n    ballRigidbody.AddForce(direction * force, ForceMode.Impulse);\n\n    \/\/ change the state to playing\n    state = GameState.Playing;\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">New here is the&nbsp;<strong>isKinematic<\/strong>&nbsp;value that we are modifying on our&nbsp;<strong>Rigidbody<\/strong>&nbsp;component of \u201cballRigidbody\u201d. The&nbsp;<a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Rigidbody-isKinematic.html\">Rigidbody.isKinematic<\/a>&nbsp;flag is a boolean \u2013 that is, it can only be set to true or false. When you set an object\u2019s isKinematic value to true, you can now control and move the object, instead of Unity\u2019s physics system. It is a simple way to take physics out of the equation. Without this, your movement of the ball would be considered to be a physical move and well\u2026 let\u2019s just say bad things can happen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here in ResetBall( ) we set isKinematic to TRUE. We then move the ball back to the original spot by setting the transform.position value to <strong>ballStartPosition<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once we finish resetting the ball, InitializeRound( ) calls StartBall( ). This script turns ball Physics back on (by setting&nbsp;<strong>isKinematic&nbsp;<\/strong>to FALSE), and then applies the direction and force that we previously held inside Start( ). Finally, we set the currentState to GameState.playing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In order to set this machine into motion, we made the last line of our Start( ) method a call to InitializeRound( ). Now the ball is in action and our paddles finally move!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now that we\u2019ve started the round, we need a way to stop it, and we do this by recognizing that back wall has been hit, and registering the scoring event.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Part 6: Registering the Score<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We set up our system so that the back walls would detect whether or not they had been hit by the ball, and tell the game manager to register the scoring event.  We did this so that we could set a variable on each wall to indicate to whom the score should be attributed.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In order to talk to the GameManager script, we needed a reference to the &#8220;GameManagerObject&#8221; object, so that we could access the component, and call the public function <strong>RegisterScore( )<\/strong>. In the past, we have referenced a GameObject and the used GetComponent&lt;>( ) to access the script, but here we shortcut that by defining a public variable of type <strong>GameManager <\/strong>and now we can ONLY associate objects with the appropriate component attached.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\npublic class BackWallScript : MonoBehaviour\n{\n    public GameManager gameManager;\n    public int playerNumber;\n\n    private void OnCollisionEnter(Collision collision)\n    {\n        if (collision.gameObject.name == &quot;BallObject&quot;)\n        {\n            gameManager.RegisterScore(playerNumber); \n        }\n}\n\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Another change from our previous collisions &#8211; this time we tested the <strong>name<\/strong> of the game object that we collided with, verifying that it is indeed the &#8220;BallObject&#8221;.  Once we have confirmed this, we tell our EasyPong instance to run the <strong>RegisterScore <\/strong>function, and pass it an integer that we will populate with the player id who should receive the point.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Back in EasyPong, we define <strong>RegisterScore(int playerNumber) <\/strong>as such:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n    public void RegisterScore(int playerNumber)\n    {\n        \/\/ stop the action\n        ballRigidbody.isKinematic = true;\n\n        \/\/ process the score\n        if (playerNumber == 1)\n        {\n            playerOneScore++;\n        } else if (playerNumber == 2)\n        {\n            playerTwoScore++;\n        } else\n        {\n            Debug.Log(&quot;Player Number was not assigned correctly.  Value=&quot; + playerNumber);\n        }\n\n        \/\/ Display the Score\n        Debug.Log(&quot;The Score is &quot; + playerOneScore + &quot;-&quot; + playerTwoScore);\n\n        \/\/ go to postround state\n        state = GameState.PostRound;\n\n        \/\/ go start the next round\n        InitializeRound();\n    }\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"> There&#8217;s a lot going on here, so let&#8217;s unpack it:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>We set <strong>isKinematic<\/strong> to true, effectively stopping the ball and removing it from the physics equation<\/li>\n\n\n\n<li>We check to see which player scores, and increment their score value by one (the ++ is the same as saying that something &#8220;+= 1&#8221; or something = something + 1)<\/li>\n\n\n\n<li>We use <strong>Display.Log( ) <\/strong>to put the score into the console to track our progress<\/li>\n\n\n\n<li>We put put our currentState value to  &#8220;PostRound&#8221;<\/li>\n\n\n\n<li>We get ready to run the next round by calling <strong>InitializeRound( )<\/strong>.<\/li>\n\n\n\n<li>This function is also where it would make sense to test if either player had just made it to our MAX_SCORE value, and if so, move to the Game Over state instead, but that part is for you to complete as part of your homework.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Part 7: Coroutines<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In past discussions, I have mentioned that Unity runs through its objects and those objects&#8217; scripts sequentially.  It is a very linear process.  When the &#8220;Awake&#8221; message is sent out, Unity goes down the list of objects that it maintains (and that you do not control) and one by one passes it the &#8220;Awake&#8221; message to each.  That message is passed to each one of that object&#8217;s components, and if that object has an <strong>Awake( )<\/strong> function in it, that function  is executed, line by line.  Once every object has received the &#8220;Awake&#8221; message the &#8220;Start&#8221; message is called on every object before moving to rendering the next frame, and Unity again goes down the list, object by object, component by component, and any corresponding function will execute.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When a function is called, it must run until it is completes every line (or until it encounters a &#8220;return&#8221;, which is a type of completion).  If another function is called during that original function, then THAT new function must run to completion before moving to the next line in the original, and so forth and so on.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Using this method, it can be difficult or cumbersome to create functions that execute periodically (such as a timed event), or to occur across a span of time and across many frames (such as a fading transition).   Creating and maintaining internal timers can be tricky, and it requires a lot of extra calls.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A <a href=\"https:\/\/docs.unity3d.com\/Manual\/Coroutines.html\"><strong>coroutine<\/strong> <\/a>is a function that lets us break out of this pattern by allowing us to pause it&#8217;s execution, hand control back to Unity, and then resume later and pick back up where it left off after some measure.   <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In our game, we would like to create a new state to let the player &#8220;get ready&#8221; to begin a round.   A moment between when the ball is reset, and the action begins.   For our first co-routine, we are going to make this moment last for 3 seconds.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We create our function by declaring an <strong>IEnumerator<\/strong>.  This function will wait for three seconds, and then call the <strong>StartBall( )<\/strong> function.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\npublic IEnumerator GetReady()\n{\n    \/\/ tell the engine to come back in three seconds\n    yield return new WaitForSeconds(3.0f);\n    \n    \/\/ resumes after the pause\n    StartBall();\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Next we call this by replacing the <strong>StartBall( )<\/strong> function call in <strong>InitRound( )<\/strong> with the <strong>StartCoroutine( )<\/strong> function, passing our coroutine&#8217;s call as the parameter.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; highlight: [6,7]; title: ; quick-code: false; notranslate\" title=\"\">\nprivate void InitRound()\n{\n    \/\/ Reset Ball\n    ResetBall();\n\n    \/\/ start the coroutine\n    StartCoroutine(GetReady());\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Now when we run this, our ball sits there for three seconds and then begins to move.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Basic UI<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Three seconds can be a long time, and we don&#8217;t want our player to get confused, so first we should build a message to the player letting them know that now is the time to Get Ready!!!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To do this, we create a new text object by going to <strong>Game Object &gt; UI &gt; Legacy &gt; Text<\/strong> or <strong>Create &gt; UI &gt; Legacy &gt; Text<\/strong>.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When you do this, you will see a few new objects appear in your scene, including a&nbsp;<strong>Canvas&nbsp;<\/strong>object, and an&nbsp;<strong>EventSystem&nbsp;<\/strong>object. We will cover the UI system more in a future lesson, for now just know that the Canvas is the two-dimensional space where UI elements live, and renders as an overlay for the active camera.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One change you will definitely want to make now is in the <strong>Canvas<\/strong> object.  Look for the <strong>Canvas Scaler<\/strong> component and change the <strong>UI Scale Mode<\/strong> to <strong>Scale with Screen Size<\/strong>.  This ensures that your UI elements will fill the same proportions of the screen whether it is in the Game window or full screen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Select the text object that you have created and change the name.  We used <strong>myOverlayTextObject<\/strong> (because we will use this for more than one message). In the <strong>Text<\/strong> component, change the <strong>Text<\/strong> field (a longform text area, and yes, text inside text is redundant) to read something besides <em>&#8220;New Text&#8221;<\/em>. I chose <em>\u201cHello World\u201d<\/em>. Set your&nbsp;<strong>Alignments<\/strong>&nbsp;to \u201cCenter\u201d and \u201cMiddle\u201d, and set your <strong>Horizontal <\/strong>and <strong>Vertical overflow<\/strong> values to Overflow. Finally, adjust the font size until you have something that looks good to you.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, go to the EasyPong script, and add a Text object variable to hold a reference to our text object. UI elements have their own Unity library, which we have to call first by adding the following line to the <em>\u201cusing\u201d<\/em> commands at the very top:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\nusing UnityEngine.UI;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Without this line, your calls to get and set text objects will return errors because Unity does not recognize that you will be using them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, create the text object to hold the message text, and use our drag-and-drop method in the Unity editor to assign the text object to this field.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n    \/\/ define text objects\n    public Text overlayMessage;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Now inside of the <strong>Start( )<\/strong> function, we set our text message to read <em>\u201cGet Ready!!!\u201d<\/em>, and then set the <strong>enabled<\/strong> property to false so that it will not display until we tell it to.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n        \/\/ set the text message to read &quot;Get Ready!!!&quot;\n        overlayMessage.text = &quot;Get Ready!!!&quot;;\n        overlayMessage.enabled = false;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">We want to make our message display while the GetReady coroutine is running, and turn off again when the stage is over and we move into the Playing state.  We do this by adjusting the text object&#8217;s <strong>enabled<\/strong> property like so:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; highlight: [3,8]; title: ; notranslate\" title=\"\">\npublic IEnumerator GetReady()\n{\n    overlayMessage.enabled = true \/\/ turn the message visibility on\n\n    \/\/ tell the engine to come back in three seconds\n    yield return new WaitForSeconds(3.0f);\n    \n    overlayMessage.enabled = false  \/\/ turn the message visibility off\n\n    \/\/ resumes after the pause\n    StartBall();\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Now we should see the message appear for 3 seconds, then disappear as the ball starts moving.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Using the Renderer<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Three seconds still feels like a long time, doesn&#8217;t it?  Players might still think our game is broken or stalled.  And just when they let their guard down, the ball shoots off!  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s help show our players that <em>something<\/em> is happening, and help them anticipate the beginning of the round.  We will do this by making the ball and the message blink.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To achieve this, you might be tempted to  the <strong>enabled<\/strong> property of the ball object, but don&#8217;t do that!  Making the ball inactive can destroy the connections, and reactivating it will run the Start( ) command all over again.  Instead, we want to manipulate only the <em>visibility<\/em> of the ball, which we do by enabling and disabling the <strong>Mesh Renderer<\/strong> component.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In our EasyPong declarations, we create a new private variable of the type <strong>Renderer<\/strong>, like so:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n  private Renderer ballRender;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u2026 then in our Start( ) method we assign the Renderer component like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\n  ballRender = ballObject.GetComponent&lt;Renderer&gt;();\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Finally, we modify our GetReady( ) script to enable and disable the Renderer component, alternated with our overlay message.  We will display one configuration for a half second, and then the other for another half second.   The use of a <strong>for<\/strong> <strong>loop<\/strong> lets us cycle through this three times.  Once the loop completes, StartBall( ) is called and our Coroutine ends. <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; gutter: false; title: ; quick-code: false; notranslate\" title=\"\">\npublic IEnumerator GetReady()\n{\n    for (int i=0; i &lt;3; i++)\n    {\n        \/\/ turn on the message\n        overlayMessage.enabled = true;\n        \/\/ turn off the ball\n        ballRender.enabled = false;\n        yield return new WaitForSeconds(0.5f);\n\n        \/\/ turn off the message\n        overlayMessage.enabled = false;\n        \/\/ turn on the ball\n        ballRender.enabled = true;\n        yield return new WaitForSeconds(0.5f);\n    }\n\n    StartBall();\n\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Now our ready message and ball alternate in quick half-second blinks that let the player get a good sense of the timing that is coming.   Now we&#8217;ve covered everything that is needed to complete Assignment #2!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<pre class=\"wp-block-preformatted\">GameManager.cs<\/pre>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; quick-code: false; notranslate\" title=\"\">\nusing System.Collections;\nusing UnityEngine;\nusing UnityEngine.UI;\n\npublic enum GameState { None, PreRound, Playing, PostRound, GameOver };\n\npublic class GameManager : MonoBehaviour\n{\n    public GameObject ballObject;\n    private Rigidbody ballRigidbody;\n    private Renderer ballRender;\n\n    public Vector3 direction;\n    public float force;\n\n    \/\/ GAME VARIABLES\n    private int playerOneScore, playerTwoScore;\n    private int scoreLimit = 3;  \/\/ score needed to win\n    public GameState state = GameState.None;\n    private Vector3 ballStartPosition;\n\n    \/\/ UI variables\n    public Text messageOverlay;\n\n    \/\/ Start is called once before the first execution of Update after the MonoBehaviour is created\n    void Start()\n    {\n        \/\/ getting necessary information and components\n        ballRigidbody = ballObject.GetComponent&lt;Rigidbody&gt;(); \/\/ assign the rigidbody\n        ballRender = ballObject.GetComponent&lt;Renderer&gt;(); \/\/ get the render component\n\n        ballStartPosition = ballObject.transform.position;  \/\/ getting the position to reset to\n\n        \/\/ reset game variables\n        playerOneScore = 0;\n        playerTwoScore = 0;\n\n        \/\/ turn off the message\n        messageOverlay.enabled = false;\n\n        \/\/ start the first round\n        InitializeRound();\n    }\n\n    private void InitializeRound()\n    {\n        \/\/ set the state\n        state = GameState.PreRound;\n        \/\/ Debug.Log(&quot;Gamestate is PreRound&quot;);\n\n        \/\/ reset the ball\n        ResetBall();\n\n        \/\/ start the get ready sequence\n        StartCoroutine(GetReady());\n    }\n\n    private void ResetBall()\n    {\n        ballRigidbody.isKinematic = true; \/\/ take control of the ball\n        ballObject.transform.position = ballStartPosition;\n    }\n\n    private void StartBall()\n    {\n        ballRigidbody.isKinematic = false; \/\/ turn on ball physics\n\n        direction.Normalize(); \/\/ normalize to a heading       \n        ballRigidbody.AddForce(direction * force, ForceMode.VelocityChange); \/\/ push the ball\n\n        \/\/ set the state\n        state = GameState.Playing;\n        \/\/ Debug.Log(&quot;Gamestate is Playing&quot;);\n    }\n\n    public void RegisterScore(int playerNumber)\n    {\n        \/\/ the round is over\n        state = GameState.PostRound;\n\n        \/\/ take over for physics\n        ballRigidbody.isKinematic = true;\n\n        \/\/ increment the score\n        if (playerNumber == 1)\n        {\n            playerOneScore++;\n        }\n        else if (playerNumber == 2)\n        {\n            playerTwoScore++;\n        }\n        else\n        {\n            Debug.Log(&quot;Player NUmber not correctly assigned.  value = &quot; + playerNumber);\n        }\n\n        \/\/ display the score\n        Debug.Log(&quot;The Score is &quot; + playerOneScore + &quot; - &quot; + playerTwoScore);\n\n        \/\/ initialize round\n        InitializeRound();\n    }\n\n    public IEnumerator GetReady()\n    {\n        \/\/ set the message text\n        messageOverlay.text = &quot;Get Ready !!!&quot;;\n\n        for (int i = 0; i &lt; 3; i++)\n        {\n            \/\/ turn the message on\n            messageOverlay.enabled = true;\n\n            \/\/ turn the ball off\n            ballRender.enabled = false;\n\n            \/\/ wait for 0.5 seconds\n            yield return new WaitForSeconds(0.5f);\n\n            \/\/ turn the message off\n            messageOverlay.enabled = false;\n            \/\/ turn the ball on\n            ballRender.enabled = true;\n\n            \/\/ wait for 0.5 seconds\n            yield return new WaitForSeconds(0.5f);\n        }\n\n        \/\/ turn the mssage off\n        messageOverlay.enabled = false;\n\n        \/\/ start the ball\n        StartBall();\n    }\n\n}\n<\/pre><\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<pre class=\"wp-block-preformatted\">PaddleScript.cs<\/pre>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; quick-code: false; notranslate\" title=\"\">\nusing UnityEngine;\n\npublic class PaddleScript : MonoBehaviour\n{\n    \/\/ paddle movement\n    private float speed = 50.0f;\n    private float offset = 18.0f;\n\n    \/\/ paddle input buttons\n    public string upButton, downButton;\n\n    \/\/ game manager info\n    private GameManager game;\n\n    \/\/ Start is called once before the first execution of Update after the MonoBehaviour is created\n    void Start()\n    {\n        game = GameObject.Find(&quot;GameManagerObject&quot;).GetComponent&lt;GameManager&gt;();\n    }\n\n    \/\/ Update is called once per frame\n    void Update()\n    {\n\n        if ((game.state == GameState.Playing) || (game.state == GameState.PreRound)) \n        {\n            MovePaddles();\n        }\n    }\n\n    private void MovePaddles()\n    {\n                \/\/ get our paddle position\n        Vector3 currentPosition = transform.position;\n\n        \/\/ adjust if keys are pressed\n        if (Input.GetKey(upButton))\n        {\n            currentPosition.z += speed * Time.deltaTime;\n        }\n\n        if (Input.GetKey(downButton))\n        {\n            currentPosition.z -= speed * Time.deltaTime;\n        }\n\n        \/\/ check the paddle position\n        currentPosition.z = Mathf.Clamp(currentPosition.z, -offset, offset);\n\n        \/\/ replace the position with the updated version\n        transform.position = currentPosition;\n    }\n}\n<\/pre><\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<pre class=\"wp-block-preformatted\">BackWallScript.cs<\/pre>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; quick-code: false; notranslate\" title=\"\">\nusing UnityEngine;\n\npublic class BackWallScript : MonoBehaviour\n{\n    public GameManager gameManager;\n    public int playerNumber;\n\n    private void OnCollisionEnter(Collision collision)\n    {\n        \/\/ Debug.Log(&quot;Back Wall Collision&quot;);\n\n        if (collision.gameObject.name == &quot;BallObject&quot;)\n        {\n            \/\/ Debug.Log(&quot;Ball hit the back wall&quot;);\n            gameManager.RegisterScore(playerNumber);\n        }\n    }\n}\n<\/pre><\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<pre class=\"wp-block-preformatted\">BallScript.cs<\/pre>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; quick-code: false; notranslate\" title=\"\">\nusing UnityEngine;\n\npublic class BallScript : MonoBehaviour\n{\n    private AudioSource audioComponent;\n    private Rigidbody rb;\n\n    public AudioClip wallSound, paddleSound, deathSound;\n\n    \/\/ Start is called once before the first execution of Update after the MonoBehaviour is created\n    void Start()\n    {\n        audioComponent = GetComponent&lt;AudioSource&gt;();\n        rb = GetComponent&lt;Rigidbody&gt;();\n    }\n\n    private void OnCollisionEnter(Collision collision)\n    {\n        if (collision.gameObject.tag == &quot;Wall&quot;)\n        {\n            \/\/ make the wall noise\n            MakeWallNoise();\n        }\n        else if (collision.gameObject.tag == &quot;Paddle&quot;)\n        {\n            \/\/ make the paddle noise\n            MakePaddleNoise();\n            if (audioComponent.pitch &lt;= 4.0f)\n            {\n                \/\/ increase the pitch\n                audioComponent.pitch *= 1.1f;\n                \/\/ increase the speed\n                rb.linearVelocity *= 1.05f;\n            }\n        }\n        else if (collision.gameObject.tag == &quot;BackWall&quot;)\n        {\n            \/\/ make the death noise\n            MakeDeathNoise();\n        }\n    }\n\n    private void MakeWallNoise()\n    {\n        audioComponent.Stop();\n        audioComponent.clip = wallSound;\n        audioComponent.Play();\n    }\n\n    private void MakePaddleNoise()\n    {\n        audioComponent.PlayOneShot(paddleSound);\n    }\n\n    private void MakeDeathNoise()\n    {\n        audioComponent.Stop();\n        audioComponent.clip = deathSound;\n        audioComponent.Play();\n    }\n}\n<\/pre><\/div>","protected":false},"excerpt":{"rendered":"<p>This week, we replicate last week&#8217;s accomplishments in a matter of minutes by using the tools that Unity affords us. This frees up extra time to build out even more of our game, and allow us to start working on the logic of moving through the stages of gameplay. This week we work with Physics, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-54","post","type-post","status-publish","format-standard","hentry","category-recap"],"blocksy_meta":"","featured_image_urls":{"full":"","thumbnail":"","medium":"","medium_large":"","large":"","1536x1536":"","2048x2048":""},"post_excerpt_stackable":"<p>This week, we replicate last week&#8217;s accomplishments in a matter of minutes by using the tools that Unity affords us. This frees up extra time to build out even more of our game, and allow us to start working on the logic of moving through the stages of gameplay. This week we work with Physics, Collisions, Sounds, Scripting Prefabs, Enumeration, Coroutines, and take an early look at Unity&#8217;s UI system. Let&#8217;s jump in! Part 1: Starting Over with Rigidbody Physics Our first step for today was to recreate our efforts from last week with a more efficient solution, Unity&#8217;s built-in&hellip;<\/p>\n","category_list":"<a href=\"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/category\/recap\/\" rel=\"category tag\">Course Recap<\/a>","author_info":{"name":"Tom Corbett","url":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/author\/tcorbett\/"},"comments_num":"0 comments","_links":{"self":[{"href":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/wp-json\/wp\/v2\/posts\/54","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/wp-json\/wp\/v2\/comments?post=54"}],"version-history":[{"count":11,"href":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/wp-json\/wp\/v2\/posts\/54\/revisions"}],"predecessor-version":[{"id":518,"href":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/wp-json\/wp\/v2\/posts\/54\/revisions\/518"}],"wp:attachment":[{"href":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/wp-json\/wp\/v2\/media?parent=54"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/wp-json\/wp\/v2\/categories?post=54"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/courses.etc.cmu.edu\/53-353\/index.php\/wp-json\/wp\/v2\/tags?post=54"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}