- 浏览: 21849 次
- 来自: ...
最新评论
2D TaiQu
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
<!-- saved from url=(0035)http://cnwander.com/demo/billiards/ -->
<HTML xmlns="http://www.w3.org/1999/xhtml"><HEAD><TITLE>台球 by CNwander</TITLE>
<META http-equiv=Content-Type content="text/html; charset=utf-8">
<STYLE type=text/css>* {
PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px
}
BODY {
BACKGROUND: black; TEXT-ALIGN: center
}
H1 {
FONT-WEIGHT: normal; FONT-SIZE: 12px; COLOR: gray; LINE-HEIGHT: 200%
}
H1 .sub {
FONT-SIZE: 9px; VERTICAL-ALIGN: super; COLOR: red
}
.info {
RIGHT: 0px; POSITION: absolute
}
#table {
BACKGROUND: url(./img//table.jpg) no-repeat; MARGIN: 20px auto 10px; WIDTH: 800px; POSITION: relative; HEIGHT: 544px
}
.ball {
WIDTH: 30px; POSITION: absolute; HEIGHT: 30px
}
#dotWrap {
Z-INDEX: 2; LEFT: 32px; WIDTH: 736px; POSITION: absolute; TOP: 32px; HEIGHT: 480px
}
.guide {
Z-INDEX: 3; BACKGROUND-IMAGE: url(./img//dashed_ball.png); BACKGROUND-REPEAT: no-repeat; _background: none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src="./img//dashed_ball.png")
}
.target {
LEFT: 500px; BACKGROUND-IMAGE: url(./img//yellow_ball.png); BACKGROUND-REPEAT: no-repeat; TOP: 250px; _background: none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src="./img//yellow_ball.png")
}
.cue {
BACKGROUND-IMAGE: url(./img//white_ball.png); BACKGROUND-REPEAT: no-repeat; _background: none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src="./img//white_ball.png")
}
.bot {
MARGIN: 10px auto; WIDTH: 800px; POSITION: relative; HEIGHT: 70px
}
.ctrl {
RIGHT: 0px; BACKGROUND: url(./img//bg_controler.png) no-repeat; WIDTH: 200px; POSITION: absolute; TOP: 0px; HEIGHT: 80px
}
#force {
BACKGROUND: url(./img//force_conver.png) no-repeat; LEFT: 0px; WIDTH: 75px; POSITION: absolute; TOP: 18px; HEIGHT: 20px
}
#shootPos {
RIGHT: 14px; WIDTH: 52px; POSITION: absolute; TOP: 0px; HEIGHT: 52px
}
#dot {
FONT-SIZE: 1px; BACKGROUND: url(./img//bule_dot.png) no-repeat; LEFT: 22px; WIDTH: 8px; POSITION: absolute; TOP: 22px; HEIGHT: 8px
}
#scoreBoard {
FONT-SIZE: 50px; Z-INDEX: 3; FILTER: alpha(opacity=0); LEFT: 346px; COLOR: white; POSITION: absolute; TOP: 230px; -moz-opacity: 0; opacity: 0
}
#tips {
PADDING-RIGHT: 0px; PADDING-LEFT: 20px; FONT-SIZE: 12px; PADDING-BOTTOM: 0px; COLOR: red; PADDING-TOP: 15px; TEXT-ALIGN: left
}
</STYLE>
<SCRIPT type=text/javascript>
// common
function $(str) {
return document.getElementById(str);
}
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
}
//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();
}
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);
}
}
}
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);
}
}
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>
<META content="MSHTML 6.00.6000.16414" name=GENERATOR></HEAD>
<BODY>
<DIV class=info><A href="http://cnwander.com/blog/?p=11">Wander's
space</A></DIV>
<H1>中国人民烎起来!<SPAN class=sub>60周年</SPAN></H1>
<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>
<!-- saved from url=(0035)http://cnwander.com/demo/billiards/ -->
<HTML xmlns="http://www.w3.org/1999/xhtml"><HEAD><TITLE>台球 by CNwander</TITLE>
<META http-equiv=Content-Type content="text/html; charset=utf-8">
<STYLE type=text/css>* {
PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px
}
BODY {
BACKGROUND: black; TEXT-ALIGN: center
}
H1 {
FONT-WEIGHT: normal; FONT-SIZE: 12px; COLOR: gray; LINE-HEIGHT: 200%
}
H1 .sub {
FONT-SIZE: 9px; VERTICAL-ALIGN: super; COLOR: red
}
.info {
RIGHT: 0px; POSITION: absolute
}
#table {
BACKGROUND: url(./img//table.jpg) no-repeat; MARGIN: 20px auto 10px; WIDTH: 800px; POSITION: relative; HEIGHT: 544px
}
.ball {
WIDTH: 30px; POSITION: absolute; HEIGHT: 30px
}
#dotWrap {
Z-INDEX: 2; LEFT: 32px; WIDTH: 736px; POSITION: absolute; TOP: 32px; HEIGHT: 480px
}
.guide {
Z-INDEX: 3; BACKGROUND-IMAGE: url(./img//dashed_ball.png); BACKGROUND-REPEAT: no-repeat; _background: none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src="./img//dashed_ball.png")
}
.target {
LEFT: 500px; BACKGROUND-IMAGE: url(./img//yellow_ball.png); BACKGROUND-REPEAT: no-repeat; TOP: 250px; _background: none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src="./img//yellow_ball.png")
}
.cue {
BACKGROUND-IMAGE: url(./img//white_ball.png); BACKGROUND-REPEAT: no-repeat; _background: none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src="./img//white_ball.png")
}
.bot {
MARGIN: 10px auto; WIDTH: 800px; POSITION: relative; HEIGHT: 70px
}
.ctrl {
RIGHT: 0px; BACKGROUND: url(./img//bg_controler.png) no-repeat; WIDTH: 200px; POSITION: absolute; TOP: 0px; HEIGHT: 80px
}
#force {
BACKGROUND: url(./img//force_conver.png) no-repeat; LEFT: 0px; WIDTH: 75px; POSITION: absolute; TOP: 18px; HEIGHT: 20px
}
#shootPos {
RIGHT: 14px; WIDTH: 52px; POSITION: absolute; TOP: 0px; HEIGHT: 52px
}
#dot {
FONT-SIZE: 1px; BACKGROUND: url(./img//bule_dot.png) no-repeat; LEFT: 22px; WIDTH: 8px; POSITION: absolute; TOP: 22px; HEIGHT: 8px
}
#scoreBoard {
FONT-SIZE: 50px; Z-INDEX: 3; FILTER: alpha(opacity=0); LEFT: 346px; COLOR: white; POSITION: absolute; TOP: 230px; -moz-opacity: 0; opacity: 0
}
#tips {
PADDING-RIGHT: 0px; PADDING-LEFT: 20px; FONT-SIZE: 12px; PADDING-BOTTOM: 0px; COLOR: red; PADDING-TOP: 15px; TEXT-ALIGN: left
}
</STYLE>
<SCRIPT type=text/javascript>
// common
function $(str) {
return document.getElementById(str);
}
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
}
//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();
}
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);
}
}
}
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);
}
}
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>
<META content="MSHTML 6.00.6000.16414" name=GENERATOR></HEAD>
<BODY>
<DIV class=info><A href="http://cnwander.com/blog/?p=11">Wander's
space</A></DIV>
<H1>中国人民烎起来!<SPAN class=sub>60周年</SPAN></H1>
<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>
相关推荐
《Unity 2D切割插件Smart Slicer 2D Pro v2020.3.0详解》 Unity 作为一款强大的游戏开发引擎,广泛应用于2D和3D游戏制作。在2D游戏开发中,有时我们需要对游戏对象进行切割操作,以实现动态交互、碰撞检测或视觉...
Box2D是一个强大的开源2D物理引擎,专为游戏开发者设计,使得在游戏场景中创建真实的物理效果变得简单易行。这个中文手册是为那些希望深入理解和应用Box2D的程序员准备的,提供了详尽的指导和实例,帮助开发者更好地...
unity2D寻路Navigation2D (Pathfinding for 2D Games) V1.27 要求Unity 2017.4.1 或更高版本。 Navigation2D uses Unity's built-in Navigation system to make 2D pathfinding possible without any axis ...
《Live2D模型资源探索与应用》 在数字艺术领域,Live2D技术因其独特的表现力和互动性,被广泛应用于游戏、动画、社交媒体等众多场景。本资源包"live2d模型x9.zip"提供了九个不同角色的Live2D模型,包括hiyori_movie...
Unity2D寻路插件PolyNav2D是游戏开发中常用的一种工具,它专为2D环境中的游戏角色或物体提供智能导航和路径规划功能。在Unity3D引擎中,2D游戏开发同样需要解决角色如何从一点移动到另一点的问题,而避免碰撞和其他...
在处理这些图像时,我们有时需要将来自不同来源的图片数据转换成Unity可识别的格式,例如从Bitmap格式转换为Texture2D。Bitmap是一种常见的图像格式,广泛应用于Windows操作系统和许多图像处理软件中。然而,Unity3D...
Unity2D水效果是2D游戏开发中一个重要的视觉元素,它可以增强游戏的真实感和玩家的沉浸体验。在Unity引擎中,2D水效果通常通过各种技术和组件来实现,如"Unity2dWater_2dwater_Unity2d水_"这个资源包就专门针对这一...
Box2D是一款强大的开源物理引擎,专为2D游戏和模拟设计。在“Box2D_02_碰撞”这个主题中,我们将深入探讨Box2D如何处理2D空间中的物体碰撞,以及如何在Android平台上编写C++代码来实现这些功能。 首先,Box2D的核心...
Box2D是一个流行的开源物理引擎,用于在2D空间中模拟真实世界物理行为。它广泛应用于游戏开发,让开发者能够创建具有逼真物理效果的游戏场景。在这个“box2d_2.添加鼠标关节MouseJoint和box2d基础概念”的主题中,...
unity开发的2D图片资源 包括npc,player的各种人物动作图,游戏画面素材,场景图标,天空,声音图标,飞鸟,怪物等各种2D游戏图标。 unity开发的2D图片资源 包括npc,player的各种人物动作图,游戏画面素材,场景图标...
Live2D是一种基于日本Cubism框架的实时三维渲染技术,它通过数学算法将2D图像转化为可动态操控的3D模型,为用户提供更为真实的视觉体验。在网页中集成Live2D,可以极大地提升用户体验,尤其是对于游戏、教育、娱乐类...
在Vue.js框架中引入Live2D是一项有趣且增强用户体验的技术应用。Live2D是一种二维实时渲染技术,可以创建逼真的动态角色模型,广泛应用于游戏、社交媒体应用和网站中。Vue.js是一个轻量级且功能强大的渐进式...
标题中的“fwt2d.v4.7.gz_FWT2D_FWT2D.V4.7.tar_fwt2d.v4.7_反演_波场”提到了一个名为"FWT2D"的软件或算法的版本4.7,它与地震波场的正反演相关。描述进一步揭示了这个软件包含频率域有限差分(Frequency-Wavelet ...
live2d.js live2d.js
Cocos Creator 3.8.0 是一个强大的跨平台游戏开发框架,它的最新版本引入了对Live2D动画的支持,让开发者能够轻松地在游戏或应用程序中集成生动、逼真的2D角色动画。Live2D是一种实时二维动画技术,通过使用物理计算...
Box2D是一个开源的2D物理引擎,广泛用于游戏开发,尤其在Cocos2d这样的2D游戏引擎中。Cocos2d是一个流行的跨平台的游戏开发框架,它提供了丰富的功能和工具,使得开发者能够轻松创建各种2D游戏。在本案例中,我们...
GprMax2D3D是基于GPU的二维和三维地面穿透雷达(Ground Penetrating Radar, GPR)仿真软件,其主要目标是帮助用户理解GPR信号的传播、反射和散射特性,以及如何通过模拟数据来分析地下结构。GprMax2D3D在地质勘探、...
《cocos2d-x与Box2D:构建基础物理引擎》 在游戏开发领域,物理引擎扮演着至关重要的角色,它赋予游戏中的对象以真实世界中的运动规律,从而增加游戏的真实感和趣味性。cocos2d-x是一个流行的开源2D游戏开发框架,...
尤其是在处理大量图像资源时,如Texture2D,动态加载可以避免在游戏启动时一次性加载所有资源导致的加载时间过长。本文将深入讲解如何在Unity3D中实现Texture2D图片的动态加载,以及解决可能遇到的纹理失真问题。 ...