Player
0
00:00
0
Computer

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