| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // demo parameters | |
| 6 // maybe overridden in test file | |
| 7 var numBalls = parseInt(getArgValue('ball_count')); | |
| 8 if (numBalls == 0 || isNaN(numBalls)) { | |
| 9 numBalls = 500; | |
| 10 } | |
| 11 var ballDiameter = 30; | |
| 12 var gravity = 0.5; //screen heights per second^2 | |
| 13 var maxInitVelocity = 0.2; | |
| 14 var maxAngularVelocity = 5; // rad per second | |
| 15 var elasticity = 0.7; | |
| 16 var joltInterval = 1.5; | |
| 17 | |
| 18 // globals | |
| 19 var balls = []; | |
| 20 var canvasWidth; | |
| 21 var canvasHeight; | |
| 22 var borderX; | |
| 23 var borderY; | |
| 24 var timeOfLastJolt = 0; | |
| 25 | |
| 26 function include(filename) { | |
| 27 var head = document.getElementsByTagName('head')[0]; | |
| 28 var script = document.createElement('script'); | |
| 29 script.src = filename; | |
| 30 script.type = 'text/javascript'; | |
| 31 head.appendChild(script) | |
| 32 } | |
| 33 | |
| 34 include("bouncing_balls_draw_ball_as_" + getArgValue('ball') + ".js"); | |
| 35 include("bouncing_balls_draw_back_as_" + getArgValue('back') + ".js"); | |
| 36 | |
| 37 window.requestAnimFrame = (function(){ | |
| 38 return window.requestAnimationFrame || | |
| 39 window.webkitRequestAnimationFrame || | |
| 40 window.mozRequestAnimationFrame || | |
| 41 window.oRequestAnimationFrame || | |
| 42 window.msRequestAnimationFrame || | |
| 43 function( callback ){ | |
| 44 window.setTimeout(callback, 1000 / 60); | |
| 45 }; | |
| 46 })(); | |
| 47 | |
| 48 window.onload = init; | |
| 49 | |
| 50 function init(){ | |
| 51 handleResize(); | |
| 52 for (var i = 0; i < numBalls; i++) { | |
| 53 balls.push(new Ball()); | |
| 54 } | |
| 55 window.addEventListener("resize", handleResize, false); | |
| 56 drawBallInit(ballDiameter); // externally defined | |
| 57 window.requestAnimFrame(updateFrame); | |
| 58 } | |
| 59 | |
| 60 function handleResize() { | |
| 61 canvasWidth = window.innerWidth; | |
| 62 canvasHeight = window.innerHeight; | |
| 63 canvas.setAttribute('width', canvasWidth); | |
| 64 canvas.setAttribute('height', canvasHeight); | |
| 65 borderX = ballDiameter/canvasWidth; | |
| 66 borderY = ballDiameter/canvasHeight; | |
| 67 prepareBackground(); // externally defined | |
| 68 } | |
| 69 | |
| 70 function updateFrame() { | |
| 71 var now = new Date().getTime() / 1000; | |
| 72 var jolt = false; | |
| 73 if (now - timeOfLastJolt > joltInterval) { | |
| 74 jolt = true; | |
| 75 timeOfLastJolt = now; | |
| 76 } | |
| 77 drawBackground(); // externally defined | |
| 78 for (var i = 0; i < numBalls; i++) { | |
| 79 balls[i].step(jolt); | |
| 80 } | |
| 81 window.requestAnimFrame(updateFrame); | |
| 82 } | |
| 83 | |
| 84 function Ball(){ | |
| 85 var x = borderX + Math.random()*(1-2*borderX); | |
| 86 var y = borderY + Math.random()*(1-2*borderY); | |
| 87 var angle = Math.PI * 2 * Math.random(); | |
| 88 var velocityY = Math.random()*maxInitVelocity*2 - maxInitVelocity; | |
| 89 var velocityX = Math.random()*maxInitVelocity*2 - maxInitVelocity; | |
| 90 var angularVelocity = Math.random()*maxAngularVelocity*2 - | |
| 91 maxAngularVelocity; | |
| 92 var previousFrameTime = new Date().getTime(); | |
| 93 var previousBounceTime = 0; | |
| 94 var alive = true; | |
| 95 function step(jolt) { | |
| 96 var curTime = new Date().getTime(); | |
| 97 var timeStep = (curTime - previousFrameTime) / 1000; | |
| 98 previousFrameTime = curTime; | |
| 99 | |
| 100 // handle balls that are no longer bouncing | |
| 101 if (!alive) { | |
| 102 if (jolt) { | |
| 103 // If a jolt is applied, bump the rollong balls enough for them to | |
| 104 // reach between 0.75x and 1x the height of the window | |
| 105 velocityY = -Math.sqrt(2 * gravity * (1-2 * borderY) * (0.75 + 0.25 * | |
| 106 Math.random())) | |
| 107 velocityX = Math.random()*maxInitVelocity*2 - maxInitVelocity; | |
| 108 angularVelocity = Math.random()*maxAngularVelocity*2 - | |
| 109 maxAngularVelocity; | |
| 110 alive = true; | |
| 111 } else { | |
| 112 // rolling on the ground | |
| 113 angularVelocity = 2*velocityX*canvasWidth/ballDiameter; | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 // Compute angular motion | |
| 118 angle += timeStep*angularVelocity; | |
| 119 // Compute horizontal motion | |
| 120 var remainingTime = timeStep; | |
| 121 var deltaX = velocityX*remainingTime; | |
| 122 while ((x+deltaX) < borderX || (x+deltaX) > (1-borderX)){ | |
| 123 if ((x+deltaX) < borderX) { | |
| 124 // left side bounce | |
| 125 remainingTime -= (borderX - x)/velocityX; | |
| 126 x = borderX; | |
| 127 } else { | |
| 128 // right side bounce | |
| 129 remainingTime -= ((1-borderX) - x)/velocityX; | |
| 130 x = 1 - borderX; | |
| 131 } | |
| 132 velocityX = -elasticity*velocityX; | |
| 133 deltaX = velocityX*remainingTime; | |
| 134 } | |
| 135 x += deltaX; | |
| 136 | |
| 137 // Compute vertical motion | |
| 138 remainingTime = timeStep; | |
| 139 var deltaY = alive ? velocityY*timeStep+gravity*timeStep*timeStep/2 : 0; | |
| 140 //Handle floor bounces | |
| 141 //To make sure the floor is air tight, we must be able to process multiple | |
| 142 //bounces per time step to avoid the "tunnel effect". | |
| 143 while ((y + deltaY) > (1 - borderY) && alive) { | |
| 144 // time to hit floor | |
| 145 var c = y-(1-borderY); | |
| 146 var b = velocityY; | |
| 147 var a = gravity/2; | |
| 148 // The greater root is always the right one | |
| 149 var subStep = (-b + Math.sqrt(b*b-4*a*c))/(2*a); | |
| 150 //velocity after floor hit | |
| 151 velocityY = -elasticity*(velocityY + gravity*subStep); | |
| 152 remainingTime -= subStep; | |
| 153 var bounceTime = curTime - remainingTime; | |
| 154 if (bounceTime - previousBounceTime < 0.005){ | |
| 155 // The number of iterations may not be finite within a timestep | |
| 156 // with elasticity < 1. This is due to power series convergence. | |
| 157 // To gard against hanging, we treat the ball as rolling on the ground | |
| 158 // once time between bounces is less than 5ms | |
| 159 alive = false; | |
| 160 deltaY = 0; | |
| 161 } else { | |
| 162 deltaY = velocityY*remainingTime+gravity*remainingTime*remainingTime/2; | |
| 163 } | |
| 164 previousBounceTime = bounceTime; | |
| 165 y = (1 - borderY); | |
| 166 } | |
| 167 y += deltaY; | |
| 168 velocityY += gravity*remainingTime; | |
| 169 | |
| 170 drawBall(x * canvasWidth, y * canvasHeight, angle); // externally defined | |
| 171 } | |
| 172 | |
| 173 return { | |
| 174 step: step | |
| 175 } | |
| 176 } | |
| OLD | NEW |