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 相关文章推荐
js 自定义的联动下拉框
Feb 07 Javascript
qTip 基于JQuery的Tooltip插件[兼容性好]
Sep 01 Javascript
jquery实现手机发送验证码的倒计时代码
Feb 12 Javascript
jQuery的图片滑块焦点图插件整理推荐
Dec 07 Javascript
JS组件Bootstrap实现下拉菜单效果代码
Apr 26 Javascript
js利用正则表达式检验输入内容是否为网址
Jul 05 Javascript
一个超简单的jQuery回调函数例子(分享)
Aug 08 Javascript
巧用jQuery选择器提高写表单效率的方法
Aug 19 Javascript
详解.vue文件中style标签的几个标识符
Jul 17 Javascript
Vue与Node.js通过socket.io通信的示例代码
Jul 25 Javascript
jQuery实现的点击显示隐藏下拉菜单功能完整示例
May 17 jQuery
如何手写简易的 Vue Router
Oct 10 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
15种PHP Encoder的比较
2007/03/06 PHP
php 生成随机验证码图片代码
2010/02/08 PHP
基于php冒泡排序算法的深入理解
2013/06/09 PHP
eAccelerator的安装与使用详解
2013/06/13 PHP
php预定义变量使用帮助(带实例)
2013/10/30 PHP
PHP的Yii框架中行为的定义与绑定方法讲解
2016/03/18 PHP
js 三级关联菜单效果实例
2013/08/13 Javascript
js判断手机和pc端选择不同执行事件的方法
2015/01/30 Javascript
js漂浮广告实现代码
2015/08/15 Javascript
jquery实现最简单的滑动菜单效果代码
2015/09/12 Javascript
javascript加载xml 并解析各节点的值(实现方法)
2016/10/12 Javascript
JS字符串统计操作示例【遍历,截取,输出,计算】
2017/03/27 Javascript
Vue CLI3创建项目部署到Tomcat 使用ngrok映射到外网
2019/05/16 Javascript
微信小程序在其他页面监听globalData中值的变化
2019/07/15 Javascript
vuex中遇到的坑,vuex数据改变,组件中页面不渲染操作
2020/11/16 Javascript
[04:26]2014DOTA2国际邀请赛-Newbee顺利进入胜者组决赛 独家专访战神7
2014/07/19 DOTA
Python实现TCP/IP协议下的端口转发及重定向示例
2016/06/14 Python
Python的string模块中的Template类字符串模板用法
2016/06/27 Python
Python中字典的setdefault()方法教程
2017/02/07 Python
简单实现python收发邮件功能
2018/01/05 Python
Python使用flask框架操作sqlite3的两种方式
2018/01/31 Python
python3.6 tkinter实现屏保小程序
2019/07/30 Python
python创建属于自己的单词词库 便于背单词
2019/07/30 Python
Python使用指定字符长度切分数据示例
2019/12/05 Python
Jupyter notebook无法导入第三方模块的解决方式
2020/04/15 Python
Myprotein丹麦官网:欧洲第一运动营养品牌
2019/04/15 全球购物
Prototype如何实现页面局部定时刷新
2013/08/06 面试题
革命先烈的英雄事迹材料
2014/02/15 职场文书
不服从公司安排检讨书
2014/09/24 职场文书
美术教师个人工作总结
2015/02/06 职场文书
公司财务人员岗位职责
2015/04/14 职场文书
农业项目投资意向书
2015/05/09 职场文书
大学学生会辞职信
2015/05/13 职场文书
golang中的空slice案例
2021/04/27 Golang
js实现模拟购物商城案例
2021/05/18 Javascript
cypress测试本地web应用
2022/06/01 Javascript