{"id":7,"date":"2013-06-03T21:27:54","date_gmt":"2013-06-03T21:27:54","guid":{"rendered":"http:\/\/joaquinruales.wordpress.com\/?p=2"},"modified":"2015-12-19T21:57:11","modified_gmt":"2015-12-19T21:57:11","slug":"2","status":"publish","type":"post","link":"https:\/\/blog.400pixels.net\/?p=7","title":{"rendered":"Tutorial: Curve Bounce in HTML5"},"content":{"rendered":"<p>In this tutorial we'll program a simulation of a red rubber ball that bounces off of a sine wave in a frictionless, gravity-less environment (a very typical scenario). We'll be using Javascript, the HTML5 Canvas element, and the <a href=\"http:\/\/www.createjs.com\/#!\/EaselJS\" target=\"_blank\">easeljs<\/a> library.<\/p>\n<p>This tutorial is different from others I have found in that it internally stores the hitting surface as a mathematical function rather than a collection of lines, and it uses the derivative of the function to calculate the response of each collision.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-38\" src=\"http:\/\/blog.400pixels.net\/wp-content\/uploads\/2013\/06\/BOUNCE-300x200.png\" alt=\"Curve Bounce\" width=\"300\" height=\"200\" srcset=\"https:\/\/blog.400pixels.net\/wp-content\/uploads\/2013\/06\/BOUNCE-300x200.png 300w, https:\/\/blog.400pixels.net\/wp-content\/uploads\/2013\/06\/BOUNCE.png 600w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<div style=\"clear: both;\"><\/div>\n<ul>You'll need:<\/p>\n<li>Some programming experience in\u00a0Javascript or Actionscript<\/li>\n<li>High School Physics (vectors, velocity)<\/li>\n<li>A web browser that supports HTML5 (If the demo linked below works, you're all set)<\/li>\n<li>A text editor such as <a title=\"TextWrangler\" href=\"http:\/\/www.barebones.com\/products\/textwrangler\/\" target=\"_blank\">TextWrangler<\/a> (Free, Mac),\u00a0<a title=\"Notepad++\" href=\"http:\/\/notepad-plus-plus.org\/\" target=\"_blank\">Notepad++<\/a> (Free, Windows), or <a href=\"http:\/\/www.engadget.com\/2012\/07\/14\/vim-how-to\/\" target=\"_blank\">VIM<\/a> (Free, Mac, Windows, and Linux). VIM has a steeper learning curve than the other two since it's intended for use without mouse input, but <a title=\"VIM Tutorial\" href=\"http:\/\/www.openvim.com\/tutorial.html\" target=\"_blank\">learning it<\/a> can help you <a href=\"http:\/\/www.viemu.com\/a-why-vi-vim.html\" target=\"_blank\">edit your code faster<\/a>.<\/li>\n<\/ul>\n<div class=\"aio-button\"><a target=\"_blank\" href=\"http:\/\/jsfiddle.net\/YXqFj\/embedded\/result\/\" class=\"aio-blue\" title=\"View Demo\"><i class=\"glyphicons glyphicons-play\"><\/i>View Demo<\/a><\/div>\n<div class=\"aio-button\"><a target=\"_blank\" href=\"http:\/\/blog.400pixels.net\/wp-content\/uploads\/2013\/06\/bounce_starter.zip\" class=\"aio-blue\" title=\"Download Starter Files\"><i class=\"glyphicons glyphicons-download-alt\"><\/i>Download Starter Files<\/a><\/div>\n<h2>Step 1: Set up<\/h2>\n<p><span style=\"line-height: 1.714285714; font-size: 1rem;\">You'll find four starter files in the above download<\/span><\/p>\n<ul>\n<li><strong>index.html<\/strong> - contains the 600-by-400 canvas element we'll be drawing on (you can change these dimensions, of course!) and imports the other three files. Open index.html in a modern internet browser (or reload the page if already open) anytime you'd like to test your program<\/li>\n<li><strong>normalize.css<\/strong>\u00a0- a <a title=\"normalize.css\" href=\"http:\/\/necolas.github.io\/normalize.css\/\" target=\"_blank\">normalization stylesheet<\/a> that helps make website styles more consistent across browsers<\/li>\n<li><strong>style.css<\/strong>\u00a0- any other css styling goes here. Edit this file to change the canvas's background color<\/li>\n<li><strong>main.js<\/strong> - we'll write the main code for our program in this file<\/li>\n<\/ul>\n<p>For this tutorial, everything's set up so that we'll only need to modify\u00a0<strong>main.js<\/strong>. Inside <strong>main.js<\/strong> you'll find the following code:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\/*\r\n * runs when index.html is fully loaded\r\n *\/\r\nwindow.onload=function() {\r\n\r\n}\r\n<\/pre>\n<p>Since our onload function is empty, when you open <strong>index.html<\/strong> on your favorite browser, you'll see a website reminiscent of <a href=\"http:\/\/en.wikipedia.org\/wiki\/Kazimir_Malevich\" target=\"_blank\">Kazimir Malevich's<\/a>\u00a0painting\u00a0<i>Black Square<\/i>. Pretty cool, but not exactly what we're looking for.<\/p>\n<h2>Step 2: You're on the ball<\/h2>\n<p>Let's add a ball to our canvas. Modify <strong>main.js<\/strong> so that it looks like this:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\/\/ initialize stage and ball globally\r\nvar stage, ball;\r\n\r\n\/*\r\n * runs when index.html is fully loaded\r\n *\/\r\nwindow.onload=function() {\r\n    \/\/initialize stage object, where &quot;canvas&quot; references the id of our canvas\r\n    stage = new createjs.Stage(&quot;canvas&quot;);\r\n\r\n    \/\/ initialize ball object\r\n    ball = new createjs.Shape();\r\n    \/\/ select ball color to be red.\r\n    ball.graphics.beginFill(&quot;#ff3333&quot;);\r\n    \/\/ draw circle of radius 5 at position (0, 0) relative to the ball's\r\n    \/\/   coordinates\r\n    ball.graphics.drawCircle(0, 0, 5);\r\n    \/\/ set ball object's coordinates\r\n    ball.x = 120;\r\n    ball.y = 50;\r\n    \/\/ add our ball to stage so that it actually gets drawn.\r\n    \/\/ (this needs to be done only once per object)\r\n    stage.addChild(ball);\r\n\r\n    \/\/ draw all shapes to canvas\r\n    stage.update();\r\n}\r\n<\/pre>\n<p>Note that we initialized <code>stage<\/code> and <code>ball<\/code> outside of the <code>onload function<\/code> so that we'll be able to reference them later when we add animation to our program. If you now open <strong>index.html,\u00a0<\/strong>you should see a red ball on a black canvas.<\/p>\n<h2>Step 3: Adding motion<\/h2>\n<p>It's time to get the ball rolling. Lets add the following declarations at the beginning of the file:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">var vx=10, vy=10;<\/pre>\n<p><code>vx<\/code> will represent the ball's velocity in the x direction (negative: left, positive: right) measured in pixels per frame. <code>vy<\/code> will be the velocity in the y direction (negative: up, positive: down). We're initializing both to +10.<br \/>\nNow add the following code right before the the\u00a0<code>onload<\/code>\u00a0function's\u00a0ending curly bracket:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">    createjs.Ticker.setFPS(60);\r\n    createjs.Ticker.addEventListener(&quot;tick&quot;, tick);<\/pre>\n<p>This tells the program to call the function <code>tick()<\/code>\u00a0(which we'll define momentarily) on every \"tick\" event, that is, every 1\/60th of a second.<\/p>\n<p>Add the following function at the end of the file, after the <code>onload<\/code> function:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\/*\r\n * called every frame (60 times per second)\r\n *\/\r\nfunction tick() {\r\n    \/\/ if ball would be out of bounds on the next frame,\r\n    \/\/   make it bounce away from the wall\r\n    if(ball.x+vx&lt;0) {\r\n        vx = Math.abs(vx);     }\r\n    if(ball.x+vx&gt;stage.canvas.width) {\r\n        vx = -1*Math.abs(vx);\r\n    }\r\n    if(ball.y+vy&lt;0) {\r\n         vy = Math.abs(vy);\r\n    }\r\n    if(ball.y+vy&gt;stage.canvas.height) {\r\n        vy = -1*Math.abs(vy);\r\n    }\r\n    \/\/ update the ball's position according to the current velocity\r\n    ball.x += vx;\r\n    ball.y += vy;\r\n\r\n    \/\/ draw all shapes to canvas\r\n    stage.update();\r\n}<\/pre>\n<p>and now the ball bounces off the walls.<\/p>\n<h2>Step 4: Drawing the curve<\/h2>\n<p>As promised, we will make the ball bounce off of a fancy, mathematically defined curve. First, however, we'll need to define our mathematical curve and draw it on the canvas. Add the following function after the\u00a0<code>tick()<\/code>\u00a0function, that is, at the very bottom of <strong>main.js<\/strong>:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\/*\r\n * defines the the shape of curve the ball will be bouncing off of.\r\n * Try playing around with the values inside this function!\r\n *\/\r\nfunction f(x) {\r\n    return 100*Math.sin((2*x)*3.14\/180)+300;\r\n}<\/pre>\n<p>This is a function in the sense you learned in math class: we give it an input number, and it gives us an output number. In this case, it gives us the sine curve you've seen in the end result. Note that the origin (0, 0) of our canvas is the upper-left corner, and that the y-axis increases as we go down the canvas. The x-axis works as usual.<\/p>\n<p>Now, to actually draw the curve to the canvas, we'll approximate it as a series of line segments. Edit the <code>onload<\/code> function so that it looks as follows (where we've highlighted the new code):<\/p>\n<pre class=\"brush: jscript; highlight: [0,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41]; title: ; notranslate\" title=\"\">\r\n\/\/ initialize stage and ball globally\r\nvar stage, ball;\r\n\/\/ set ball velocity\r\nvar vx=10, vy=10;\r\n\r\n\/*\r\n * runs when index.html is fully loaded\r\n *\/\r\nwindow.onload=function() {\r\n    \/\/initialize stage object, where &quot;canvas&quot; references the id of our canvas\r\n    stage = new createjs.Stage(&quot;canvas&quot;);\r\n\r\n    \/\/ initialize ball object\r\n    ball = new createjs.Shape();\r\n    \/\/ select ball color to be light blue.\r\n    ball.graphics.beginFill(&quot;#3399CC&quot;);\r\n    \/\/ draw circle of radius 5 at position (0, 0) relative to the ball's\r\n    \/\/   coordinates\r\n    ball.graphics.drawCircle(0, 0, 5);\r\n    \/\/ set ball object's coordinates\r\n    ball.x = 120;\r\n    ball.y = 50;\r\n    \/\/ add our ball to stage so that it actually gets drawn.\r\n    \/\/ (this needs to be done only once per object)\r\n    stage.addChild(ball);\r\n\r\n    \/\/ initialize curve object\r\n    curve = new createjs.Shape();\r\n    \/\/ set line width to 2px\r\n    curve.graphics.setStrokeStyle(2);\r\n    \/\/ select a random color for the line\r\n    curve.graphics.beginStroke(createjs.Graphics.getRGB(Math.floor(Math.random()*256),\r\n                                  Math.floor(Math.random()*256), Math.floor(Math.random()*256)));\r\n    \/\/ start first line segment at position (0, f(0))\r\n    curve.graphics.moveTo(0, f(0));\r\n    \/\/ keep on drawing line segments to (i, f(i)) as i moves across the width of the canvas\r\n    for(var i=0; i&lt;stage.canvas.width; i++) {\r\n        curve.graphics.lineTo(i, f(i));\r\n    }\r\n    \/\/ add our curve object to stage so that it actually gets drawn.\r\n    stage.addChild(curve);\r\n\r\n    \/\/ draw all shapes to canvas\r\n    stage.update();\r\n\r\n    \/\/ set framerate to 60FPS\r\n    createjs.Ticker.setFPS(60);\r\n    \/\/ call tick(event) on every &quot;tick&quot;\r\n    createjs.Ticker.addEventListener(&quot;tick&quot;, tick);\r\n}<\/pre>\n<p>Where the <code>Math.floor()<\/code> function rounds down and <code>Math.random()<\/code> generates a number in the interval [0, 1), so\u00a0<code>Math.floor(Math.random()*256)<\/code> generates a random number between 0 and 255, inclusive.<\/p>\n<p>At this point you'll see the curve on the screen, but the ball ignores it completely(!)<\/p>\n<h2>Step 5: Detecting curve crossing<\/h2>\n<p>When is the right time to bounce? How do we detect if the ball is about to cross the curve?\u00a0Since our curve is a function in the mathematical sense, we know that there will only be one 'y' value for the curve for each 'x', and assuming our function will be continuous, we can simply check if the ball will be below the curve on the next frame, i.e. if its 'y' value will be greater than the curve's 'y' value.<\/p>\n<p>Add the following code at the very beginning of the tick() function, right after its first opening curly brace:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">    \/\/ check if a crossing is about to happen.\r\n    if((ball.y+vy) &gt;= f(ball.x+vx)) {\r\n        \/\/ if ball would cross the curve on next frame, log the message &quot;crossed&quot; to console\r\n        console.log(&quot;crossed&quot;);\r\n    }<\/pre>\n<p>At this point a new \"crossed\" message will be printed to the javascript console every time the ball crosses the curve. (<a href=\"http:\/\/stackoverflow.com\/questions\/4743730\/what-is-console-log-and-how-do-i-use-it\" target=\"_blank\">This link<\/a> explains how to access the javascript console in different browsers). In some browsers, printing to the javascript console makes the program crash if the console isn't open, so comment out the <code>console.log<\/code> line after you're done testing.<\/p>\n<p>Let's bounce.<\/p>\n<h2>Step 6: Bouncing off the curve<\/h2>\n<p>Our program now knows where the ball hits the curve, but we'll need more information about the direction the curve faces at the collision point to know how the ball will bounce.<\/p>\n<p>Right after the end of the <code>f(x)<\/code> function, define the following function:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\/*\r\n * returns the derivative of f(x) evaluated at x\r\n *\/\r\nfunction dfdx(x) {\r\n    return (f(x+0.00001)-f(x))\/0.00001;\r\n}<\/pre>\n<p>If you've taken Calculus, you'll recognize that <code>dfdx(x)<\/code> is an approximation to the derivative of\u00a0the curve <code>f(x)<\/code>\u00a0we drew earlier. If you haven't taken Calculus, all you need to know is that <code>dfdx(x)<\/code> measures the <a href=\"https:\/\/www.khanacademy.org\/math\/calculus\/differential-calculus\/derivative_intro\/v\/calculus--derivatives-1--new-hd-version\" target=\"_blank\">slope of the curve<\/a> <code>f(x)<\/code> at point x.<\/p>\n<p>When dealing with the four walls, we simply had to change the sign of one of the components of the velocity to make the ball bounce. How do we bounce at an angle?<\/p>\n<p>Once we've defined dfdx(x), we can make the ball bounce by adding the following code right after the commented-out console.log command:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">        var J = dfdx(ball.x);\r\n        var K = 1+J*J;\r\n        var tangentComponent = {x:(vx+vy*J)\/K, y:J*(vx+vy*J)\/K};\r\n        var normalComponent = {x:J*(vx*J-vy)\/K, y:-1*(vx*J-vy)\/K};\r\n        vx = tangentComponent.x - normalComponent.x;\r\n        vy = tangentComponent.y - normalComponent.y;<\/pre>\n<p>This code separates the velocity vector into two component vectors\u2014one tangent to the curve at the collision point and one normal (perpendicular) to it\u2014and then puts the components back together with the perpendicular component flipped.<\/p>\n<p>Now open <strong>index.html<\/strong>. If everything worked well, the ball should now bounce off the curve. Nice!<\/p>\n<h2>Conclusion<\/h2>\n<p>Here concludes this tutorial. For larger projects, remember to <a href=\"http:\/\/www.wikihow.com\/Compress-Javascript\" target=\"_blank\">minify<\/a> your Javascript files before uploading them to make your program load faster. Some Ideas of how to expand this project: \u00a0try\u00a0adding sound, visual effects, gravity, and friction to the\u00a0scene.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial we'll program a simulation of a red rubber ball that bounces off of a sine wave in a frictionless, gravity-less environment (a very typical scenario). We'll be using Javascript, the HTML5 Canvas element, and the easeljs library. This tutorial is different from others I have found in that it internally stores the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-7","post","type-post","status-publish","format-standard","hentry","category-tutorials"],"_links":{"self":[{"href":"https:\/\/blog.400pixels.net\/index.php?rest_route=\/wp\/v2\/posts\/7","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.400pixels.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.400pixels.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.400pixels.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.400pixels.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7"}],"version-history":[{"count":10,"href":"https:\/\/blog.400pixels.net\/index.php?rest_route=\/wp\/v2\/posts\/7\/revisions"}],"predecessor-version":[{"id":487,"href":"https:\/\/blog.400pixels.net\/index.php?rest_route=\/wp\/v2\/posts\/7\/revisions\/487"}],"wp:attachment":[{"href":"https:\/\/blog.400pixels.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.400pixels.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.400pixels.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}