NOW, THIS IS SNOOKER!
Can you pot all the balls? Have a go!
var ballsPotted=[];
var world=new PhysicsWorld();
world.on("pocketed",function(type){
if(type=="cueBall"){
firstStrike=true;
}
ai.setLastColor(type);
//if potted color then replace ball if reds still in play
if(type!="red"){
ballsPotted.push(type);
}
});
var firstStrike=true;
var fixedTimeStep = 1.0 / 120.0; // seconds
var maxSubSteps = 3;
var MODE_AIM=0;
var MODE_VIEW=1;
var MODE_SHOOT=2;
var MODE_PLACE=3;
var mode=MODE_VIEW;
var scene=new Scene();
scene.on("progress",function(progress){
document.getElementById("progressbar").style.width=(progress*100)+"%";
});
scene.on("loaded",function(){
document.getElementById("progressbar").style.width="100%";
setTimeout(function(){
document.getElementById("loadingscreen").style.opacity="0";
start();
setTimeout(function(){
document.getElementById("loadingscreen").style.display="none";
},1000);
},1000);
});
var cannonDebugRenderer = new THREE.CannonDebugRenderer( scene.scene, world.world );
scene.render();
/*green: 51, 230
yellow: 97, 230
brown: 74, 230
blue: 74,146
pink: 74,75
blank: 74,30
redfront: 74, 70*/
var tableDef={
redFront: [TABLE_HEIGHT/2, 2.175],
balls:[
['blank', 0x000000, TABLE_HEIGHT/2,2.575],
['pink', 0xd97bc6, TABLE_HEIGHT/2,2.1],
['blue', 0x356da6, TABLE_HEIGHT/2,1.415],
['brown', 0x684141, TABLE_HEIGHT/2, 0.575],
['green', 0x367e2d, TABLE_HEIGHT/3-BALL_RADIUS, 0.575],
['yellow', 0xe3d641, TABLE_HEIGHT/3*2+BALL_RADIUS, 0.575]
]
}
var startY=tableDef.redFront[0];
var startX=tableDef.redFront[1];
/*
var virtualBalls=[];
for(var x=1;x<20;x++){
virtualBalls.push(scene.addBall(0xffffff))
}*/
var balls3d=[];
for(var x=1;x<6;x++){
for(y=0;y1){
x/=l;
y/=l;
}
targetPoint[0]=x;
targetPoint[1]=y;
balltarget.style.left=(50+x*50)+"%";
balltarget.style.top=(50+y*50)+"%";
scene.setCuePoint(x,y);
updateCue();
};
var getCameraPosition=function(){
switch(mode){
case MODE_VIEW:
case MODE_SHOOT:
case MODE_PLACE:
var a = new THREE.Euler( cameraRotation[1], 0,-cameraRotation[0], 'ZXY' );
var b = new THREE.Vector3( 0, 3, 0 );
var c = b.applyEuler(a);
break;
case MODE_AIM:
var a = new THREE.Euler( cueRotation[1], 0,-cueRotation[0], 'ZXY' );
var b = new THREE.Vector3( 0, 0.5, 0 );
var c = b.applyEuler(a);
c.x+=world.cueBall.position.x;
c.y+=world.cueBall.position.y;
c.z+=BALL_RADIUS*6;;
break;
}
return c;
};
var zero=new THREE.Vector3( 0, 0, 0 );
var cameraspeed=50;
var updateCamera=function(){
var view=mode==MODE_AIM?new THREE.Vector3( world.cueBall.position.x, world.cueBall.position.y, BALL_RADIUS*5 ):zero;
scene.setCamera(getCameraPosition(),view,cameraspeed);
};
updateCamera();
var power=0;
var shootStart=0;
var updateTable=function(){
for(var i=0;i0){
var dt=Math.min(1,(+new Date-shootStart)/200);
var p=(power-(Math.pow(dt,1.5)*power));
scene.setCueOffset(p*BALL_RADIUS*5);
cuepower.firstChild.style.height=(p*100)+"0%";
if(dt==1){
shootStart=0;
}
}
//debug
/*var b=ai.getVirtualBalls(balls3d)
for(var i=0;i0){
validBalls.push([balls[i],balls3d[i]]);
}
}
//next step find balls close to ray
var ballsOnPath=[];
var origin_distance=direction.x*origin.y-direction.y*origin.x;
for(var i=0;i0){
firstStrike=false;
setCanShoot(false);
//hide lines
scene.setPrimaryLine(0,0,0,0);
scene.setBounceLine(0,0,0,0);
scene.setBallLine(0,0,0,0);
//calc vector and position
var vec=(new THREE.Vector4(0,1,0,0)).applyMatrix4(scene.cue.matrix);
var d=Math.sqrt(1-targetPoint[0]*targetPoint[0]-targetPoint[1]*targetPoint[1]);
var point=(new THREE.Vector4(-targetPoint[0]*BALL_RADIUS,0,-targetPoint[1]*BALL_RADIUS,1)).applyMatrix4(scene.cue.matrix);
//var point=(new THREE.Vector4(-targetPoint[1]*BALL_RADIUS,0,-targetPoint[0]*BALL_RADIUS,1)).applyMatrix4(scene.cue.matrix);
point.x+=vec.x*d;
point.y+=vec.y*d;
point.z+=vec.z*d;
setTimeout(function(){
shootStart=+new Date;
setTimeout(function(){
setMode(MODE_SHOOT);
world.cueBall.applyImpulse(
new CANNON.Vec3(-vec.x*power*MAXPOWER, -vec.y*power*MAXPOWER, -vec.z*power*MAXPOWER),
new CANNON.Vec3(point.x, point.y, point.z)
);
power=0;
},200);
},mode==MODE_VIEW?10:1000);
cameraRotation=[0,1.54];
setViewButton(MODE_VIEW,false);
updateCamera();
}
};
var updateBallPlacement=function(x,y){
if(x>-0.8625) x=-0.8625;
var dx=x+0.8625;
var dy=y;
var l=Math.sqrt(dx*dx+dy*dy);
if(l>TABLE_HEIGHT/6){
x=dx/l*TABLE_HEIGHT/6-0.8625;
y=dy/l*TABLE_HEIGHT/6;
}
world.cueBall.position.x=x;
world.cueBall.position.y=y;
scene.doRender=true;
};
var powerdrag=false;
var cueDown=function(x,y){
if(canshoot){
powerdrag=[x,y];
}
};
var pointdrag=false;
var ballDown=function(x,y){
pointdrag=true;
ballpoint.style.opacity=1;
var x=x-ballpoint.offsetLeft;
var y=y-ballpoint.offsetTop;
setBallPoint(x*2/ballpoint.offsetWidth-1,y*2/ballpoint.offsetHeight-1)
};
var ballMove=function(x,y){
if(pointdrag){
ballDown(x,y);
}
};
var viewdrag=false;
var cursordrag=false;
var canvasDown=function(x,y){
cameraspeed=10;
switch(mode){
case MODE_VIEW:
case MODE_SHOOT:
viewdrag=[x,y,cameraRotation[0],cameraRotation[1]];
break;
case MODE_AIM:
viewdrag=[x,y,cueRotation[0],cueRotation[1]];
break;
case MODE_PLACE:
cursordrag=[x,y,world.cueBall.position.x,world.cueBall.position.y];
break;
}
};
var documentMove=function(x,y){
if(viewdrag){
var dx=x-viewdrag[0];
var dy=y-viewdrag[1];
switch(mode){
case MODE_VIEW:
case MODE_SHOOT:
cameraRotation[0]=viewdrag[2]+dx/innerWidth*5;
cameraRotation[1]=viewdrag[3]+dy/innerWidth*5;
cameraRotation[1]=Math.max(0.25,Math.min(1.54,cameraRotation[1]));
cameraRotation[0]=cameraRotation[0]%(Math.PI*2);
break;
case MODE_AIM:
cueRotation[0]=viewdrag[2]+dx/innerWidth*2;
cueRotation[1]=viewdrag[3]+dy/innerWidth*2;
cueRotation[1]=Math.max(0.1,Math.min(0.75,cueRotation[1]));
cueRotation[0]=cueRotation[0]%(Math.PI*2);
break;
}
updateCamera();
updateCue();
scene.doRender=true;
}
if(powerdrag){
var dy=y-powerdrag[1];
power=Math.max(0,Math.min(1,dy/(cuepower.offsetHeight*0.8)));
cuepower.firstChild.style.height=(power*100)+"%";
scene.setCueOffset(power*BALL_RADIUS*5);
}
if(cursordrag){
var dx=x-cursordrag[0];
var dy=y-cursordrag[1];
updateBallPlacement(cursordrag[2]-dx/innerHeight,cursordrag[3]+dy/innerHeight);
scene.doRender=true;
};
};
var documentUp=function(e){
viewdrag=false;
powerdrag=false;
pointdrag=false;
cursordrag=false;
ballpoint.style.opacity="";
if(power>0) shoot();
};
document.onmousemove=function(e){
documentMove(e.pageX,e.pageY);
};
document.onmouseup=function(e){
documentUp();
};
scene.canvas.onmousedown=function(e){
canvasDown(e.pageX,e.pageY);
};
ballpoint.onmousedown=function(e){
pointdrag=true;
var x=e.clientX-ballpoint.offsetLeft;
var y=e.clientY-ballpoint.offsetTop;
setBallPoint(x*2/ballpoint.offsetWidth-1,y*2/ballpoint.offsetHeight-1)
};
ballpoint.onmousemove=function(e){
ballMove(e.clientX,e.clientY);
};
ballpoint.onmousedown=function(e){
ballDown(e.clientX,e.clientY);
};
cuepower.onmousedown=function(e){
cueDown(e.clientX,e.clientY);
};
scene.canvas.addEventListener("touchstart",function(e){
canvasDown(e.touches[0].pageX,e.touches[0].pageY);
});
ballpoint.addEventListener("touchstart",function(e){
ballDown(e.touches[0].clientX,e.touches[0].clientY);
});
cuepower.addEventListener("touchstart",function(e){
cueDown(e.touches[0].clientX,e.touches[0].clientY);
});
ballpoint.addEventListener("touchmove",function(e){
ballMove(e.touches[0].clientX,e.touches[0].clientY);
});
document.addEventListener("touchmove",function(e){
documentMove(e.touches[0].pageX,e.touches[0].pageY);
});
document.addEventListener("touchend",function(e){
documentUp();
});
modebutton.onclick=function(){
cameraspeed=10;
scene.doRender=true;
if(viewButtonEnabled){
if(firstStrike){
switch(mode){
case MODE_VIEW:
setViewButton(MODE_PLACE,true);
break;
case MODE_PLACE:
setViewButton(MODE_AIM,true);
break;
case MODE_AIM:
setViewButton(MODE_VIEW,true);
break;
}
}else{
switch(mode){
case MODE_VIEW:
setViewButton(MODE_AIM,true);
break;
case MODE_AIM:
setViewButton(MODE_VIEW,true);
break;
}
}
}
};
var lineupshot=function(){
var shot=ai.getShot();
console.log(shot);
cueRotation[0]=shot[0];
cueRotation[1]=0.1;
updateCamera();
updateCue();
if(!canshoot){
cueRotation[1]=0.6;
updateCamera();
updateCue();
}
scene.doRender=true;
setTimeout(function(){
power=shot[1];
shoot();
},100);
};
var ai=new BallAI();
ai.setBalls(balls3d);
ai.setCueBall(cueball);
ai.setPhysicsBalls(world.playBalls);
// Start the simulation loop
var lastTime;
var firstFrame=true;
var physicsActive=false;
var start=function(){
(function simloop(time){
requestAnimationFrame(simloop);
if(!scene.loaded || !world.loaded) return;
if(lastTime !== undefined){
var dt = (time - lastTime) / 1000;
if(!scene.cue.visible) world.step(fixedTimeStep, dt, maxSubSteps);
}
lastTime = time;
updateTable();
//cannonDebugRenderer.update();
//hide cue
if(world.doFreeze()){
if(mode==MODE_SHOOT){
if(firstStrike){
setViewButton(MODE_PLACE,true);
world.resetCueBall();
setTimeout(function(){
scene.doRender=true;
},10);
}else{
setViewButton(MODE_AIM,true);
}
var color,balls=tableDef.balls;
while(color=ballsPotted.pop()){
for(var i=0;i