Created
July 10, 2011 03:07
-
-
Save scottschiller/1074207 to your computer and use it in GitHub Desktop.
A collision-enabled variant of my JavaScript Animation Demo #2, feature added at the request of a public school technology teacher who wrote in. (Teachers showing kids JavaScript in high school FTW! :P)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> | |
<head> | |
<style type="text/css"> | |
body { | |
font:76% normal verdana,arial,tahoma; | |
} | |
h1, h2 { | |
margin:0px; | |
font-size:1.2em; | |
} | |
p { | |
margin:0px 0px 1em 0px; | |
padding:0px; | |
} | |
.balls img { | |
position:absolute; | |
width:12px; | |
height:12px; | |
} | |
</style> | |
<script type="text/javascript"> | |
// <![CDATA[ | |
var balls = []; | |
var canvasX = 0; | |
var canvasY = 0; | |
var timer = null; | |
var m_lastX = 0; | |
var m_lastY = 0; | |
var M_SPACE = 24; | |
var B_VMIN = 5; | |
var B_VMAX = 5; | |
var B_WIDTH = 13; | |
var B_HEIGHT = 13; | |
function rnd(n) { | |
return Math.random()*n; | |
} | |
function rndI(n) { | |
return parseInt(rnd(n)); | |
} | |
function createBall(oParent) { | |
oParent.appendChild(balls[0].cloneNode(false)); | |
initBall(balls[balls.length-1]); | |
} | |
function createBallAtMouse(e) { | |
e = e?e:event; | |
createBall(document.getElementById('ball-container')); | |
with (balls[balls.length-1]) { | |
_x = e.clientX; | |
_y = e.clientY; | |
} | |
} | |
function initBall(oBall) { | |
oBall._x = rnd(canvasX); | |
oBall._y = rnd(canvasY); | |
oBall._vX = B_VMIN + rnd(B_VMAX) * (Math.random() > 0.5 ? 1 : -1); | |
oBall._vY = B_VMIN + rnd(B_VMAX); | |
} | |
function moveBall(oBall) { | |
oBall._x += oBall._vX; | |
oBall._y += oBall._vY; | |
oBall.style.left = oBall._x + 'px'; | |
oBall.style.top = oBall._y + 'px'; | |
if ((oBall._vX > 0 && oBall._x + oBall._vX + B_WIDTH > canvasX) || (oBall._vX < 0 && oBall._x + oBall._vX < 0)) { | |
// horizontal bounce | |
oBall._vX *= -1; | |
} | |
if ((oBall._vY > 0 && oBall._y + oBall._vY + B_HEIGHT > canvasY) || (oBall._vY < 0 && oBall._y + oBall._vY < 0)) { | |
// vertical bounce | |
oBall._vY *= -1; | |
} | |
} | |
function animateStuff() { | |
for (var i=balls.length; i--;) { | |
moveBall(balls[i]); | |
} | |
collisionCheck(); | |
} | |
function isColliding(ball1, ball2) { | |
if (Math.abs(ball1._x - ball2._x) < B_WIDTH && Math.abs(ball1._y - ball2._y) < B_HEIGHT) { | |
/* | |
* we have a collision! | |
* edge case to consider: balls may get stuck colliding back and forth | |
* between each other for a few frames if they don't fully "separate" | |
* from each other in one frame of motion. | |
*/ | |
return true; | |
} else { | |
return false; | |
} | |
} | |
function collisionCheck() { | |
// simple loop through all the ball objects, comparing coordinates | |
var i, j; | |
for (i = balls.length; i--;) { | |
for (j = balls.length; j--;) { | |
if (j !== i) { // don't compare each ball to itself | |
if (isColliding(balls[j], balls[i])) { | |
// bounce the ball based on its dominant direction (horizontal or vertical movement) | |
if (Math.abs(balls[j]._vX) > Math.abs(balls[j]._vY)) { | |
// moving more horizontally | |
balls[j]._vX *= -1; | |
} else if (Math.abs(balls[j]._vY) > Math.abs(balls[j]._vX)) { | |
// moving more vertically | |
balls[j]._vY *= -1; | |
} else { | |
// edge case: if identical speed on x/y, bounce both | |
balls[j]._vX *= -1; | |
balls[j]._vY *= -1; | |
} | |
} | |
} | |
} | |
} | |
} | |
function startAnimation() { | |
if (!timer) { | |
timer = setInterval(animateStuff,20); | |
} | |
} | |
function stopAnimation() { | |
if (!timer) { | |
return false; | |
} | |
clearInterval(timer); | |
timer = null; | |
} | |
function mouseDown(e) { | |
e = e?e:event; | |
m_lastX = e.clientX; | |
m_lastY = e.clientY; | |
document.onmousemove = mouseMove; | |
document.onmouseup = mouseUp; | |
} | |
function mouseMove(e) { | |
e = e?e:event; | |
if (Math.abs(e.clientX - m_lastX) > M_SPACE || Math.abs(e.clientY - m_lastY) > M_SPACE) { | |
m_lastX = e.clientX; | |
m_lastY = e.clientY; | |
createBallAtMouse(e); | |
} | |
return false; | |
} | |
function mouseUp() { | |
document.onmousemove = null; | |
document.onmouseup = null; | |
} | |
function init() { | |
balls = document.getElementById('ball-container').getElementsByTagName('img'); | |
for (var i=balls.length; i--;) { | |
initBall(balls[i]); | |
} | |
getWindowCoords(); | |
startAnimation(); | |
document.onmousedown = mouseDown; | |
} | |
getWindowCoords = (navigator.userAgent.match(/opera/i) || navigator.userAgent.match(/safari/i)) ? function() { | |
canvasX = window.innerWidth; | |
canvasY = window.innerHeight; | |
} : function() { | |
canvasX = document.documentElement.clientWidth||document.body.clientWidth||document.body.scrollWidth; | |
canvasY = document.documentElement.clientHeight||document.body.clientHeight||document.body.scrollHeight; | |
} | |
window.onresize = getWindowCoords; | |
window.onload = init; | |
// ]]> | |
</script> | |
</head> | |
<body> | |
<h1>Interval-based animation</h1> | |
<p> | |
Click and drag to create more. | |
</p> | |
<p> | |
<button onclick="startAnimation()">Start</button> | |
<button onclick="stopAnimation()">Stop</button> | |
</p> | |
<div id="ball-container" class="balls"> | |
<img src="http://www.schillmania.com/content/projects/javascript-animation-2/demo/ball.gif" alt="" /> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment