By the way, this is just a simple DEMO. I haven’t given much thought to gameplay, game rules, etc. If you are interested in refining it, you can refine it, such as refining the rules, game switches, adding a sound, refining the goal detection, and even more rigorous. Check the strength of the shot, the real friction of the table, etc. to make the game more like a game. I'm just giving you some programming ideas, just take a demo and it won't be very enjoyable to play~~
Snooker Game
There are two categories in the entire snooker game, one is the ball and the other is the auxiliary aiming line. If you want to make the game more complex, you can also abstract a shape class to detect collisions between the ball and corners and goals. The game I made uses the simplest wall collision detection, so there is no collision detection between balls and irregular shapes. If you want to play more complex collisions, you can poke about simple collision detection Cen An The speech was still very good. Okay, let’s do it step by step:
【Ball】
Post the code first:
[/code]var Ball = function(x, y, ismine){
this.x = x;
this.y = y;
this.ismine = ismine;
this.oldx = x;
this.oldy = y;
this.vx = 0;
this.vy = 0;
this.radius = ballRadius;
this.inhole = false;this.moving = true;
}
Ball.prototype = {
constructor:Ball,
_paint:function(){
var b = this.ismine ?document.getElementById("wb") : document.getElementById("yb")
if(b.complete) {
ctx.drawImage(b , this.x-this.radius , this.y-this .radius , 2*this.radius , 2*this.radius);
ctx.drawImage(b, this.x-this .radius , this.y-this.radius , 2*this.radius , 2*this.radius);
run:function(t){
this.oldx = this.x;
this.oldy = this.y;
this.vx = Math.abs(this.vx)<0.1? 0 : (this.vx>0? this.vx-mcl*t : this.vx mcl*t);
this.vy = Math.abs(this.vy)<0.1? 0 : (this.vy>0? this.vy-mcl*t : this.vy mcl*t);
// this.vx = this.vx> ;0? -mcl*t : mcl*t;
this.x = t * this.vx * pxpm;
this.y = t * this.vy * pxpm;
if((this.x<50 && this.y<50) || (this.x>370 && this.x<430 && this.y<50) || (this.x > 758 && this.y<50) || (this.x<46 && this.y>490) || (this.x>377 && this.x<420 && this.y>490) || (this.x > 758 && this.y>490)){
this.inhole = true;
if(this.ismine){
var that = this;
setTimeout(function(){
that.x = 202;
that.y = canvas.height/2;
that.vx = 0;
that.vy = 0;
that.inhole = false;
} , 500)
}
else {
document.getElementById("shotNum").innerHTML = parseInt(document.getElementById("shotNum").innerHTML) 1
}
}
else {
if(this.y > canvas.height - (ballRadius tbw) || this.y < (ballRadius tbw)){
this.y = this.y < (ballRadius tbw) ? (ballRadius tbw) : (canvas.height - (ballRadius tbw));
this.derectionY = !this.derectionY;
this.vy = -this.vy*0.6;
}
if(this.x > canvas.width - (ballRadius tbw) || this.x < (ballRadius tbw)){
this.x = this.x < (ballRadius tbw) ? (ballRadius tbw) : (canvas.width - (ballRadius tbw));
this.derectionX = !this.derectionX;
this.vx = -this.vx*0.6;
this.moving = false;
else {
}
}
}[/code]
Ball attributes: x, y ball position, vx, vy ball horizontal speed and vertical speed. , ismine represents whether it is a white ball or another ball (different balls draw different pictures in the _paint method), oldx, oldy are used to save the position of the ball in the previous frame, but they have not been used yet, it should be useful. There is nothing much to say about the _paint method. The _run method is to track the position of the ball and calculate the displacement increment and speed increment of the ball based on the time of each frame of the ball. mcl and pxpm are both constants, mcl is the friction force, and pxpm is approximately Calculate the pixel and reality conversion ratio. . . . Then there is collision detection. This is easy to understand. It calculates whether the position of the ball exceeds the boundary. If it exceeds, it will rebound. However, this kind of collision detection is very loose. If you really want to make a game, it is recommended to use something more complicated. There is also the method of stopping the ball according to its speed.
Copy code
Copy code
Assign the speed increment to the collision ball. Because in the frame when the two balls collide, the two balls partially overlap, so the position correction must be performed. Otherwise, the small balls will always be in collision and then stick together. The principle of position correction is also simple. Calculate the distance between the two balls. Center distance, calculate the width of the overlapping area of the two balls through the Pythagorean theorem, and then divide the width by 2 and assign the new position to the ball. The new position is that the radius of the two balls is exactly equal to the distance between the centers of the balls.
【Mouse action】
document.querySelector(".shotPower").style.display = "block";
document.querySelector(".shotPower").style.top = balls[0].y-60 "px";
document.querySelector(".shotPower").style.left = balls[0].x-40 "px";
document.getElementById("pow").className = "animate";
var x = event.clientX document.body.scrollLeft document.documentElement.scrollLeft - document.querySelector(".view").offsetLeft;
var y = event.clientY document.body.scrollTop document.documentElement.scrollTop - document.querySelector(".view").offsetTop;
dotline.display = true;
dotline.x0 = balls[0].x;
dotline.y0 = balls[0].y;
dotline.x1 = x;
dotline.y1 = y;
window.addEventListener("mouseup" , muHandle , false);
window.addEventListener("mousemove" , mmHandle , false);
function mmHandle(){
var x = event.clientX document.body.scrollLeft document.documentElement.scrollLeft - document.querySelector(".view").offsetLeft;
var y = event.clientY document.body.scrollTop document.documentElement.scrollTop - document.querySelector(".view").offsetTop;
dotline.x1 = x;
dotline.y1 = y;
}
function muHandle(){
var x = event.clientX document.body.scrollLeft document.documentElement.scrollLeft - document.querySelector(".view").offsetLeft;
var y = event.clientY document.body.scrollTop document.documentElement.scrollTop - document.querySelector(".view").offsetTop;
var angle = Math.atan((y - balls[0].y)/(x - balls[0].x));
var h = document.getElementById("pow").offsetHeight/document.getElementById("powbar").offsetHeight;
var v = 60*h;
document.getElementById("pow").style.height = h*100 "%"
balls[0].vx = x - balls[0].x>0 ? v*Math.abs(Math.cos(angle)) : -v*Math.abs(Math.cos(angle));
balls[0].vy = y - balls[0].y>0 ? v*Math.abs(Math.sin(angle)) : -v*Math.abs(Math.sin(angle));
document.getElementById("pow").className = "";
window.removeEventListener("mouseup" , muHandle , false);
window.removeEventListener("mousemove" , muHandle , false);
dotline.display = false;
document.querySelector(".shotPower").style.display = "none";
}
},false);
鼠标动作也比较简单,有js基础的基本上都没问题,就是鼠标按下后计算鼠标位置,然后产生辅助虚线,鼠标移动后修改辅助虚线的终点位置。鼠标按下的时候旁边产生一个力量计,我就只用用animation做动画了,然后鼠标按键抬起时通过计算力量计的大小来确定白球的速度,然后再分解成水平速度以及垂直速度赋给白球。同时取消鼠标移动以及鼠标抬起的事件绑定,把辅助虚线以及力量计隐藏。
【动画舞台】
collision();
balls.foreach(function(){
if(!this.inhole) this._run(t);
});
if(dotline.display){
dotline.x0 = balls[0].x;
dotline.y0 = balls[0].y;
dotline._paint();
}
t0 = t1;
if(!animateStop){
if("requestAnimationFrame" in window){
requestAnimationFrame(animate);
}
else if("webkitRequestAnimationFrame" in window){
webkitRequestAnimationFrame(animate);
}
else if("msRequestAnimationFrame" in window){
msRequestAnimationFrame(animate);
}
else if("mozRequestAnimationFrame" in window){
mozRequestAnimationFrame(animate);
}
else {
setTimeout(animate , 16);
}
}
}
window.onload = function(){
var myball = new Ball(202 , canvas.height/2 , true);
balls.push(myball);
for(var i=0;i<6;i ){
for(var j=0;j var other = new Ball(520 i*(ballRadius-2)*2 , (canvas.height-i*2*ballRadius)/2 ballRadius 2*ballRadius*j , false);
balls.push(other);
}
}
t0 = new Date();
dotline = new dotLine(0,0,0,0);
animateStop = false;
animate();
}
源码地址:https://github.com/whxaxes/canvas-test/tree/gh-pages/src/Game-demo/snooker