位置:海鸟网 > IT > JavaScript >

JS模拟引力环境下的运动轨迹

话说这篇文章的起源还得从1643年1月4日谈起。这一天,一位引领人类认知世界的巨人诞生了,他就是艾萨克·牛顿(Isaac Newton)。扯远了,就近一点,2010年1月4日,为了纪念牛顿,google设计了一个Google Doodles,看这里:今日google纪念logo-典型的物理运动实现。

  进口审核剪切版:

<input type="button" value="demo" onclick="demo()">
<img id="fall" src=http://www.zzsky.cn/build/content/"" style="position:absolute;left:200px;top:46px">
<script type="text/javascript">
function demo(){
 var h=1,k=-0.5,f=document.getElementById('fall'),
  i=setInterval(function(){
   if(f){
    var y=parseInt(f.style.top) + h;
    if(y<210) {h+=2}
    else{
     h*=(h>1)?k:0
    }
    f.style.top=y+'px';
   }
   if(h==0){clearInterval(i);h=1;}
  },25);
}
</script>



随后,我便模拟了一个重力环境下的抛物线运动:

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>模拟重力环境下的抛物运动(假使1px==1mm)</title>
<style type="text/css">
*{padding:0;margin:0;}
html,body{height:100%;overflow:hidden;}
p{margin:2px;font-size:12px;}
label{display:inline-block;width:80px;text-align:right;}
input{width:80px;}
.wrap{position:relative;width:800px;height:500px;margin:5px;border:1px solid #ccc;}
#fall{width:20px;font-size:0;height:20px;background:orange;position:absolute;top:0;left:0;border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;}
</style>
</head>
<body>
<p><label>横向初速度:</label><input id="Vx" type="text" value="3">px/ms</p>
<p><label>纵向初速度:</label><input id="Vy" type="text" value="0">px/ms</p>
<p><label>重力加速度:</label><input id="a" type="text" value="0.0098">px/平方ms</p>
<p>(如果这个加速度是一个随时间变化的值,就能达到其他非匀加速运动的效果了。)</p>
<p><label>单位时间:</label><input id="t" type="text" value="10">(记录运动的时间间隔)
<p><button type="button" onclick="demo()">演示</button></p>
<div class="wrap">
<div id="fall">o</div>
</div>
<script type="text/javascript">
var $id=function(o) {
 return document.getElementById(o) || o;
}
var demo=function() {
 var x=$id('Vx').value,
  y=$id('Vy').value,
  a=$id('a').value,
  t=$id('t').value;
  shoot(x,y,a,t);
}
var shoot=function(x,y,a,t) {
 var f=document.getElementById('fall');
 var Vx=parseInt(x),
  Vy=parseInt(y),
  g=a,
  t=parseInt(t),
  h=0,l=0,Sx=0,Sy=0;
 var i=setInterval(function(){
  if(f){
   Sx+=Vx*t;
   l=Sx;
   Vy+=g*t;
   h+=Vy*t;
   if(h>480) {
    h=480;
    clearInterval(i);
   }
   if(l>780) {
    l=780;
    clearInterval(i);
   }
   f.style.left=l+'px';
   f.style.top=h+'px';
  }
 },t);
}
</script>
</body>
</html>



  模拟采用的公式:

Function: 对于运动瞬间
V=V0+aT;
S=S0+VT;
T:运动的时间间隔,是固定值



  这个公式有别于那种运动模拟中常用的补间动画公式(tween算法)。补间动画是需要事先确定总路程和总时间的,而我们模拟的运动轨迹没有事先计算,因为我们运动中间或许还有一些变数,比如撞击、主动改变方向(键盘控制)等等,所以我觉得这个物理公式更能模拟出真实的各种运动。

  直至本月前两天,某同事向我展示了这个:重力版google(浏览首选chrome、safari,次选opera、firefox,若是ie9以下请无视)。膜拜啊,js且不论,css3已经大量使用了,我还只局限用用阴影、圆角呢。

  不才也做一个关于落体、撞击、摩擦的简单模拟,以表膜拜。
[/code]<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>模拟引力环境下的撞击、摩擦、落体运动</title>
<style type="text/css">
*{padding:0;margin:0;}
html,body{height:100%;overflow:hidden;}
p{margin:2px;font-size:12px;}
label{display:inline-block;width:80px;text-align:right;}
input{width:80px;}
#fall{width:20px;font-size:0;height:20px;background:orange;position:absolute;top:50px;left:400px;border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;}
</style>
</head>
<body>
<p><label>横向初速度:</label><input id="Vx" type="text" value="3">px/ms</p>
<p><label>纵向初速度:</label><input id="Vy" type="text" value="0">px/ms</p>
<p><label>重力加速度:</label><input id="a" type="text" value="0.01">px/平方ms</p>
<p><label>单位时间:</label><input id="t" type="text" value="10">(记录运动的时间间隔)
<p>摩擦,碰撞的消耗并没有按公式进行计算,纯属于杜撰,是不符合规律的,仅仅是模拟。</p>
<p><button type="button" onclick="demo()">演示</button><button type="button" onclick="document.location.reload()">重置(可拖动放置)</button></p>
<div id="fall" onmousedown="drag(this,event)">o</div>
</body>
<script type="text/javascript">
var $id=function(o) {
 return document.getElementById(o) || o;
}
var demo=function() {
 var x=$id('Vx').value,
  y=$id('Vy').value,
  a=$id('a').value,
  t=$id('t').value;
  shoot(x,y,a,t);
}
var shoot=function(x,y,a,t) {
 if(i) {alert(1);clearInterval(i)};
 var f=document.getElementById('fall');
 var Vx=parseFloat(x),
  Vy=parseFloat(y),
  g=parseFloat(a),
  h=f.offsetTop,
  Sx=f.offsetLeft,
  l=0,
  t=parseInt(t);
 var i=setInterval(function(){
  if(f){
   Sx+=Vx*t;
   l=Sx;
   Vy+=g*t;
   h+=Vy*t;
   if(h>=document.documentElement.offsetHeight-f.offsetHeight) {//底部
    h=document.documentElement.offsetHeight-f.offsetHeight;
    Vx=(Math.abs(Vx)-0.1 < 0) ? 0 : Vx/Math.abs(Vx) * (Math.abs(Vx)-0.1)//摩擦消耗x速度
    Vy=(Math.abs(Vy)-0.8 < 0) ? 0 : -(Math.abs(Vy)-0.8);//撞击消耗y速度
    if(Math.abs(Vy)==0 && Math.abs(Vx)==0 ) {clearInterval(i);}//x、y速度为0时,clear
   }
   if(l<0 || l>document.documentElement.offsetWidth-f.offsetWidth) {//左右两侧
    Sx=(l<0) ? 0 : document.documentElement.offsetWidth-f.offsetWidth;
    Vx=(Math.abs(Vx)-0.2 < 0) ? 0 : -Vx/Math.abs(Vx) * (Math.abs(Vx)-0.2)//撞击消耗x速度
   }
   f.style.left=l+'px';
   f.style.top=h+'px';
  }
 },t);
};
var drag=function(o,e){//拖曳位置,与运动模拟无关
 var e = e ? e : window.event;
 if(!window.event) {e.preventDefault();}
 var tX=o.offsetLeft,
  tY=o.offsetTop,
  dx=e.clientX,
  dy=e.clientY;
 document.onmousemove=function(e){
  var e = e ? e : window.event;
  o.style.left=tX+e.clientX-dx+"px";
  o.style.top=tY+e.clientY-dy+"px";
 }
 document.onmouseup=function(){
  document.onmousemove=null;
  document.onmouseup=null;
 }
}
</script>
</html>[/code]

  对于这个运动的模拟,我觉得以后倒是可以扩展出一些挺有趣的交互游戏的模拟,比如射击、驾驶等等,当然纯属娱乐啦。

  作者:ONEBOYS,原文地址:。