javascript运动系列第八篇——碰壁运动
前面的话
碰撞运动可能是运动系列里面比较复杂的运动了。碰撞可以分为碰壁和互碰两种形式,而碰撞前后的运动形式也可以分为变速和匀速两种,如果再涉及到阻力,具有速度损耗的话,就更加复杂了。本文先介绍碰壁运动
匀速碰壁
碰壁是一种常见的碰撞形式,匀速碰壁是最简单的碰撞运动
假设一个密闭空间内一个弹性小球,小球有一个随机方向随机大小的初始速度。当小球碰壁时,速度不损失,而是做反向的匀速运动
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Document</title>
- </head>
- <body>
- <div id="test" style="height: 100px;width: 100px;background:lightblue;position:absolute;top:60px;left:20px;border-radius:50%;"></div>
- <button id="btn1">开始运动</button>
- <button id="btn2">停止运动</button>
- <span>游戏说明:当小球开始运动后,点击小球一次得一分</span>
- <div id="result"></div>
- <script>
- var timer,i=0;
- //声明得分
- var key = 0;
- var arr = ['orange','lightgreen','lightcoyal','pink','lightcyan','lightgray','lightseagreen','lightsteelblue'];
- function changeColor(){
- i++;
- if(i == arr.length){
- i = 0;
- }
- test.style.background = arr[i];
- }
- document.onmousemove = function(){
- return false;
- }
- test.onclick = function(){
- //当小球开始运动后,开始记分
- if(test.timer){
- result.innerHTML = '当前得分为:' + ++key + '分'
- }
- changeColor();
- }
- btn1.onclick = function(){
- result.innerHTML = ''
- //将分数清零
- key = 0;
- collisionMove({
- obj:test
- })
- clearInterval(timer);
- timer = setInterval(function(){
- changeColor();
- },500);
- }
- btn2.onclick = function(){
- clearInterval(timer);
- clearInterval(test.timer);
- test.timer = 0;
- result.innerHTML = '你得到:' + key + '分,再接再厉!'
- }
- function getCSS(obj,style){
- if(window.getComputedStyle){
- return getComputedStyle(obj)[style];
- }
- return obj.currentStyle[style];
- }
- function collisionMove(json){
- var obj = json.obj;
- var fn = json.fn;
- //声明x、y轴的当前值
- var curX = parseFloat(getCSS(obj,'left'));
- var curY = parseFloat(getCSS(obj,'top'));
- //声明x、y轴的步长值
- var stepX = json.stepX;
- var stepY = json.stepY;
- //步长值默认值为[-25,-20,-15,-10,-5,0,5,10,15,20]中的一个随机数
- stepX = Number(stepX) || 5*Math.floor(Math.random() * 10 - 5);
- stepY = Number(stepY) || 5*Math.floor(Math.random() * 10 - 5);
- //声明x、y轴方向
- var dirX = json.dirX;
- var dirY = json.dirY;
- dirX = stepX > 0 ? '+' : '-';
- dirY = stepY > 0 ? '+' : '-';
- //声明offset宽高
- var offsetWidth = obj.offsetWidth;
- var offsetHeight = obj.offsetHeight;
- //声明元素活动区域宽高
- var activeWidth = json.activeWidth;
- var activeHeight = json.activeHeight;
- //元素获取区域宽高默认值为可视区域宽高
- activeWidth = Number(activeWidth) || document.documentElement.clientWidth;
- activeHeight = Number(activeHeight) || document.documentElement.clientHeight;
- //声明left、top样式值
- var left;
- var top;
- //清除定时器
- if(obj.timer){return;}
- //开启定时器
- obj.timer = setInterval(function(){
- //获取x、y轴的当前值
- curX = parseFloat(getCSS(obj,'left'));
- curY = parseFloat(getCSS(obj,'top'));
- //更新left、top值
- left = curX + stepX;
- top = curY + stepY;
- //右侧碰壁前一刻,步长大于剩余距离,且元素向右运动时
- if((left > activeWidth - offsetWidth) && (dirX == '+')){
- left = activeWidth - offsetWidth;
- }
- //左侧碰壁前一刻,步长大于剩余距离,且元素向左运动时
- if((Math.abs(stepX) > curX) && (dirX == '-')){
- left = curX;
- }
- //下侧碰壁前一刻,步长大于剩余距离,且元素向下运动时
- if((top > activeHeight - offsetHeight) && (dirY == '+')){
- top = activeHeight - offsetHeight;
- }
- //上侧碰壁前一刻,步长大于剩余距离,且元素向上运动时
- if((Math.abs(stepY) > curY) && (dirY == '-')){
- top = curY;
- }
- obj.style.left= left + 'px';
- obj.style.top = top + 'px';
- //左侧或右侧碰撞瞬间
- if(left == activeWidth - offsetWidth || left == curX){
- stepX = -stepX;
- }
- //上侧或下侧碰撞瞬间
- if(top == activeHeight - offsetHeight || top == curY){
- stepY = -stepY;
- }
- //更新运动方向
- dirX = stepX > 0 ? '+' : '-';
- dirY = stepY > 0 ? '+' : '-';
- },20);
- }
- </script>
- </body>
- </html>
自由落体
元素在实际运动中,并不是保持匀速运动的,更多的是变速运动,而且会有速度损耗。典型的场景是自由落体运动,物体落地之后会反方向弹几下,最终停在地上
自由落体运动可以看做是重力与阻力合作的结果。在空中运动时,向下运动时,做匀加速运动;向上运动时,做匀减速运动。与地面碰撞的瞬间,产生速度损耗
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Document</title>
- </head>
- <body>
- <div id="test" style="height:50px;width: 50px;background:lightblue;position:absolute;top:60px;border-radius:50%;"></div>
- <button id="btn1">开始运动</button>
- <button id="btn2">还原</button>
- <script>
- document.onmousedown = function(){
- return false;
- }
- btn1.onclick = function(){
- collisionMove({
- obj:test
- })
- }
- btn2.onclick = function(){
- history.go();
- }
- function getCSS(obj,style){
- if(window.getComputedStyle){
- return getComputedStyle(obj)[style];
- }
- return obj.currentStyle[style];
- }
- function collisionMove(json){
- var obj = json.obj;
- var fn = json.fn;
- //声明y轴的当前值
- var curY = parseFloat(getCSS(obj,'top'));
- //声明offset高
- var offsetHeight = obj.offsetHeight;
- //声明元素活动区域高
- var activeHeight = json.activeHeight;
- //元素获取区域宽高默认值为可视区域高
- activeHeight = Number(activeHeight) || document.documentElement.clientHeight;
- //声明y轴的步长值
- var stepY = 0;
- //声明top样式值
- var top;
- //声明减速系数
- var k = 0.8;
- //声明碰撞次数
- var i = 0;
- //清除定时器
- if(obj.timer){return;}
- //开启定时器
- obj.timer = setInterval(function(){
- //获取y轴的当前值
- curY = parseFloat(getCSS(obj,'top'));
- //更新步长值stepY
- stepY+= 5;
- //更新top值
- top = curY + stepY;
- //下侧碰壁前一刻,步长大于剩余距离,且元素向下运动时
- if(top > activeHeight - offsetHeight){
- top = activeHeight - offsetHeight;
- }
- obj.style.top = top + 'px';
- //下侧碰撞瞬间,改变运动方向,并产生速度损耗
- if(top == activeHeight - offsetHeight){
- //若碰撞10次后,则停止运动
- i++;
- if(i== 10){
- clearInterval(obj.timer)
- obj.timer = 0;
- fn && fn.call(obj);
- }
- stepY = -stepY * k;
- }
- },20);
- }
- </script>
- </body>
- </html>
投掷碰壁
如果一个物体向空中投掷出去,会呈现一个抛物线的效果,最终经过与地面碰撞多次后停止
投掷碰撞效果是x轴和y轴的合效果。x轴做匀速运动,当物体碰到地面后,x轴速度发生损耗;y轴做匀加速运动,当物体碰到地面后,y轴速度同样发生损耗
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Document</title>
- </head>
- <body>
- <div id="test" style="height: 50px;width: 50px;background:lightblue;position:absolute;top:200px;left:20px;border-radius:50%;"></div>
- <button id="btn1">开始运动</button>
- <button id="btn2">还原</button>
- <script>
- document.onmousedown = function(){
- return false;
- }
- btn1.onclick = function(){
- collisionMove({
- obj:test
- })
- }
- btn2.onclick = function(){
- history.go();
- }
- function getCSS(obj,style){
- if(window.getComputedStyle){
- return getComputedStyle(obj)[style];
- }
- return obj.currentStyle[style];
- }
- function collisionMove(json){
- var obj = json.obj;
- var fn = json.fn;
- //声明y轴的当前值
- var curY = parseFloat(getCSS(obj,'top'));
- //声明offset高
- var offsetHeight = obj.offsetHeight;
- //声明元素活动区域高
- var activeHeight = json.activeHeight;
- //元素获取区域宽高默认值为可视区域高
- activeHeight = Number(activeHeight) || document.documentElement.clientHeight;
- //声明x、y轴的步长值
- var stepY = -50;
- var stepX = 10;
- //声明top、left样式值
- var top;
- var left;
- //声明减速系数
- var k = 0.8;
- //声明碰撞次数
- var i = 0;
- //清除定时器
- if(obj.timer){return;}
- //开启定时器
- obj.timer = setInterval(function(){
- //获取x、y轴的当前值
- curX = parseFloat(getCSS(obj,'left'));
- curY = parseFloat(getCSS(obj,'top'));
- //更新步长值stepY
- stepY+= 5;
- //更新top、left值
- top = curY + stepY;
- left = curX + stepX;
- //下侧碰壁前一刻,步长大于剩余距离,且元素向下运动时
- if(top > activeHeight - offsetHeight){
- top = activeHeight - offsetHeight;
- }
- obj.style.top = top + 'px';
- obj.style.left = left + 'px';
- //下侧碰撞瞬间,改变运动方向,并产生速度损耗
- if(top == activeHeight - offsetHeight){
- //若碰撞10次后,则停止运动
- i++;
- if(i== 10){
- clearInterval(obj.timer)
- obj.timer = 0;
- fn && fn.call(obj);
- }
- //速度损耗
- stepY = -stepY * k;
- stepX = stepX * k;
- }
- },20);
- }
- </script>
- </body>
- </html>
拖拽碰壁
实际情况下,一个物体默认具有重力效果。物体的重力效果是时时刻刻都在发生的,相当于定时器的每次运动,都有向下的匀加速运动
如果投掷速度不同,则运动速度也不相同。在碰壁的情况下,速度会有损耗,并且发生速度方向变化。最终,物体会落到地上
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Document</title>
- </head>
- <body>
- <div id="test" style="height: 100px;width: 100px;border-radius:50%;background:pink;position:absolute;top:40px;left:0;"></div>
- <script>
- //声明元素投掷步长值
- var stepX=0,stepY=0;
- //默认情况下,也存在重力效果
- collisionMove({
- obj:test,
- stepX:stepX,
- stepY:stepY
- })
- function getCSS(obj,style){
- if(window.getComputedStyle){
- return getComputedStyle(obj)[style];
- }
- return obj.currentStyle[style];
- }
- //碰撞运动函数
- function collisionMove(json){
- var obj = json.obj;
- var fn = json.fn;
- //声明x、y轴的当前值
- var curX = parseFloat(getCSS(obj,'left'));
- var curY = parseFloat(getCSS(obj,'top'));
- //声明x、y轴的步长值
- var stepX = json.stepX;
- var stepY = json.stepY;
- //声明元素的重要加速度
- var g = json.g || 3;
- //步长值默认值为10
- if(isNaN(Number(stepX))){
- stepX = 10;
- }else{
- stepX = Number(stepX);
- }
- if(isNaN(Number(stepY))){
- stepY = 10;
- }else{
- stepY = Number(stepY);
- }
- //声明x、y轴方向
- var dirX = json.dirX;
- var dirY = json.dirY;
- dirX = stepX > 0 ? '+' : '-';
- dirY = stepY > 0 ? '+' : '-';
- //声明offset宽高
- var offsetWidth = obj.offsetWidth;
- var offsetHeight = obj.offsetHeight;
- //声明元素活动区域宽高
- var activeWidth = json.activeWidth;
- var activeHeight = json.activeHeight;
- //元素获取区域宽高默认值为可视区域宽高
- activeWidth = Number(activeWidth) || document.documentElement.clientWidth;
- activeHeight = Number(activeHeight) || document.documentElement.clientHeight;
- //声明left、top样式值
- var left;
- var top;
- //声明减速系数
- var k = 0.8;
- //声明碰撞次数
- var i = 0;
- //清除定时器
- if(obj.timer){return;}
- //开启定时器
- obj.timer = setInterval(function(){
- //获取x、y轴的当前值
- curX = parseFloat(getCSS(obj,'left'));
- curY = parseFloat(getCSS(obj,'top'));
- //受到重力影响,更新步长值stepY
- stepY += g;
- //更新left、top值
- left = curX + stepX;
- top = curY + stepY;
- //右侧碰壁前一刻,步长大于剩余距离,且元素向右运动时
- if((left > activeWidth - offsetWidth) && (dirX == '+')){
- left = activeWidth - offsetWidth;
- }
- //左侧碰壁前一刻,步长大于剩余距离,且元素向左运动时
- if((Math.abs(stepX) > curX) && (dirX == '-')){
- left = curX;
- }
- //下侧碰壁前一刻,步长大于剩余距离,且元素向下运动时
- if((top > activeHeight - offsetHeight) && (dirY == '+')){
- top = activeHeight - offsetHeight;
- }
- //上侧碰壁前一刻,步长大于剩余距离,且元素向上运动时
- if((Math.abs(stepY) > curY) && (dirY == '-')){
- top = curY;
- }
- obj.style.left= left + 'px';
- obj.style.top = top + 'px';
- //左侧或右侧碰撞瞬间
- if(left == activeWidth - offsetWidth || left == curX){
- //x轴方向速度损耗,并发生方向变化
- stepX = -stepX * k;
- }
- //上侧或下侧碰撞瞬间
- if(top == activeHeight - offsetHeight || top == curY){
- //y轴方向速度损耗,并发生方向变化
- stepY = -stepY * k;
- //x轴方向速度损耗
- stepX = stepX * k;
- }
- //元素与地面碰撞10次后,则停止运动
- if(top == activeHeight - offsetHeight){
- i++;
- if(i== 10){
- clearInterval(obj.timer)
- obj.timer = 0;
- fn && fn.call(obj);
- }
- }
- //更新运动方向
- dirX = stepX > 0 ? '+' : '-';
- dirY = stepY > 0 ? '+' : '-';
- },20);
- }
- //初始抛掷
- test.onmousedown = function(e){
- e = e || event;
- //声明上一次mousemove事件的坐标位置
- var lastX2 = e.clientX;
- var lastY2 = e.clientY;
- //获取元素距离定位父级的x轴及y轴距离
- var x0 = this.offsetLeft;
- var y0 = this.offsetTop;
- //获取此时鼠标距离视口左上角的x轴及y轴距离
- var x1 = e.clientX;
- var y1 = e.clientY;
- //鼠标按下时,获得此时的页面区域
- var L0 = 0;
- var R0 = document.documentElement.clientWidth;
- var T0 = 0;
- var B0 = document.documentElement.clientHeight;
- //鼠标按下时,获得此时的元素宽高
- var EH = this.offsetHeight;
- var EW = this.offsetWidth;
- document.onmousemove = function(e){
- e = e || event;
- //获取此时鼠标距离视口左上角的x轴及y轴距离
- var x2 = e.clientX;
- var y2 = e.clientY;
- stepX = x2 - lastX2;
- stepY = y2 - lastY2;
- lastX2 = e.clientX;
- lastY2 = e.clientY;
- //计算此时元素应该距离视口左上角的x轴及y轴距离
- var X = x0 + (x2 - x1);
- var Y = y0 + (y2 - y1);
- /******范围限定*******/
- //获取鼠标移动时元素四边的瞬时值
- var L = X;
- var R = X + EW;
- var T = Y;
- var B = Y + EH;
- //在将X和Y赋值给left和top之前,进行范围限定
- //只有在范围内时,才进行相应的移动
- //如果脱离左侧范围,则left置L0
- if(L < L0){X = L0;}
- //如果脱离右侧范围,则left置为R0
- if(R > R0){X = R0 - EW;}
- //如果脱离上侧范围,则top置T0
- if(T < T0){Y = T0;}
- //如果脱离下侧范围,则top置为B0
- if(B > B0){Y = B0 - EH;}
- //将X和Y的值赋给left和top,使元素移动到相应位置
- test.style.left = X + 'px';
- test.style.top = Y + 'px';
- }
- document.onmouseup = function(e){
- e = e || event;
- var maxHeight = document.documentElement.clientHeight - test.offsetHeight;
- var maxWidth = document.documentElement.clientWidth - test.offsetWidth;
- //以设置的投掷速度来进行碰撞运动
- collisionMove({
- obj:test,
- stepX:stepX,
- stepY:stepY
- })
- //当鼠标抬起时,拖拽结束,则将onmousemove赋值为null即可
- document.onmousemove = null;
- //释放全局捕获
- if(test.releaseCapture){
- test.releaseCapture();
- }
- }
- //阻止默认行为
- return false;
- //IE8-浏览器阻止默认行为
- if(test.setCapture){
- test.setCapture();
- }
- }
- </script>
- </body>
- </html>
javascript运动系列第八篇——碰壁运动的更多相关文章
- javascript运动系列第五篇——缓冲运动和弹性运动
× 目录 [1]缓冲运动 [2]弹性运动 [3]距离分析[4]步长分析[5]弹性过界[6]弹性菜单[7]弹性拖拽 前面的话 缓冲运动指的是减速运动,减速到0的时候,元素正好停在目标点.而弹性运动同样是 ...
- javascript面向对象系列第三篇——实现继承的3种形式
× 目录 [1]原型继承 [2]伪类继承 [3]组合继承 前面的话 学习如何创建对象是理解面向对象编程的第一步,第二步是理解继承.本文是javascript面向对象系列第三篇——实现继承的3种形式 [ ...
- 深入理解javascript函数系列第三篇——属性和方法
× 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...
- 深入理解javascript作用域系列第四篇——块作用域
× 目录 [1]let [2]const [3]try 前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用 ...
- 深入理解javascript作用域系列第三篇——声明提升(hoisting)
× 目录 [1]变量 [2]函数 [3]优先 前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javasc ...
- 深入理解javascript作用域系列第三篇
前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javascript作用域系列第三篇——声明提升(hois ...
- 深入理解javascript作用域系列第四篇
前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀.简洁的 ...
- 深入理解javascript函数系列第三篇
前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数 ...
- 【JavaScript数据结构系列】00-开篇
[JavaScript数据结构系列]00-开篇 码路工人 CoderMonkey 转载请注明作者与出处 ## 0. 开篇[JavaScript数据结构与算法] 大的计划,写以下两部分: 1[JavaS ...
随机推荐
- linux shell basic command
Learning basic Linux commands Command Description $ ls This command is used to check the contents of ...
- js实现简单的图片轮播
js代码如下 <script type="text/javascript"> var n=1; var map=new Array(); map[0]=new Imag ...
- SRM 628 DIV2
250 想想就发现规律了. 500 暴力,括号匹配. 1000 给一个f数组,如果i存在,那么f[i]也得存在,问这样的集合有多少种. 先拓扑一下,dp[i] = mul(dp[son]+1)最后 ...
- 懒加载lazyload
什么是懒加载 懒加载就是当你做滚动到页面某个位置,然后再显示当前位置的图片,这样做可以减少页面请求. 懒加载:主要目的是作为服务器前端的优化,减少请求数或延迟请求数,一些图片非常多的网站中非常有用,在 ...
- 无法加载 DLL“SQLite.Interop.dll”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)
SQLite部署-无法加载 DLL“SQLite.Interop.dll”: 找不到指定的模块 近期刚使用SQLite,主要引用的是System.Data.SQLite.dll这个dll,在部署到测试 ...
- 也来说说关于未在本地计算机上注册“VFPOLEDB.1”的程序的解决方法
大家都知道VFP是一个非常古老的数据库.但是,还有一些单位用到这些数据库. 前段时间,也做了一个关于DBF数据导出的功能的测试.程序以前有同事写好了,但当我进行修改调试的时候,问题就出来了. 调试的时 ...
- HUAS_ACM 个人训练#4
A 题目连接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=117542#problem/A 题意:给出n个单词(字符串),选出最长的字符 ...
- (转)什么是“黑客” by 王珢
什么是“黑客” by 王垠很多程序员自豪的把自己叫做“黑客”(hacker),把编程叫做 hack.可是殊不知,其实在最高级的程序员眼里,“黑客”其实是一个贬义词.他们更愿意被叫做“程序员”(prog ...
- form data和request payload的区别
HTML <form> 标签的 enctype 属性 在下面的例子中,表单数据会在未编码的情况下进行发送: <form action="form_action.asp&qu ...
- Android课程---远程服务器存储
在使用Volley进行获取数据时,需要事先准备环境:在libs里面导入一个Volley.jar包,在网上都有,可以下载下来导入,或者自己电脑上有DT的,自己合成一个包也行. WebActivity.j ...