{"id":33,"date":"2023-05-18T14:00:00","date_gmt":"2023-05-18T18:00:00","guid":{"rendered":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/?p=33"},"modified":"2023-05-19T11:33:59","modified_gmt":"2023-05-19T15:33:59","slug":"day-4-hard-pong","status":"publish","type":"post","link":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/?p=33","title":{"rendered":"Day 4: Hard Pong"},"content":{"rendered":"\n<p>In today&#8217;s class, we discussed the principles behind what makes an &#8220;animation&#8221; &#8211; the rapid succession of images that create the illusion of movement. We discussed the difference between display rates of monitors (refresh rate) and game engines (frame rates), and covered a little bit of &#8220;vector math&#8221; which we will use to position and move objects.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>Finally we generated a quick script to get the ball moving.  Simple and possibly choppy, but it gets the idea across.<\/p>\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 Ping: MonoBehaviour\n{\n    public GameObject myBall;\n    public float speed;\n    public Vector3 direction;\n\n    \/\/ Start is called before the first frame update\n    void Start()\n    {\n        myBall.transform.position = new Vector3();\n    }\n    \/\/ Update is called once per frame\n    void Update()\n    {\n        myBall.transform.position = myBall.transform.position + (direction * speed);\n    }\n}<\/pre>\n\n\n\n<p>Next, we discussed principles of animation, and applied some changes to regulate and smooth our motion. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">1. Normalized direction<\/h4>\n\n\n\n<p>Currently, our &#8220;direction&#8221; values create a vector of indeterminate length. Because we express our movement here as <em>speed * direction<\/em>, we have implied that we only want Direction to contribute to the heading of the motion, not to have an effect on the velocity. To do this, we want to <strong>normalize<\/strong> our direction vector. Normalizing values let&#8217;s us bring them to a scale or standard. In terms of modifying our vector, the <strong>Normalize( )<\/strong> command will find the <strong>magnitude<\/strong> of a Vector3 (the distance from [0,0,0] to the point expressed by [x,y,z]) and divide all 3 vector values by that number, resulting in a Vector3 with a magnitude of 1.0.<\/p>\n\n\n\n<p>This means that our scalar value <strong>speed<\/strong> will be the distance traveled (the magnitude of our motion vector) in each frame.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">2. Smoothed motion<\/h4>\n\n\n\n<p>We made our ball appear to move smoothly, independent of our frame rate. Frame rate depends on the amount of time it takes to render a frame and execute all commands in between. As we saw in class, this rate can vary greatly from frame to frame. (To see this for yourself, click on the <strong>Stats<\/strong> button in the top bar of your <strong>Game<\/strong> window while the game is playing and look for the number next to &#8220;fps&#8221; (frames per second).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"745\" height=\"944\" src=\"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/wp-content\/uploads\/2022\/05\/image-2.png\" alt=\"\" class=\"wp-image-39\" srcset=\"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/wp-content\/uploads\/2022\/05\/image-2.png 745w, https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/wp-content\/uploads\/2022\/05\/image-2-237x300.png 237w\" sizes=\"(max-width: 745px) 100vw, 745px\" \/><\/figure><\/div>\n\n\n<p>At first, we made our ball move a fixed amount in each frame (expressed as <em>direction * speed<\/em>). In order to ensure that the ball appeared to move consistently over time rather than stutter, we introduced an additional multiplier &#8211; &#8220;delta time&#8221; &#8211; which returns the numeric value for seconds elapsed since the last frame was drawn. (This is generally a very low number &#8211; most games aim to run at 60 fps, leaving only 16.67ms between frames. ) By using &#8220;delta time&#8221;, we are incorporating the passage of time in the real world, and so a speed value of &#8220;2&#8221; now becomes &#8220;2 unit\/second&#8221; when multiplied by <a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Time-deltaTime.html\">Time.deltaTime<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">3. Moving Paddles<\/h4>\n\n\n\n<p>Next, we created a paddle object, converted it into a prefab (by dragging it from our Hierarchy to our Assets folder) and placed prefab instances of the paddle on the left and right of the field of play, with x-values of -40 and 40.<\/p>\n\n\n\n<p>We defined a new function <strong>MovePaddles( )<\/strong>, which we call from <strong>Update( )<\/strong> so that it runs every frame. We defined public variables for the GameObjects leftPaddle and rightPaddle (and associated them in the browser), and created a paddleSpeed value to control the motion. In the function definition, we made the following steps:<\/p>\n\n\n\n<ol>\n<li>Get the position of the paddles (leftPadPos, rightPadPos)<\/li>\n\n\n\n<li>Test certain keys to see if they are pressed, and if they are, increment or decrement the x-value of the corresponding paddle position.<\/li>\n\n\n\n<li>Pass the new positions back to the paddles.<\/li>\n<\/ol>\n\n\n\n<p>This creates the effect of moving the left and right paddle when we press the W, S, up arrow, and down arrow keys.<\/p>\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 Ping : MonoBehaviour\n{\n    public GameObject myBall;\n    public GameObject leftPaddle;\n    public GameObject rightPaddle;\n\n    public Vector3 direction;\n    public float speed;\n\n    public float paddleSpeed;\n\n    \/\/ Start is called before the first frame update\n    void Start()\n    {\n        myBall.transform.position = new Vector3();  \/\/ Reset the ball to 0,0,0\n\n        \/\/ normalize the direction vector\n        direction.Normalize();\n    }\n\n    \/\/ Update is called once per frame\n    void Update()\n    {\n        \/\/ move the ball\n        myBall.transform.position = myBall.transform.position + (direction * speed * Time.deltaTime);\n\n        \/\/ move the paddles\n        MovePaddles();\n\n    }\n\n    private void MovePaddles()\n    {\n        \/\/ get the current position of the paddles\n        Vector3 leftPadPos = leftPaddle.transform.position;\n        Vector3 rightPadPos = rightPaddle.transform.position;\n\n        \/\/ adjust that position based on the keys pressed\n        if (Input.GetKey(\"up\"))\n        {\n            rightPadPos.z = rightPadPos.z + (paddleSpeed * Time.deltaTime);\n        }\n        if (Input.GetKey(\"down\"))\n        {\n            rightPadPos.z = rightPadPos.z - (paddleSpeed * Time.deltaTime);\n        }\n        if (Input.GetKey(KeyCode.W))\n        {\n            leftPadPos.z += (paddleSpeed * Time.deltaTime);\n        }\n        if (Input.GetKey(KeyCode.S))\n        {\n            leftPadPos.z -= (paddleSpeed * Time.deltaTime);\n        }\n\n\n        \/\/ put the new position back into the object's transform\n        rightPaddle.transform.position = rightPadPos;\n        leftPaddle.transform.position = leftPadPos;\n\n    }\n\n}\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p><a class=\"more-link\"  href=\"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/?p=33\"><span class=\"more-text\"><\/span><\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"greenlet_layout":[]},"categories":[6],"tags":[],"_links":{"self":[{"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/index.php?rest_route=\/wp\/v2\/posts\/33"}],"collection":[{"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=33"}],"version-history":[{"count":6,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/index.php?rest_route=\/wp\/v2\/posts\/33\/revisions"}],"predecessor-version":[{"id":157,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/index.php?rest_route=\/wp\/v2\/posts\/33\/revisions\/157"}],"wp:attachment":[{"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=33"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=33"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/53-353\/m2023\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=33"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}