用js脚本制作的2D桌球小游戏效果,非常的逼真,玩转js特效就能用它来做很多有用的程序功能。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html;charset=gb2312"> <meta name="keywords" content="武鸣人网站,武鸣信息网,武鸣本地网,武鸣信息资源平台,减肥,健身,励志,励志语录,js特效,网页特效,www.wuming.ren"> <meta name="description" content="欢迎来到武鸣人信息资源平台,各种信息免费发布,资源共享合作共赢,分享互联网流行的励志语录经典短句,减肥健身健康小常识及打卡记录,收集各种js特效代码。"> <title>js制作2D桌球游戏特效_武鸣人</title> <style type="text/css"> * {margin:0; padding:0} body {background:black; text-align:center; font-size:12px} h1 {font-size:12px; color:gray; font-weight:normal; line-height:200%} h1 .sub {vertical-align:super; color:red; font-size:9px} .info {position:absolute; right:0; color:gray} #table {position:relative; width:800px; margin:20px 50px 50px 10px; height:544px; background:url(/img/20240318_www_wuming_ren_9.gif) no-repeat} .ball {position:absolute; width:30px; height:30px} #dotWrap {position:absolute; z-index:2; left:32px; top:32px; width:736px; height:480px} .guide {z-index:3; background-image:url(/img/20240318_www_wuming_ren_10.png); _background:none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src="/img/20240318_www_wuming_ren_10.png"); background-repeat:no-repeat} .target {left:500px; top:250px; background-image:url(/img/20240318_www_wuming_ren_11.png); _background:none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src="/img/20240318_www_wuming_ren_11.png"); background-repeat:no-repeat} .cue {background-image:url(/img/20240318_www_wuming_ren_12.png); _background:none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src="/img/20240318_www_wuming_ren_12.png"); background-repeat:no-repeat} .bot {position:relative; width:800px; margin:10px auto 10px; height:70px} .ctrl {position:absolute; top:0; right:0; width:200px; height:80px; background:url(/img/20240318_www_wuming_ren_13.png) no-repeat} #force {position:absolute; left:0; top:18px; width:75px; height:20px; background:url(/img/20240318_www_wuming_ren_14.png) no-repeat} #shootPos {position:absolute; top:0; right:14px; width:52px; height:52px} #dot {position:absolute; top:22px; left:22px; width:8px; height:8px; background:url(/img/20240318_www_wuming_ren_15.png) no-repeat; font-size:1px} #scoreBoard {position:absolute; z-index:3; top:230px; left:346px; font-size:50px; color:white; filter:alpha(opacity=0); -moz-opacity:0; opacity:0} #tips {padding:15px 0 0 20px; text-align:left; color:red; font-size:12px} </style> <script type="text/javascript"> // common function $(str) { return document.getElementById(str); }//武鸣人网站https://www.wuming.ren 网站很好记住,wuming.ren(武鸣拼音.ren域名后缀) function $tag(str,target) { target = target || document; return target.getElementsByTagName(str); } function addEventHandler(obj,eType,fuc){ if(obj.addEventListener){ obj.addEventListener(eType,fuc,false); }else if(obj.attachEvent){ obj.attachEvent("on" + eType,fuc); }else{ obj["on" + eType] = fuc; } } function removeEventHandler(obj,eType,fuc){ if(obj.removeEventListener){ obj.removeEventListener(eType,fuc,false); }else if(obj.attachEvent){ obj.detachEvent("on" + eType,fuc); } } function randowNum(start,end) { return Math.floor(Math.random()*(end - start)) + start; } Array.prototype.remove=function(dx) { if(isNaN(dx)||dx>this.length){return false} for(var i=0,n=0;i<this.length;i++) { if(this[i]!=this[dx]) { this[n++]=this[i] } } this.length-=1 }//武鸣人网站https://www.wuming.ren 网站很好记住,wuming.ren(武鸣拼音.ren域名后缀) //const var TOTALR = 15, //球的半径(包括阴影) R = 12, //球真实半径 POKER = 20, W = 736, //案宽 H = 480, //案高 THICKNESS = 32, //边缘厚度 RATE = 100, //刷新频率 F = 0.01, //摩擦力 LOSS = 0.2, // 碰撞速度损失 TIPS = ["Tip1: 参考球,目标球,目标袋,三点一线,这是最基本的进球方法","Tip2: 右下角蓝条代表击球力度,小的力度更便于控制母球位置","Tip3: 右下角白球上的蓝点控制击球点,高杆,低杆,加塞都由它控制,高手与菜鸟的区别往往在此","Tip4: 桌球,其实打的不是目标球,是母球"]; var table, //案子 cueBall, //母球 guideBall, //参考球 dotWrap, //参考线 speed = 12, rollUp = 0, rollRight = 0, timer, forceTimer, balls = [], movingBalls = [], pokes = [[0,0],[W/2,-5],[W,0],[0,H],[W/2,H+5],[W,H]], hasShot = false; shots = 0; //连击次数 window.onload = function() { initTable(); initShootPos(); showTips(); startGame(); } function startGame() { initBall(); addEventHandler(table,"mousemove",dragCueBall); addEventHandler(table,"mouseup",setCueBall); } function initTable() { table = $("table"); var dotWrapDiv = document.createElement("div"), guideBallDiv = document.createElement("div"); dotWrapDiv.id = "dotWrap"; guideBallDiv.className = "guide ball"; setStyle(guideBallDiv,"display","none"); dotWrap = table.appendChild(dotWrapDiv); guideBall = table.appendChild(guideBallDiv); } function initBall() { //添加母球 cueBall = new Ball("cue",170,H/2); balls.push(cueBall); //添加目标球 for(var i = 0; i < 5; i++) { for(var j = 0; j <= i; j++){ var ball = new Ball("target",520 + i*2*R, H/2 - R*i + j*2*R); balls.push(ball); } } } function initShootPos() { var wrap = $("shootPos"), handler = $("dot"), arrowR = 18; addEventHandler(wrap,"mousedown",selectDot); function selectDot(e) { e = e || event; var pos = getElemPos(wrap), x = e.clientX - pos[0] - handler.offsetWidth/2, y = e.clientY - pos[1] - handler.offsetHeight/2; if(Math.sqrt((x-22)*(x-22) + (y-22)*(y-22)) > arrowR) { var angle = Math.atan2(x-22,y-22); x = arrowR*Math.sin(angle) + 22; y = arrowR*Math.cos(angle) + 22; } setPos(handler,x,y); } } function getElemPos(target,reference) { reference = reference || document; var left = 0,top = 0; return getPos(target); function getPos(target) { if(target != reference) { left += target.offsetLeft; top += target.offsetTop; return getPos(target.parentNode); } else { return [left,top]; } } } // ball class function Ball(type,x,y) { var div = document.createElement("div"); div.className = type + " ball"; this.elem = table.appendChild(div); this.type = type; this.x = x; //位置 this.y = y; this.angle = 0; //角度 this.v = 0; //速度(不包含方向) setBallPos(this.elem,x,y); return this; } function setCueBall() { removeEventHandler(table,"mousemove",dragCueBall); removeEventHandler(table,"mouseup",setCueBall); startShot(); }//武鸣人网站https://www.wuming.ren 网站很好记住,wuming.ren(武鸣拼音.ren域名后缀) function startShot() { show(cueBall.elem); addEventHandler(table,"mousemove",showGuide); addEventHandler(table,"mousedown",updateForce); addEventHandler(table,"mouseup",shotCueBall); } function dragCueBall(e) { var toX,toY; e = e || event; toX = e.clientX - table.offsetLeft - THICKNESS, toY = e.clientY - table.offsetTop - THICKNESS; toX = toX >= R ? toX : R; toX = toX <= 170 ? toX : 170; toY = toY >= R ? toY : R; toY = toY <= H - R ? toY : H - R; setBallPos(cueBall,toX,toY); } function shotCueBall() { removeEventHandler(table,"mousemove",showGuide); removeEventHandler(table,"mousedown",updateForce); removeEventHandler(table,"mouseup",shotCueBall); window.clearInterval(forceTimer); speed = $("force").offsetWidth * 0.15; var dotDisX = $("dot").offsetLeft-22, dotDisY = $("dot").offsetTop-22, dotDis = Math.sqrt(dotDisX*dotDisX + dotDisY*dotDisY), dotAngle = Math.atan2(dotDisX,dotDisY); rollRight = Math.round(dotDis*Math.sin(dotAngle))/5; rollUp = -Math.round(dotDis*Math.cos(dotAngle))/5; var formPos = getBallPos(cueBall.elem), toPos = getBallPos(guideBall), angle = Math.atan2(toPos[0] - formPos[0],toPos[1] - formPos[1]); hide(dotWrap); hide(guideBall); cueBall.v = speed; cueBall.angle = angle; movingBalls.push(cueBall); timer = window.setInterval(roll,1000 / RATE); } function showGuide(e) { var fromX,fromY,toX,toY; e = e || event; toX = e.clientX - table.offsetLeft - THICKNESS, toY = e.clientY - table.offsetTop - THICKNESS; setBallPos(guideBall,toX,toY); show(dotWrap); show(guideBall); drawLine(); //参考线 function drawLine() { var dotNum = 16, pos = getBallPos(cueBall.elem); dotWrap.innerHTML = ""; fromX = pos[0]; fromY = pos[1]; var partX = (toX - fromX) / dotNum, partY = (toY - fromY) / dotNum; for(var i = 1; i < dotNum; i++) { var x = fromX + partX * i, y = fromY + partY * i; drawDot(dotWrap, x, y); } } }//武鸣人网站https://www.wuming.ren 网站很好记住,wuming.ren(武鸣拼音.ren域名后缀) function roll() { if(movingBalls.length <= 0) { if(!hasShot) shots = 0; else shots ++; //累计连击 hasShot = false; setStyle($("force"),"width",80+"px"); setPos($("dot"),22,22); window.clearInterval(timer); if(shots > 1) showScore(shots); //显示连击数 startShot(); } for(var i = 0; i < movingBalls.length; i++) { var ball = movingBalls[i], sin = Math.sin(ball.angle), cos = Math.cos(ball.angle); ball.v -= F; //移除静止的小球 if(Math.round(ball.v) == 0) { ball.v = 0; movingBalls.remove(i); continue; } var vx = ball.v * sin, vy = ball.v * cos; ball.x += vx; ball.y += vy; //入袋 if(isPocket(ball.x,ball.y)) { hide(ball.elem); if(ball.type == "cue") { if(!hasShot) shots = 0; hasShot = false; window.setTimeout(function(){ ball.v = 0; setBallPos(ball,170,250); },500); }else { //移除入袋小球 hasShot = true; ball.v = 0; for(var k = 0, l =0; k < balls.length; k++) { if(balls[k] != ball) { balls[l++] = balls[k]; } } balls.length -= 1; } return; } //边缘碰撞 if(ball.x < R || ball.x > W - R) { ball.angle *= -1; ball.angle %= Math.PI; ball.v = ball.v * (1 - LOSS); vx = ball.v*Math.sin(ball.angle); vy = ball.v*Math.cos(ball.angle); if(ball.x < R) ball.x = R; if(ball.x > W - R) ball.x = W - R; //母球加塞 if(ball.type == "cue"){ if(ball.angle > 0) vy -= rollRight; else vy += rollRight; vx += rollUp; rollUp *= 0.2; rollRight *= 0.2; ball.v = Math.sqrt(vx*vx + vy*vy); ball.angle = Math.atan2(vx,vy); } } if(ball.y < R || ball.y > H - R) { ball.angle = ball.angle > 0 ? Math.PI - ball.angle : - Math.PI - ball.angle ; ball.angle %= Math.PI; ball.v = ball.v * (1 - LOSS); vx = ball.v*Math.sin(ball.angle); vy = ball.v*Math.cos(ball.angle); if(ball.y < R) ball.y = R; if(ball.y > H - R) ball.y = H - R; //母球加塞 if(ball.type == "cue"){ if(Math.abs(ball.angle) < Math.PI/2) vx += rollRight; else vx -= rollRight; vy += rollUp; rollUp *= 0.2; rollRight *= 0.2; ball.v = Math.sqrt(vx*vx + vy*vy); ball.angle = Math.atan2(vx,vy); } } //小球碰撞 for(var j = 0; j < balls.length; j++) { var obj = balls[j]; if(obj == ball) continue; var disX = obj.x - ball.x, disY = obj.y - ball.y, gap = 2 * R; if(disX <= gap && disY <= gap) { var dis = Math.sqrt(Math.pow(disX,2)+Math.pow(disY,2)); if(dis <= gap) { //如果是静止的,则添加到数组movingBalls if(Math.round(obj.v) == 0) movingBalls.push(obj); //将坐标旋转到x轴进行碰撞计算 // 计算角度和正余弦值 - 精确值 //var c = (obj.x*ball.y - obj.y*ball.x)/(2*R), //d = Math.sqrt(ball.x*ball.x + ball.y*ball.y), //angle = Math.asin(ball.y/d) - Math.asin(c/d) - ball.angle%(Math.PI/2), //angle = Math.asin(oy / (2 * R)), //还原两球相切状态 - 近似值 ball.x -= (gap - dis)*sin; ball.y -= (gap - dis)*cos; disX = obj.x - ball.x; disY = obj.y - ball.y; // 计算角度和正余弦值 var angle = Math.atan2(disY, disX), hitsin = Math.sin(angle), hitcos = Math.cos(angle), objVx = obj.v * Math.sin(obj.angle), objVy = obj.v * Math.cos(obj.angle); //trace(angle*180/Math.PI); // 旋转坐标 var x1 = 0, y1 = 0, x2 = disX * hitcos + disY * hitsin, y2 = disY * hitcos - disX * hitsin, vx1 = vx * hitcos + vy * hitsin, vy1 = vy * hitcos - vx * hitsin, vx2 = objVx * hitcos + objVy * hitsin, vy2 = objVy * hitcos - objVx * hitsin; // 碰撞后的速度和位置 var plusVx = vx1 - vx2; vx1 = vx2; vx2 = plusVx + vx1; //母球加塞 if(ball.type == "cue"){ vx1 += rollUp; rollUp *= 0.2; } x1 += vx1; x2 += vx2; // 将位置旋转回来 var x1Final = x1 * hitcos - y1 * hitsin, y1Final = y1 * hitcos + x1 * hitsin, x2Final = x2 * hitcos - y2 * hitsin, y2Final = y2 * hitcos + x2 * hitsin; obj.x = ball.x + x2Final; obj.y = ball.y + y2Final; ball.x = ball.x + x1Final; ball.y = ball.y + y1Final; // 将速度旋转回来 vx = vx1 * hitcos - vy1 * hitsin; vy = vy1 * hitcos + vx1 * hitsin; objVx = vx2 * hitcos - vy2 * hitsin; objVy = vy2 * hitcos + vx2 * hitsin; //最终速度 ball.v = Math.sqrt(vx*vx + vy*vy) * (1 - 0); obj.v = Math.sqrt(objVx*objVx + objVy*objVy) * (1 - 0); // 计算角度 ball.angle = Math.atan2(vx , vy); obj.angle = Math.atan2(objVx , objVy); //break; } } } setBallPos(ball,ball.x,ball.y); } }//武鸣人网站https://www.wuming.ren 网站很好记住,wuming.ren(武鸣拼音.ren域名后缀) function isPocket(x,y) { if(y < POKER) return check(0,2); else if (y > H - POKER) return check(3,5); else return false; function check(m,n) { for(var i=m; i<=n; i++) { if(x >= pokes[i][0] - POKER && x <= pokes[i][0] + POKER) { var dis = Math.sqrt(Math.pow(x - pokes[i][0],2) + Math.pow(y - pokes[i][1],2)); if(dis <= POKER) return true; else return false; } } } } function getBallPos(obj) { var pos = []; pos.push(obj.offsetLeft - THICKNESS + TOTALR); pos.push(obj.offsetTop - THICKNESS + TOTALR); return pos; } function setPos(obj,x,y) { obj.style.left = x + "px"; obj.style.top = y + "px"; } function setBallPos(ball,x,y) { if(ball.constructor == Ball) { ball.x = x; ball.y = y; ball = ball.elem; } setPos(ball,x + THICKNESS - TOTALR,y + THICKNESS - TOTALR); } function drawDot(wrap,x,y) { var elem = document.createElement("div"); setStyle(elem,{ position: "absolute", width: "1px", height: "1px", fontSize: "1px", background: "white" }); setPos(elem,x,y); wrap.appendChild(elem); } function updateForce() { var obj = $("force"), len = 80, up = true; forceTimer = window.setInterval(update,10); function update() { if(up) setStyle(obj,"width",len+++"px"); else setStyle(obj,"width",len--+"px"); if(len > 136) up = false; if(len <= 0) up = true; } } function setStyle() { if(arguments.length == 2 && typeof arguments[1] == "object") { for(var key in arguments[1]) { arguments[0].style[key] = arguments[1][key]; } } else if (arguments.length > 2) { arguments[0].style[arguments[1]] = arguments[2]; } } function hide(obj) { setStyle(obj,"display","none"); } function show(obj) { setStyle(obj,"display","block"); } //输出信息 function trace(sth,who) { who = who || $("tips"); if(document.all) who.innerText = sth; else who.textContent = sth; return who; } function showScore(n) { var wrap = $("scoreBoard"); trace(n+"连杆",wrap); fadeIn(wrap); } function fadeIn(obj){ var fromY = 230, posStep = [8,14,19,23,26,28,29,29,30,30,30], opaStep = [0,0.05,0.1,0.15,0.2,0.25,0.3,0.4,0.5,0.6,0.8], fromOpa = 0, t = 0, step = posStep.length, inTimer = window.setInterval(showIn,20), outTimer; function showIn() { setOpacity(obj,opaStep[t]); obj.style.top = fromY + posStep[t] + "px"; t++; if(t>=step) { window.clearInterval(inTimer); outTimer = window.setInterval(fadeOut,50); } } function fadeOut() { t--; setOpacity(obj,opaStep[t]); obj.style.top = fromY + posStep[t] + "px"; if(t <= 0) { window.clearInterval(outTimer); hide(obj); } } } function setOpacity(obj,n) { obj.style.cssText = "filter:alpha(opacity="+ n*100 +"); -moz-opacity:"+ n +"; opacity:"+ n; } function showTips() { var i = 0; tip(); window.setInterval(tip,3000); function tip() { trace(TIPS[i++]); if(i >= TIPS.length) i = 0; } } </script> </head> <body> <a href="https://www.wuming.ren">武鸣人</a>,各种信息资源免费发布,分享励志语录经典短句,减肥健身常识,各种js特效代码。网站很好记住,wuming.ren(武鸣拼音.ren域名后缀)<hr> <!--欢迎来到武鸣人信息资源平台,各种信息免费发布,资源共享合作共赢,分享互联网流行的励志语录经典短句,减肥健身健康小常识及打卡记录,收集各种js特效代码。--> <script type="text/javascript" src="https://www.wuming.ren/ad/tc.js"></script> <script type="text/javascript" src="https://www.wuming.ren/ad/a.js"></script> <div id="table"> <div id="scoreBoard"></div> </div> <div class="bot"> <div id="tips"></div> <div class = "ctrl"> <div id="force"></div> <div id="shootPos"> <div id="dot"></div> </div> </div> </div> </body> </html>
本文来自武鸣人网站,转载请注明出处