javascript实现10个球随机运动、碰撞实例详解


Posted in Javascript onJuly 08, 2015

本文实例讲述了javascript实现10个球随机运动、碰撞的方法。分享给大家供大家参考。具体如下:

学了一段时间的javascript了,做过一些小案例,目前最有难度的就是10个小球随机碰撞效果,这不,把它上上来与大家分享一下,相信不少和我一样的菜鸟在开始上手编程时都会有不少的困惑,希望它能给一些人带来帮助。

效果要求:10个小球在页面随机移动,碰到窗口边界或其他小球都会反弹

思路:

1、10个小球是10个div;
2、碰窗口反弹,定义vx vy为小球的移动变量,以及一个弹力变量bounce(负值),小球碰窗口边界时,vx vy分别乘以bounce,则改变了小球移动方向
3、小球相碰反弹,说简单点,当两个小球的圆心距变量dist小于其最小值(半径之和)则改变球的移动方向,实现反弹

好了,代码如下:

html和js是分开的文件哟
 
test.html文件如下:

<html>
 <head>
  <title></title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   <style type="text/css">
body {
    margin:0;
    padding:0;
    text-align: center;
}
#screen { width: 800px; height: 640px; position: relative; background: #ccccff;margin: 0 auto;vertical-align: bottom}
#inner { position: absolute; left:0px; top:0px; width:100%; height:100%; }
#screen p {color:white;font:bold 14px;}
.one { background-image:url('bubble.png'); background-position: -66px -58px; }
.two { background-image:url('bubble.png'); background-position: -66px -126px;}
.three { background-image:url('bubble.png'); background-position: -66px -194px; }
.four { background-image:url('bubble.png'); background-position: -66px -263px; }
.five { background-image:url('bubble.png'); background-position: -66px -331px; }
.six { background-image:url('bubble.png'); background-position: -66px -399px; }
.seven { background-image:url('bubble.png'); background-position: -66px -194px; }
.eight { background-image:url('bubble.png'); background-position: -66px -263px; }
.nine { background-image:url('bubble.png'); background-position: -66px -331px; }
.ten{ background-image:url('bubble.png'); background-position: -66px -399px; }
  </style>
 </head>
 <body>
   <div id="screen" >
     <p>hi test it!</p>
     <div id="inner"></div>
   </div>
   <input type="button" id="start" value="start" >
   <input type="button" id="stop" value="stop">
   <br><br><br>
<script type="text/javascript" src="test.js"></script>
 </body>
</html>

test.js文件如下:

var getFlag=function (id) {
     return document.getElementByIdx_x(id);  //获取元素引用
}
var extend=function(des, src) {
     for (p in src) {
       des[p]=src[p];
   }
  return des;
 }
