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 ...
随机推荐
- Canvas 最佳实践(性能篇)
Canvas 想必前端同学们都不陌生,它是 HTML5 新增的「画布」元素,允许我们使用 JavaScript 来绘制图形.目前,所有的主流浏览器都支持 Canvas. Canvas 最常见的用途是渲 ...
- [RxJava^Android]项目经验分享 --- 失败重试
简单介绍一下业务逻辑:获取字符串,如果获取失败进行10次重试,超出10次未成功视为失败. 模拟获取字符串场景 代码块 class MsgTool { int count; String getMsg( ...
- Java_类似java.lang.VerifyError: Expecting a stackmap frame at branch target 22 in method的解决方法
报异常的方法内使用了Java 7的新特性:自动资源释放,类似于try(){},即在try后面跟一括号,在括号里面对一些资源赋值,try里面的代码块执行完毕之后会自动释放try后面的括号中声明的资源. ...
- linux一句话轻松提权
linux命令: [b@fuckks~]$ printf "install uprobes /bin/sh" > exploit.conf; MODPROBE_OPTI** ...
- java的值传递笔记
1. 背景:开发小伙伴突然问我java是值传递还是引用传递,我说当然是值传递,只不过有时候传递一个对象时实际传递的是对象的地址值,所以让人容易产生一种引用传递的假象,貌似在李刚的疯狂java讲义有提到 ...
- C++ 虚函数表解析
转载:陈皓 http://blog.csdn.net/haoel 前言 C++中 的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实 ...
- jasmine入门
本文来自http://blog.fens.me/nodejs-jasmine-bdd 粉丝日志 张丹 前言TDD(Test Driven Development)测试驱动开发,是敏捷开发中提出的最 ...
- Spring的通知(Advice)
Spring提供了5种Advice类型: Interception Around:JointPoint前后调用 Before:JointPoint前调用 After Returning:JointPo ...
- js弹出框、对话框、提示框、弹窗总结
一.JS的三种最常见的对话框 //====================== JS最常用三种弹出对话框 ======================== //弹出对话框并输出一段提示信息 funct ...
- Android应用性能优化(转)
人类大脑与眼睛对一个画面的连贯性感知其实是有一个界限的,譬如我们看电影会觉得画面很自然连贯(帧率为24fps),用手机当然也需要感知屏幕操作的连贯性(尤其是动画过度),所以Android索性就把达到这 ...