| 
                         今天在cnwander的博客看到一款非常棒的桌球小游戏,与众不同的是它并非是flash制作的,而是用JavaScript实现的,并且可以实现台球的力度、撞击点等,当鼠标按住时还可以看到右下角的力量进度条实时滑动,非常不错,先看一下演示: 
 提示:可修改后代码再运行! 
贴出一些关键代码稍作解释,有兴趣的同学看看。
  // ball class  function Ball(type,x,y) {  ...  this.type = type;  this.x = x; //位置  this.y = y;  this.angle = 0; //角度  this.v = 0; //速度(不包含方向)  ...  return this;  }  描述小球的四个信息,小球的类型(母球,目标球),坐标,角度,速度  在更新坐标时,读取小球的v,刷新小球的位置  在与边沿碰撞时,更改小球angle 
  var formPos = getBallPos(cueBall.elem),  toPos = getBallPos(guideBall),  angle = Math.atan2(toPos[0] - formPos[0],toPos[1] - formPos[1]);  计算母球,与参考球之间的角度,其它任意小球之间也是如此  值得注意的是我采用的是Math.atan2,而非Math.atan,这是因为Math.atan2返回的是(0 - Math.PI)和(-Math.PI - 0),可以确定唯一的角度,而Math.atan不唯一。
  //边缘碰撞  if(ball.x < R || ball.x > W - R) {  ball.angle *= -1;  ball.v = ball.v * (1 - LOSS);  ...  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 ;  ...  不考虑小球旋转时,边缘碰撞很简单,更改小球angle即可  当小球旋转时,如果碰到固定不动的物体时,那将会把速度作用给自身  并且自身旋转速度减小  我这里计算球与球之间碰撞,并没有将旋转传递,这是不准确的,有待改善 
  这一段是核心,即小球与小球碰撞后各自的速度,其实并不难  先判断两球距离  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);  //还原两球相切状态,用其它方式做我不知道,但用js来做,这一步相当关键,否则误差将相当大  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);  } 
  坐标旋转的公式:  x1 = Math.cos(angle) * x - Math.sin(angle) * y;  y1 = Math.cos(angle) * y + Math.sin(angle) * x; 
  反坐标旋转:  x1 = Math.cos(angle) * x + Math.sin(angle) * y;  y1 = Math.cos(angle) * y - Math.sin(angle) * x; 
  稍作注意就会发现还存在很多问题,与真实桌球还有相当差距,慢慢改善吧,以后改用flash来作或许来得更流畅吧,欢迎大伙多提意见。                         (编辑:52站长网) 
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! 
                     |