var clss=['one','two','three','four','five','six','seven','eight','nine','ten'];
var Ball=function (diameter,classn) {
  var ball=document.createElement_x("div");
  ball.className=classn;
  with(ball.style) {
    width=height=diameter+'px';position='absolute';
  }
  return ball;
}
var Screen=function (cid,config) {
  //先创建类的属性
  var self=this;
  if (!(self instanceof Screen)) {
    return new Screen(cid,config)
  }
  config=extend(Screen.Config, config)  //configj是extend类的实例
  self.container=getFlag(cid);      //窗口对象
  self.ballsnum=config.ballsnum;
  self.diameter=56;            //球的直径
  self.radius=self.diameter/2;
  self.spring=config.spring;       //球相碰后的反弹力
  self.bounce=config.bounce;       //球碰到窗口边界后的反弹力
  self.gravity=config.gravity;      //球的重力
  self.balls=[];             //把创建的球置于该数组变量
  self.timer=null;            //调用函数产生的时间id
  self.L_bound=0;            //container的边界
  self.R_bound=self.container.clientWidth;
  self.T_bound=0;
  self.B_bound=self.container.clientHeight;
};
Screen.Config={             //为属性赋初值
  ballsnum:10,
  spring:0.8,
  bounce:-0.9,
  gravity:0.05
};
Screen.prototype={
  initialize:function () {
    var self=this;
    self.createBalls();
    self.timer=setInterval(function (){self.hitBalls()}, 30)
  },
  createBalls:function () {
    var self=this, num=self.ballsnum;
    var frag=document.createDocumentFragment();  //创建文档碎片,避免多次刷新    
     for (i=0;i<num;i++) {
      var ball=new Ball(self.diameter,clss[ Math.floor(Math.random()* num )]);
      ball.diameter=self.diameter;
      ball.radius=self.radius;
      ball.style.left=(Math.random()*self.R_bound)+'px'; //球的初始位置,
      ball.style.top=(Math.random()*self.B_bound)+'px';
      ball.vx=Math.random() * 6 -3;
      ball.vy=Math.random() * 6 -3;
      frag.appendChild(ball);
      self.balls[i]=ball;
    }
    self.container.appendChild(frag);
  },
  hitBalls:function () {
    var self=this, num=self.ballsnum,balls=self.balls;
    for (i=0;i<num-1;i++) {
      var ball1=self.balls[i];
      ball1.x=ball1.offsetLeft+ball1.radius;   //小球圆心坐标
      ball1.y=ball1.offsetTop+ball1.radius;
      for (j=i+1;j<num;j++) {
        var ball2=self.balls[j];
        ball2.x=ball2.offsetLeft+ball2.radius;
        ball2.y=ball2.offsetTop+ball2.radius;
        dx=ball2.x-ball1.x;           //两小球圆心距对应的两条直角边
        dy=ball2.y-ball1.y;
        var dist=Math.sqrt(dx*dx + dy*dy);    //两直角边求圆心距
        var misDist=ball1.radius+ball2.radius;  //圆心距最小值
       if(dist < misDist) {          
          //假设碰撞后球会按原方向继续做一定的运动,将其定义为运动A  
          var angle=Math.atan2(dy,dx);
         //当刚好相碰,即dist=misDist时,tx=ballb.x, ty=ballb.y
          tx=balla.x+Math.cos(angle) * misDist; 
            ty=balla.y+Math.sin(angle) * misDist;
         //产生运动A后,tx > ballb.x, ty > ballb.y,所以用ax、ay记录的是运动A的值
            ax=(tx-ballb.x) * self.spring; 
            ay=(ty-ballb.y) * self.spring;
         //一个球减去ax、ay,另一个加上它,则实现反弹
            balla.vx-=ax;             
            balla.vy-=ay;
            ballb.vx+=ax;
            ballb.vy+=ay;
          }
      }
    }
    for (i=0;i<num;i++) {
      self.moveBalls(balls[i]);
    }
  },
  moveBalls:function (ball) {
    var self=this;
    ball.vy+=self.gravity;
    ball.style.left=(ball.offsetLeft+ball.vx)+'px';
    ball.style.top=(ball.offsetTop+ball.vy)+'px';
    //判断球与窗口边界相碰,把变量名简化一下
    var L=self.L_bound, R=self.R_bound, T=self.T_bound, B=self.B_bound, BC=self.bounce; 
    if (ball.offsetLeft < L) {
      ball.style.left=L;
      ball.vx*=BC;
    }
    else if (ball.offsetLeft + ball.diameter > R) {
      ball.style.left=(R-ball.diameter)+'px';
      ball.vx*=BC;
    }
    else if (ball.offsetTop < T) {
      ball.style.top=T;
      ball.vy*=BC;
    }
    if (ball.offsetTop + ball.diameter > B) {
      ball.style.top=(B-ball.diameter)+'px';
      ball.vy*=BC;
    }
  }
}
window.onload=function() {
  var sc=null;
  getFlag('start').onclick=function () {
    document.getElementByIdx_x("inner").innerHTML='';
    sc=new Screen('inner',{ballsnum:10, spring:0.8, bounce:-0.9, gravity:0.05});
    sc.initialize();
  }
  getFlag('stop').onclick=function() {
    clearInterval(sc.timer);
  }
}

测试后的效果还是很不错的,各位也许会觉得代码挺长,但是其思路还是蛮清晰的:
首先创建Screen类,并在Screen的构造函数中给出了球移动、碰撞所需的各种属性变量,如ballsnum、spring、bounce、gravity等等
然后用原型prototype给出相应的函数,如创建球,createBalls,球碰撞hitBalls,球移动moveBalls,给每个函数添加相应的功能、
最后用按钮点击事件调用函数,仅此而已。

希望本文所述对大家的javascript程序设计有所帮助。

Javascript 相关文章推荐
jQuery学习笔记 更改jQuery对象
Sep 19 Javascript
JS表格组件神器bootstrap table详解(强化版)
May 26 Javascript
运用js教你轻松制作html音乐播放器
Apr 17 Javascript
Vue 固定头 固定列 点击表头可排序的表格组件
Nov 25 Javascript
详解Jquery EasyUI tree 的异步加载(遍历指定文件夹,根据文件夹内的文件生成tree)
Feb 11 Javascript
jQuery Mobile漏洞会有跨站脚本攻击风险
Feb 12 Javascript
Angular.js中angular-ui-router的简单实践
Jul 18 Javascript
一次记住JavaScript的6个正则表达式方法
Feb 22 Javascript
vue项目中实现缓存的最佳方案详解
Jul 11 Javascript
vue 使用element-ui中的Notification自定义按钮并实现关闭功能及如何处理多个通知
Aug 17 Javascript
原生js拖拽实现图形伸缩效果
Feb 10 Javascript
vue项目中使用vue-layer弹框插件的方法
Mar 11 Javascript
详细分析JavaScript变量类型
Jul 08 #Javascript
js实现图片点击左右轮播
Jul 08 #Javascript
javascript获取重复次数最多的字符
Jul 08 #Javascript
javascript连续赋值问题
Jul 08 #Javascript
JavaScript中函数(Function)的apply与call理解
Jul 08 #Javascript
JavaScript forEach()遍历函数使用及介绍
Jul 08 #Javascript
JavaScript中调用函数的4种方式代码实例
Jul 08 #Javascript
You might like
PHP安装问题
2006/10/09 PHP
php+mysql事务rollback&amp;commit示例
2010/02/08 PHP
PHP 命令行工具 shell_exec, exec, passthru, system详细使用介绍
2011/09/11 PHP
php使用curl访问https示例分享
2014/01/17 PHP
浅析PHP微信支付通知的处理方式
2014/05/25 PHP
ThinkPHP3.1基础知识快速入门
2014/06/19 PHP
PHP如何实现跨域
2016/05/30 PHP
在Laravel的Model层做数据缓存的实现
2019/09/26 PHP
javascript间隔刷新的简单实例
2013/11/14 Javascript
基于JS实现密码框(password)中显示文字提示功能代码
2016/05/27 Javascript
jQuery validate插件功能与用法详解
2016/12/15 Javascript
jQuery实现鼠标经过显示动画边框特效
2017/03/24 jQuery
微信小程序实现YDUI的ScrollNav组件
2018/02/02 Javascript
详解Vue中watch的高级用法
2018/05/02 Javascript
Jquery异步上传文件代码实例
2019/11/13 jQuery
全面解析Vue中的$nextTick
2020/12/24 Vue.js
Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)
2008/09/06 Python
Python自动化测试Eclipse+Pydev 搭建开发环境
2016/08/15 Python
Python人工智能之路 之PyAudio 实现录音 自动化交互实现问答
2019/08/13 Python
Python的形参和实参使用方式
2019/12/24 Python
jupyter notebook 添加kernel permission denied的操作
2020/04/21 Python
英国高街品牌:Miss Selfridge(塞尔弗里奇小姐)
2016/09/21 全球购物
Charlotte Tilbury美国官网:英国美妆品牌
2017/10/13 全球购物
艺龙旅行网酒店预订:国内、港澳台酒店
2018/06/26 全球购物
会计专业大学生职业生涯规划书
2014/02/11 职场文书
《童年》教学反思
2014/02/18 职场文书
单位工程竣工验收方案
2014/03/16 职场文书
经销商订货会主持词
2014/03/27 职场文书
中介业务员岗位职责
2014/04/09 职场文书
法人授权委托书
2014/09/16 职场文书
党员个人总结自评
2015/02/14 职场文书
标会主持词应该怎么写?
2019/08/15 职场文书
创业计划书之香辣虾火锅
2019/09/23 职场文书
java固定大小队列的几种实现方式详解
2021/07/15 Java/Android
Python 处理表格进行成绩排序的操作代码
2021/07/26 Python
使用CSS实现小三角边框原理解析
2021/11/07 HTML / CSS