Skip to content

Instantly share code, notes, and snippets.

@scottschiller
Created July 10, 2011 03:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scottschiller/1074207 to your computer and use it in GitHub Desktop.
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)
<!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