{"id":1242,"date":"2018-01-02T03:32:22","date_gmt":"2018-01-02T08:32:22","guid":{"rendered":"http:\/\/bluegalaxy.info\/codewalk\/?p=1242"},"modified":"2021-01-17T20:29:18","modified_gmt":"2021-01-18T01:29:18","slug":"javascript-intro-web-game-development-part-4-animate-left-paddle","status":"publish","type":"post","link":"https:\/\/bluegalaxy.info\/codewalk\/2018\/01\/02\/javascript-intro-web-game-development-part-4-animate-left-paddle\/","title":{"rendered":"JavaScript: Intro to Web Game Development &#8211; Part 4: animate left paddle"},"content":{"rendered":"\n<p>This is the fourth part in the series on how to create a web browser game of Pong using JavaScript. Part 3 can be read here:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-chris-nielsen-code-walk wp-block-embed-chris-nielsen-code-walk\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"miLZ6smScR\"><a href=\"http:\/\/bluegalaxy.info\/codewalk\/2017\/12\/30\/javascript-intro-web-game-development-part-3-add-graphical-components\/\">JavaScript: Intro to Web Game Development &#8211; Part 3: add graphical components<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\" title=\"&#8220;JavaScript: Intro to Web Game Development &#8211; Part 3: add graphical components&#8221; &#8212; Chris Nielsen Code Walk\" src=\"http:\/\/bluegalaxy.info\/codewalk\/2017\/12\/30\/javascript-intro-web-game-development-part-3-add-graphical-components\/embed\/#?secret=miLZ6smScR\" data-secret=\"miLZ6smScR\" width=\"600\" height=\"338\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>For this article, I will demonstrate how to add mouse control to the left paddle so that it moves straight up and down on the Y axis, based on mouse movement. In this step I am also:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>assigning variables<\/li><li>creating a &#8220;drawComponents&#8221; function<\/li><li>setting up a framerate of 30 frames per second for interactive gameplay<\/li><li>implementing an event listener to move the left paddle according to the mouse position<\/li><\/ul>\n\n\n\n<p><strong>Step 1: Create variables<br><\/strong><\/p>\n\n\n\n<p>For this step, I moved some numeric values that were previously hard coded, into global variables at the top of the script. For example:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var canvas;\nvar canvasContext;\nvar canvas_width;\nvar canvas_height;\n\n\/\/ offsets to account for the rounded corners\nvar offsetA = 30;\nvar offsetB = 60;\n\n\/\/ starting y position of the left paddle\nvar paddle1Y = 100;\n\n\/\/ defaults for paddle thickness and height\nconst PADDLE_THICKNESS = 10;\nconst PADDLE_HEIGHT = 70;<\/pre>\n\n\n\n<p><strong>Step 2: Create drawComponents function<br><\/strong><\/p>\n\n\n\n<p>Things that were previously drawn in the window.onload function are now moved to a dedicated &#8220;drawComponents&#8221; function. For example:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">function drawComponents() {\n\n    \/\/ this line blacks out the background to give the appearance of animation\n    canvasContext.fillStyle = 'black';\n    canvasContext.fillRect(offsetA, 0, canvas_width-offsetB, canvas_height);\n\n    \/\/ Left paddle\n    canvasContext.fillStyle = 'white';\n    canvasContext.fillRect(offsetA, paddle1Y, PADDLE_THICKNESS, PADDLE_HEIGHT);\n\n    \/\/ Right paddle\n    canvasContext.fillStyle = 'white';\n    canvasContext.fillRect(canvas_width-40, canvas_height-120, PADDLE_THICKNESS, PADDLE_HEIGHT);\n\n    \/\/ Draw the ball\n    canvasContext.fillStyle = 'white';\n    canvasContext.fillRect(200, 300, 10, 10);\n\n    \/\/ Place holder for the scores\n    canvasContext.font=\"40px monospace\";\n    canvasContext.fillText(\"1\", (canvas_width\/2)-60, 40);\n    canvasContext.fillText(\"0\", (canvas_width\/2)+35, 40);\n\n    drawNet();\n}<\/pre>\n\n\n\n<p><strong>Step 3: Create a frame rate and game loop<br><\/strong><\/p>\n\n\n\n<p>Inside the window.onload function, I am setting a framerate with the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"no-highlight\">setInterval()<\/code> method, which sets up a game loop. Since this function contains the game loop, everything that happens in the game, all of the &#8220;action&#8221;, needs to occur in this loop, which is why there is a call to drawComponents() inside this block.<\/p>\n\n\n\n<p>This setup, defining a framerate, and using it as the second argument to the setInterval() method, is the standard way to create a game loop in JavaScript.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var framesPerSecond = 30;\nsetInterval(\n    function() {\n        drawComponents();\n    }, 1000\/framesPerSecond);<\/pre>\n\n\n\n<p>For more information about setInterval, see:<br><a href=\"https:\/\/www.w3schools.com\/jsref\/met_win_setinterval.asp\">https:\/\/www.w3schools.com\/jsref\/met_win_setinterval.asp<\/a><\/p>\n\n\n\n<p><strong>Step 4: Create a mousemove EventListener<br><\/strong><\/p>\n\n\n\n<p>Also inside the window.onload function, I need to add an EventListener for mouse movements. This is achieved with the JavaScript method <code class=\"EnlighterJSRAW\" data-enlighter-language=\"no-highlight\">addEventListener()<\/code> and its first argument is &#8216;mousemove&#8217;.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">canvas.addEventListener('mousemove',\n\tfunction(evt) {\n\t\tvar mousePos = calculateMousePos(evt);\n\t\tpaddle1Y = mousePos.y - (PADDLE_HEIGHT\/2);\n\t});<\/pre>\n\n\n\n<p>The paddle will be moving up and down on the Y axis. The line that controls this is:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">paddle1Y = mousePos.y - (PADDLE_HEIGHT\/2);<\/pre>\n\n\n\n<p>PADDLE_HEIGHT\/2 is the middle of the paddle vertically, which corresponds to the movement of the mouse.<\/p>\n\n\n\n<p>For more information about addEventListener() see:<br><a href=\"https:\/\/www.w3schools.com\/jsref\/met_element_addeventlistener.asp\">https:\/\/www.w3schools.com\/jsref\/met_element_addeventlistener.asp<\/a><\/p>\n\n\n\n<p>Notice inside the function, a mousePos variable is being set by calling another function called calculateMousePos(). That function also needs to be added to the script, but not inside the window.onload function. It looks like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">function calculateMousePos(evt) {\n    var rect = canvas.getBoundingClientRect();\n    var root = document.documentElement;\n    var mouseX = evt.clientX - rect.left - root.scrollLeft;\n    var mouseY = evt.clientY - rect.top - root.scrollTop;\n    return {\n        x:mouseX,\n        y:mouseY\n    };\n}<\/pre>\n\n\n\n<p>This function is crucial in working with the EventListener to enable movement of the paddle based on mouse movement. It uses a JavaScript method called <code class=\"EnlighterJSRAW\" data-enlighter-language=\"no-highlight\">getBoundingClientRect()<\/code>. It also uses MouseEvent <code class=\"EnlighterJSRAW\" data-enlighter-language=\"no-highlight\">clientX<\/code>&nbsp;and <code class=\"EnlighterJSRAW\" data-enlighter-language=\"no-highlight\">clientY<\/code> properties, which output the coordinates of the mouse pointer.<\/p>\n\n\n\n<p>For more information about <span class=\"me0\">getBoundingClientRect<\/span><span class=\"br0\">(<\/span><span class=\"br0\">), see:<\/span><br><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Element\/getBoundingClientRect\">https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Element\/getBoundingClientRect<\/a><\/p>\n\n\n\n<p>For more about clientX and clientY, see:<br><a href=\"https:\/\/www.w3schools.com\/jsref\/event_clientx.asp\">https:\/\/www.w3schools.com\/jsref\/event_clientx.asp<\/a><\/p>\n\n\n\n<p>Here is what the entire script looks like so far:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var canvas;\nvar canvasContext;\nvar canvas_width;\nvar canvas_height;\n\n\/\/ offsets to account for the rounded corners\nvar offsetA = 30;\nvar offsetB = 60;\n\n\/\/ starting y position of the left paddle\nvar paddle1Y = 100;\n\n\/\/ defaults for paddle thickness and height\nconst PADDLE_THICKNESS = 10;\nconst PADDLE_HEIGHT = 70;\n\n\nwindow.onload = function() {\n\n    canvas = document.getElementById(\"gameCanvas\");\n    canvasContext = canvas.getContext(\"2d\");\n    canvas_width = canvas.width;\n    canvas_height = canvas.height;\n\n    \/\/ Create the rounded canvas play area\n    canvasContext.roundRect(0, 0, canvas_width, canvas_height, 40, \"black\");\n\n    var framesPerSecond = 30;\n    setInterval(\n        function() {\n            drawComponents();\n        }, 1000\/framesPerSecond);\n\n    canvas.addEventListener('mousemove',\n    \tfunction(evt) {\n    \t\tvar mousePos = calculateMousePos(evt);\n    \t\tpaddle1Y = mousePos.y - (PADDLE_HEIGHT\/2);\n    \t});\n\n}\n\n\/\/ Function to create rounded corners on the rectangle\nCanvasRenderingContext2D.prototype.roundRect = function(x, y, width, height, radius, fill, stroke) {\n    \/\/ If stroke argument not provided, provide a stroke by default\n    if (typeof stroke == \"undefined\" ) {\n        stroke = true;\n    }\n    \/\/ If no radius is defined, then give it a default of 5\n    if (typeof radius === \"undefined\") {\n        radius = 5;\n    }\n\n    \/\/ Start of shape definition\n    this.beginPath();\n\n    this.moveTo(x + radius, y);\n    \/\/ Draw the top border line\n    this.lineTo(x + width - radius, y);\n\n    \/\/ Draw the top right curve\n    this.quadraticCurveTo(x + width, y, x + width, y + radius);\n\n    \/\/ Draw the right border line\n    this.lineTo(x + width, y + height - radius);\n\n    \/\/ Draw the bottom right curve\n    this.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);\n\n    \/\/ Draw the bottom border line\n    this.lineTo(x + radius, y + height);\n\n    \/\/ Draw the bottom left curve\n    this.quadraticCurveTo(x, y + height, x, y + height - radius);\n\n    \/\/ Draw the left border line\n    this.lineTo(x, y + radius);\n\n    \/\/ Draw the final (top left) curve\n    this.quadraticCurveTo(x, y, x + radius, y);\n\n    \/\/ End of shape definition\n    this.closePath();\n\n    \/\/ Draw the shape with a line\n    if (stroke) {\n        this.stroke();\n    }\n    \/\/ Fill in the shape with color\n    if (fill) {\n        this.fill();\n    }\n}\n\n\nfunction calculateMousePos(evt) {\n    var rect = canvas.getBoundingClientRect();\n    var root = document.documentElement;\n    var mouseX = evt.clientX - rect.left - root.scrollLeft;\n    var mouseY = evt.clientY - rect.top - root.scrollTop;\n    return {\n        x:mouseX,\n        y:mouseY\n    };\n}\n\nfunction drawComponents() {\n\n    \/\/ this line blacks out the background to give the appearance of animation\n    canvasContext.fillStyle = 'black';\n    canvasContext.fillRect(offsetA, 0, canvas_width-offsetB, canvas_height);\n\n    \/\/ Left paddle\n    canvasContext.fillStyle = 'white';\n    canvasContext.fillRect(offsetA, paddle1Y, PADDLE_THICKNESS, PADDLE_HEIGHT);\n\n    \/\/ Right paddle\n    canvasContext.fillStyle = 'white';\n    canvasContext.fillRect(canvas_width-40, canvas_height-120, PADDLE_THICKNESS, PADDLE_HEIGHT);\n\n    \/\/ Draw the ball\n    canvasContext.fillStyle = 'white';\n    canvasContext.fillRect(200, 300, 10, 10);\n\n    \/\/ Place holder for the scores\n    canvasContext.font=\"40px monospace\";\n    canvasContext.fillText(\"1\", (canvas_width\/2)-60, 40);\n    canvasContext.fillText(\"0\", (canvas_width\/2)+35, 40);\n\n    drawNet();\n}\n\nfunction drawNet() {\n    for(var i=0; i &lt; canvas_height; i += 30) {\n        canvasContext.fillStyle = 'white';\n        canvasContext.fillRect(canvas_width\/2, i, 2, 10, 'white');\n    }\n}\n<\/pre>\n\n\n\n<p>And here is what the game looks like so far, with the left paddle responding to mouse movements:<\/p>\n\n\n\n<p><iframe loading=\"lazy\" id=\"iframe_drop_shadow\" src=\"https:\/\/bluegalaxy.info\/js\/pong_pt4.html\" width=\"770\" height=\"600\" scrolling=\"no\"><span style=\"display: inline-block; width: 0px; overflow: hidden; line-height: 0;\" data-mce-type=\"bookmark\" class=\"mce_SELRES_start\">\ufeff<\/span><span style=\"display: inline-block; width: 0px; overflow: hidden; line-height: 0;\" data-mce-type=\"bookmark\" class=\"mce_SELRES_start\">\ufeff<\/span><span style=\"display: inline-block; width: 0px; overflow: hidden; line-height: 0;\" data-mce-type=\"bookmark\" class=\"mce_SELRES_start\">\ufeff<\/span><\/iframe><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is the fourth part in the series on how to create a web browser game of Pong using JavaScript. Part 3 can be read here: For this article, I will demonstrate how to add mouse control to the left paddle so that it moves straight up and down on the Y axis, based on &hellip; <a href=\"https:\/\/bluegalaxy.info\/codewalk\/2018\/01\/02\/javascript-intro-web-game-development-part-4-animate-left-paddle\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">JavaScript: Intro to Web Game Development &#8211; Part 4: animate left paddle<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[44],"tags":[68,89,88,45,87],"class_list":["post-1242","post","type-post","status-publish","format-standard","hentry","category-javascript-language","tag-addeventlistener","tag-clientx","tag-getboundingclientrect","tag-javascript","tag-setinterval"],"_links":{"self":[{"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/posts\/1242","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/comments?post=1242"}],"version-history":[{"count":16,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/posts\/1242\/revisions"}],"predecessor-version":[{"id":3332,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/posts\/1242\/revisions\/3332"}],"wp:attachment":[{"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/media?parent=1242"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/categories?post=1242"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/tags?post=1242"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}