Skip to content

Instantly share code, notes, and snippets.

@termat
Created March 14, 2019 14:02
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 termat/76628d05f973a09d485a0bab4ab0b851 to your computer and use it in GitHub Desktop.
Save termat/76628d05f973a09d485a0bab4ab0b851 to your computer and use it in GitHub Desktop.
Ball
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Ball</title>
</head>
<body>
<table border="1"><tr><td>
<canvas id="canvas" width="460" height="460"></canvas>
</td></tr></table>
</body>
</html>
var ctx;
var balls=new Array();
var WIDTH;
var HEIGHT;
var isDown=false;
var addBall=false;
var mx;
var my;
var px;
var py;
$(document).ready(function() {
var canvas = document.getElementById('canvas');
ctx=canvas.getContext('2d');
WIDTH=canvas.width;
HEIGHT=canvas.height;
init();
$('#canvas').mousedown(function(event) {
isDown=true;
mx=event.pageX; px=mx;
my=event.pageY; py=my;
});
$('#canvas').mousemove(function(event) {
if(!isDown)return;
px=event.pageX;
py=event.pageY;
});
$('#canvas').mouseup(function(event) {
isDown=false;
addBall=true;
});
var timer = setInterval("update()", 10);
});
function init(){
while(balls.length<5){
var xx=420*Math.random()+20;
var yy=420*Math.random()+20;
var rr=20*Math.random()+5;
var b=new Ball(xx,yy,rr);
if(checkBall(b))balls[balls.length]=b;
}
}
function update(){
ctx.clearRect(0,0,WIDTH,HEIGHT);
for(var i=0;i<10;i++){
for(var j=0;j<balls.length;j++)balls[j].move(10);
for(var j=0;j<balls.length;j++){
for(var k=j+1;k<balls.length;k++){
collision(balls[j],balls[k]);
}
}
}
for(var i=0;i<balls.length;i++)balls[i].update(ctx);
if(isDown){
var dx = px - mx;
var dy = py - my;
var lg = Math.sqrt(dx * dx + dy * dy);
var rad = Math.min(40,200 / (lg / 10 + 1));
ctx.beginPath();
ctx.moveTo(mx,my);
ctx.lineTo(px,py);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.arc(mx, my, rad, 0, 2*Math.PI, true);
ctx.stroke();
}
if(addBall){
var dx = px - mx;
var dy = py - my;
var lg = Math.sqrt(dx * dx + dy * dy);
var rad = Math.min(40,200 / (lg / 10 + 1));
var b=new Ball(mx,my,rad);
b.vx=dx/10;
b.vy=dy/10;
if(checkBall(b)){
balls[balls.length]=b;
addBall=false;
}
}
}
function checkBall(b){
for(var i=0;i<balls.length;i++){
var dx = b.x - balls[i].x;
var dy = b.y - balls[i].y;
var lg = Math.sqrt(dx * dx + dy * dy);
if(b.r+balls[i].r>lg)return false;
}
return true;
}
function collision(b0,b1){
var pvx = b1.x - b0.x;
var pvy = b1.y - b0.y;
var len = Math.sqrt(pvx*pvx+pvy*pvy);
if (len < b0.r + b1.r) {
var theta = Math.atan2(pvy, pvx);
var sine = Math.sin(theta);
var cosine = Math.cos(theta);
var tmp0x = 0;
var tmp0y = 0;
var tmp1x = cosine * pvx + sine * pvy;
var tmp1y = cosine * pvy - sine * pvx;
var tmp0vx = cosine * b0.vx + sine * b0.vy;
var tmp0vy = cosine * b0.vy - sine * b0.vx;
var tmp1vx = cosine * b1.vx + sine * b1.vy;
var tmp1vy = cosine * b1.vy - sine * b1.vx;
var fp0vx = ((b0.m - b1.m) * tmp0vx + 2 * b1.m * tmp1vx) / (b0.m + b1.m);
var fp0vy = tmp0vy;
var fp1vx = ((b1.m - b0.m) * tmp1vx + 2 * b0.m * tmp0vx) / (b0.m + b1.m);
var fp1vy = tmp1vy;
tmp0x += fp0vx;
tmp1x += fp1vx;
var pf0x = cosine * tmp0x - sine * tmp0y;
var pf0y = cosine * tmp0y + sine * tmp0x;
var pf1x = cosine * tmp1x - sine * tmp1y;
var pf1y = cosine * tmp1y + sine * tmp1x;
b1.x = b0.x + pf1x;
b1.y = b0.y + pf1y;
b0.x = b0.x + pf0x;
b0.y = b0.y + pf0y;
b0.vx = cosine * fp0vx - sine * fp0vy;
b0.vy = cosine * fp0vy + sine * fp0vx;
b1.vx = cosine * fp1vx - sine * fp1vy;
b1.vy = cosine * fp1vy + sine * fp1vx;
pvx = b1.x - b0.x;
pvy = b1.y - b0.y;
while (Math.sqrt(pvx * pvx + pvy * pvy) < b0.r + b1.r) {
b0.x += b0.vx; b0.y += b0.vy;
b1.x += b1.vx; b1.y += b1.vy;
pvx = b1.x - b0.x;
pvy = b1.y - b0.y;
}
}
}
var Ball=function(_x,_y,_r){
this.x=_x;
this.y=_y;
this.r=_r;
this.m=this.r*0.1;
this.vx=0;
this.vy=0;
this.deg=0;
this.color=getColor(360*Math.random(),0.9,1.0);
this.update=function(ctx){
ctx.beginPath();
ctx.stroke();
ctx.strokeStyle="rgb(200,200,200)";
ctx.fillStyle=this.color;
ctx.arc(this.x, this.y, this.r, 0, 2*Math.PI, true);
ctx.stroke();
ctx.fillStyle=this.color;
var ss=this.r*0.4;
var grad=ctx.createRadialGradient(this.x-ss,this.y-ss,ss,this.x-ss,this.y-ss,2*ss);
grad.addColorStop(0,'white');
grad.addColorStop(1,ctx.fillStyle);
ctx.fillStyle = grad;
ctx.fill();
ctx.closePath();
};
this.move=function(n){
this.x += this.vx/n;
this.y += this.vy/n;
this.checkBoundaryCollision();
}
this.checkBoundaryCollision=function(){
if (this.x > WIDTH-this.r&&this.vx>0){
this.x = WIDTH-this.r;
this.vx *= -0.95;
return true;
} else if (this.x < this.r&&this.vx<0){
this.x = this.r;
this.vx *= -0.95;
return true;
} else if (this.y > HEIGHT-this.r&&this.vy>0){
this.y = HEIGHT-this.r;
this.vy *= -0.95;
return true;
} else if (this.y < this.r&&this.vy<0){
this.y = this.r;
this.vy *= -0.95;
return true;
}
return false;
}
}
function getColor(i, s, v){
var h = i / 60;
var ii = Math.floor(h);
var ff = h - ii;
var p1 = (v - s);
var p2 = (v - s * ff);
var p3 = (v - s * (v - ff));
var rv, gv, bv;
switch(ii) {
case 0:
rv = v, gv = p3, bv = p1;
break;
case 1:
rv = p2, gv = v, bv = p1;
break;
case 2:
rv = p1, gv = v, bv = p3;
break;
case 3:
rv = p1, gv = p2, bv = v;
break;
case 4:
rv = p3, gv = p1, bv = v;
break;
default:
rv = v, gv = p1, bv = p2;
}
var color = Math.max(0, Math.min(255, Math.round(rv * 255)))+","+Math.max(0, Math.min(255, Math.round(gv * 255)))+","+Math.max(0, Math.min(255, Math.round(bv * 255)));
return "rgb("+color+")";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment