Skip to content

Instantly share code, notes, and snippets.

@angus-c
Created September 23, 2014 16:39
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 angus-c/eeb5ad933009105dc673 to your computer and use it in GitHub Desktop.
Save angus-c/eeb5ad933009105dc673 to your computer and use it in GitHub Desktop.
A Bouncing Ball // source http://jsbin.com/hidori/11
<!DOCTYPE html>
<html>
<head>
<title>A Bouncing Ball</title>
</head>
<body>
<canvas id="canvas" width="300" height="300"></canvas>
<input id="delay" type="range" max="2000" value="10"/>
<script id="jsbin-javascript">
var ballCount = 1;
var ballSize = 10;
var delay = 1;
var interval;
var colors = ['black', 'blue', 'fuschia', 'green', 'coral', 'gray', 'navy', 'purple', 'olive', 'red']
var map;
window.onload = function() {
document.getElementById('delay').addEventListener(
'change',
function(e) {
clearInterval(interval);
interval = setInterval(renderBalls, e.target.value);
}
);
}
var Ball = function (xSpeed, ySpeed, magic, color) {
this.x = 300*Math.random();
this.y = 300*Math.random();
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.magic = magic;
this.movesSinceCollision = 0;
this.color = color;
};
var circle = function (x, y, radius, fillCircle, color) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
if (fillCircle) {
ctx.fillStyle=color;
ctx.fill();
} else {
ctx.stroke();
}
};
Ball.prototype.draw = function () {
circle(this.x, this.y, ballSize, true, this.color);
};
Ball.prototype.move = function () {
this.x += this.xSpeed;
this.y += this.ySpeed;
this.movesSinceCollision++;
};
Ball.prototype.checkCollision = function () {
var xE = this.x + ballSize + 2;
var xxE = this.x + Math.pow((ballSize*ballSize/2), 0.5);
var xW = this.x - ballSize - 2;
var xxW = this.x - Math.pow((ballSize*ballSize/2), 0.5);
var yN = this.y - ballSize - 2;
var yyN = this.y - Math.pow((ballSize*ballSize/2), 0.5);
var yS = this.y + ballSize + 2;
var yyS = this.y + Math.pow((ballSize*ballSize/2), 0.5);
var probe = {
e: getOpacityAt(xE, this.y),
w: getOpacityAt(xW, this.y),
n: getOpacityAt(this.x, yN),
s: getOpacityAt(this.x, yS),
ne: getOpacityAt(xxE + 1, yyN - 1),
se: getOpacityAt(xxE + 1, yyS + 1),
nw: getOpacityAt(xxW - 1, yyN - 1),
sw: getOpacityAt(xxW - 1, yyS + 1)
}
function getOpacityAt(x, y) {
return map[(Math.round(x) + Math.round(y)*300)*4 -1];
}
if (probe.e) {
this.xSpeed = -Math.abs(this.xSpeed);
this.afterCollision(probe);
} else if (probe.w) {
this.xSpeed = Math.abs(this.xSpeed);
this.afterCollision(probe);
} else if (probe.n) {
this.ySpeed = Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.s) {
this.ySpeed = -Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.ne) {
this.xSpeed = -Math.abs(this.xSpeed);
this.ySpeed = Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.se) {
this.xSpeed = -Math.abs(this.xSpeed);
this.ySpeed = -Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.nw) {
this.xSpeed = Math.abs(this.xSpeed);
this.ySpeed = Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.sw) {
this.xSpeed = Math.abs(this.xSpeed);
this.ySpeed = -Math.abs(this.ySpeed);
this.afterCollision(probe);
}
// ctx.fillStyle="red";
// ctx.fillRect(xE, this.y, 1, 1);
// ctx.fillRect(xW, this.y, 1, 1);
// ctx.fillRect(this.x, yN, 1, 1);
// ctx.fillRect(this.x, yS, 1, 1);
// ctx.fillRect(xxE+1, yyN-1, 1, 1);
// ctx.fillRect(xxE+1, yyS+1, 1, 1);
// ctx.fillRect(xxW-1, yyN-1, 1, 1);
// ctx.fillRect(xxW-1, yyS+1, 1, 1);
};
Ball.prototype.afterCollision = function(probe) {
if (!this.movesSinceCollision) {
console.log('pos:', this.x, this.y);
console.log(
Object.keys(probe).filter(
function(k) {return Number(probe[k])}
)
);
}
if (this.magic) {
// console.log(Object.keys(probe).filter(
// function(k) {return Number(probe[k])}
// ));
// console.log('sX', this.xSpeed, 'sY', this.ySpeed);
}
this.movesSinceCollision = 0;
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var balls = [];
for (var i = 0; i < ballCount; i++) {
balls[i] = new Ball(
1 - 2*Math.random(),
1 - 2*Math.random(),
i == 0,
colors[i]
);
}
interval = setInterval(renderBalls, delay);
function renderBalls() {
ctx.clearRect(0, 0, 300, 300);
ctx.strokeRect(0, 0, 300, 300);
for (var i = 0; i < ballCount; i++)
balls[i].draw();
map = ctx.getImageData(0, 0, 300, 300).data;
for (var i = 0; i < ballCount; i++)
balls[i].checkCollision();
for (var i = 0; i < ballCount; i++)
balls[i].move();
}
</script>
<script id="jsbin-source-javascript" type="text/javascript"> var ballCount = 1;
var ballSize = 10;
var delay = 1;
var interval;
var colors = ['black', 'blue', 'fuschia', 'green', 'coral', 'gray', 'navy', 'purple', 'olive', 'red']
var map;
window.onload = function() {
document.getElementById('delay').addEventListener(
'change',
function(e) {
clearInterval(interval);
interval = setInterval(renderBalls, e.target.value);
}
);
}
var Ball = function (xSpeed, ySpeed, magic, color) {
this.x = 300*Math.random();
this.y = 300*Math.random();
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.magic = magic;
this.movesSinceCollision = 0;
this.color = color;
};
var circle = function (x, y, radius, fillCircle, color) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
if (fillCircle) {
ctx.fillStyle=color;
ctx.fill();
} else {
ctx.stroke();
}
};
Ball.prototype.draw = function () {
circle(this.x, this.y, ballSize, true, this.color);
};
Ball.prototype.move = function () {
this.x += this.xSpeed;
this.y += this.ySpeed;
this.movesSinceCollision++;
};
Ball.prototype.checkCollision = function () {
var xE = this.x + ballSize + 2;
var xxE = this.x + Math.pow((ballSize*ballSize/2), 0.5);
var xW = this.x - ballSize - 2;
var xxW = this.x - Math.pow((ballSize*ballSize/2), 0.5);
var yN = this.y - ballSize - 2;
var yyN = this.y - Math.pow((ballSize*ballSize/2), 0.5);
var yS = this.y + ballSize + 2;
var yyS = this.y + Math.pow((ballSize*ballSize/2), 0.5);
var probe = {
e: getOpacityAt(xE, this.y),
w: getOpacityAt(xW, this.y),
n: getOpacityAt(this.x, yN),
s: getOpacityAt(this.x, yS),
ne: getOpacityAt(xxE + 1, yyN - 1),
se: getOpacityAt(xxE + 1, yyS + 1),
nw: getOpacityAt(xxW - 1, yyN - 1),
sw: getOpacityAt(xxW - 1, yyS + 1)
}
function getOpacityAt(x, y) {
return map[(Math.round(x) + Math.round(y)*300)*4 -1];
}
if (probe.e) {
this.xSpeed = -Math.abs(this.xSpeed);
this.afterCollision(probe);
} else if (probe.w) {
this.xSpeed = Math.abs(this.xSpeed);
this.afterCollision(probe);
} else if (probe.n) {
this.ySpeed = Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.s) {
this.ySpeed = -Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.ne) {
this.xSpeed = -Math.abs(this.xSpeed);
this.ySpeed = Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.se) {
this.xSpeed = -Math.abs(this.xSpeed);
this.ySpeed = -Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.nw) {
this.xSpeed = Math.abs(this.xSpeed);
this.ySpeed = Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.sw) {
this.xSpeed = Math.abs(this.xSpeed);
this.ySpeed = -Math.abs(this.ySpeed);
this.afterCollision(probe);
}
// ctx.fillStyle="red";
// ctx.fillRect(xE, this.y, 1, 1);
// ctx.fillRect(xW, this.y, 1, 1);
// ctx.fillRect(this.x, yN, 1, 1);
// ctx.fillRect(this.x, yS, 1, 1);
// ctx.fillRect(xxE+1, yyN-1, 1, 1);
// ctx.fillRect(xxE+1, yyS+1, 1, 1);
// ctx.fillRect(xxW-1, yyN-1, 1, 1);
// ctx.fillRect(xxW-1, yyS+1, 1, 1);
};
Ball.prototype.afterCollision = function(probe) {
if (!this.movesSinceCollision) {
console.log('pos:', this.x, this.y);
console.log(
Object.keys(probe).filter(
function(k) {return Number(probe[k])}
)
);
}
if (this.magic) {
// console.log(Object.keys(probe).filter(
// function(k) {return Number(probe[k])}
// ));
// console.log('sX', this.xSpeed, 'sY', this.ySpeed);
}
this.movesSinceCollision = 0;
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var balls = [];
for (var i = 0; i < ballCount; i++) {
balls[i] = new Ball(
1 - 2*Math.random(),
1 - 2*Math.random(),
i == 0,
colors[i]
);
}
interval = setInterval(renderBalls, delay);
function renderBalls() {
ctx.clearRect(0, 0, 300, 300);
ctx.strokeRect(0, 0, 300, 300);
for (var i = 0; i < ballCount; i++)
balls[i].draw();
map = ctx.getImageData(0, 0, 300, 300).data;
for (var i = 0; i < ballCount; i++)
balls[i].checkCollision();
for (var i = 0; i < ballCount; i++)
balls[i].move();
}
</script></body>
</html>
var ballCount = 1;
var ballSize = 10;
var delay = 1;
var interval;
var colors = ['black', 'blue', 'fuschia', 'green', 'coral', 'gray', 'navy', 'purple', 'olive', 'red']
var map;
window.onload = function() {
document.getElementById('delay').addEventListener(
'change',
function(e) {
clearInterval(interval);
interval = setInterval(renderBalls, e.target.value);
}
);
}
var Ball = function (xSpeed, ySpeed, magic, color) {
this.x = 300*Math.random();
this.y = 300*Math.random();
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.magic = magic;
this.movesSinceCollision = 0;
this.color = color;
};
var circle = function (x, y, radius, fillCircle, color) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
if (fillCircle) {
ctx.fillStyle=color;
ctx.fill();
} else {
ctx.stroke();
}
};
Ball.prototype.draw = function () {
circle(this.x, this.y, ballSize, true, this.color);
};
Ball.prototype.move = function () {
this.x += this.xSpeed;
this.y += this.ySpeed;
this.movesSinceCollision++;
};
Ball.prototype.checkCollision = function () {
var xE = this.x + ballSize + 2;
var xxE = this.x + Math.pow((ballSize*ballSize/2), 0.5);
var xW = this.x - ballSize - 2;
var xxW = this.x - Math.pow((ballSize*ballSize/2), 0.5);
var yN = this.y - ballSize - 2;
var yyN = this.y - Math.pow((ballSize*ballSize/2), 0.5);
var yS = this.y + ballSize + 2;
var yyS = this.y + Math.pow((ballSize*ballSize/2), 0.5);
var probe = {
e: getOpacityAt(xE, this.y),
w: getOpacityAt(xW, this.y),
n: getOpacityAt(this.x, yN),
s: getOpacityAt(this.x, yS),
ne: getOpacityAt(xxE + 1, yyN - 1),
se: getOpacityAt(xxE + 1, yyS + 1),
nw: getOpacityAt(xxW - 1, yyN - 1),
sw: getOpacityAt(xxW - 1, yyS + 1)
}
function getOpacityAt(x, y) {
return map[(Math.round(x) + Math.round(y)*300)*4 -1];
}
if (probe.e) {
this.xSpeed = -Math.abs(this.xSpeed);
this.afterCollision(probe);
} else if (probe.w) {
this.xSpeed = Math.abs(this.xSpeed);
this.afterCollision(probe);
} else if (probe.n) {
this.ySpeed = Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.s) {
this.ySpeed = -Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.ne) {
this.xSpeed = -Math.abs(this.xSpeed);
this.ySpeed = Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.se) {
this.xSpeed = -Math.abs(this.xSpeed);
this.ySpeed = -Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.nw) {
this.xSpeed = Math.abs(this.xSpeed);
this.ySpeed = Math.abs(this.ySpeed);
this.afterCollision(probe);
} else if (probe.sw) {
this.xSpeed = Math.abs(this.xSpeed);
this.ySpeed = -Math.abs(this.ySpeed);
this.afterCollision(probe);
}
// ctx.fillStyle="red";
// ctx.fillRect(xE, this.y, 1, 1);
// ctx.fillRect(xW, this.y, 1, 1);
// ctx.fillRect(this.x, yN, 1, 1);
// ctx.fillRect(this.x, yS, 1, 1);
// ctx.fillRect(xxE+1, yyN-1, 1, 1);
// ctx.fillRect(xxE+1, yyS+1, 1, 1);
// ctx.fillRect(xxW-1, yyN-1, 1, 1);
// ctx.fillRect(xxW-1, yyS+1, 1, 1);
};
Ball.prototype.afterCollision = function(probe) {
if (!this.movesSinceCollision) {
console.log('pos:', this.x, this.y);
console.log(
Object.keys(probe).filter(
function(k) {return Number(probe[k])}
)
);
}
if (this.magic) {
// console.log(Object.keys(probe).filter(
// function(k) {return Number(probe[k])}
// ));
// console.log('sX', this.xSpeed, 'sY', this.ySpeed);
}
this.movesSinceCollision = 0;
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var balls = [];
for (var i = 0; i < ballCount; i++) {
balls[i] = new Ball(
1 - 2*Math.random(),
1 - 2*Math.random(),
i == 0,
colors[i]
);
}
interval = setInterval(renderBalls, delay);
function renderBalls() {
ctx.clearRect(0, 0, 300, 300);
ctx.strokeRect(0, 0, 300, 300);
for (var i = 0; i < ballCount; i++)
balls[i].draw();
map = ctx.getImageData(0, 0, 300, 300).data;
for (var i = 0; i < ballCount; i++)
balls[i].checkCollision();
for (var i = 0; i < ballCount; i++)
balls[i].move();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment