7 缓冲和弹跳
下面我们来介绍一下很常用的缓冲和弹跳的处理。在我们实现复杂运动时,这两种技术会处理大多种的情况。缓冲与弹跳非常均是用来处理将一个对象从已知起点移动到给定终点的技术——缓冲是指对象滑动到目标位置并停止,而弹跳是指对象做有摩擦力的弹簧振子运动。它们有一些共同点:
具体原理是缓冲的速度大小与距离成正相关,而弹跳的加速度大小与距离成正相关。
7.1 缓冲处理
缓冲有两大类,缓冲进入到某一种与缓冲离开某一点;同时还有一些具体的运动属性,如以正弦形式缓冲,以弹跳形式缓冲等。我们主要讨论缓冲离开某点的实现,其它的后面会做简单介绍。
7.1.1 简单缓冲
简单缓冲很容易理解,下面来简单描述其实现。假设我们想把一个对象在多帧时间之内从A移动到B。我们可以计算A,B两点间的角度与距离,对速度进行正交分解,之后在每一帧的动画中重新绘制当前对象到新位置,等对象到达B点时,停止移动对象。
上面的方案很容易实现,但如果我们想让对象移动得更自然一些,这个方案就不对了。因为它指定了对象以给定的速度在运动,到达终点时立即停止,这只适合于前面我们介绍的碰撞。我们想要的是带缓冲的实现,在这种情况下,开始的运动速度非常快,随着逐渐接近目标,速度线性地减小,当到达目标位置时,速度变为0。这种简单缓冲有一种非常容易实现的逼近方案:
1. 设定一个数值(缓冲系统)用来模拟逼近我们的缓冲运动,此值与摩擦系数类似,在0和1之间。
2. 决定目标位置
3. 计算起点到终点的距离
4. 用上面设定的缓冲系数值乘以我们得到的距离,此即当前运动对象的速度
5. 在每一帧以上面得到的速度来确定物体的速度
6. 重复上述3~5步。
上面我们指定的缓冲系数可以视为距离的摩擦系数,缓冲系数越接近1,瞬时速度也越大。按上面的描述,我们仍然以小球模型来实现一个简单缓冲的例子。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>缓冲处理</title>
<style type="text/css">
body {
margin: 0px;
padding: 0px;
}
canvas {
margin: 0px;
padding: 0px;
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<script type="text/javascript" src="utils.js"></script>
<script type="text/javascript" src="ball.js"></script>
<script type="text/javascript">
window.onload=function(){
//初始化环境参数
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
//设置缓冲系数
var EASING=0.1;
//创建小球实例
var ball=new Ball(40);
ball.x=0;
ball.y=0;
(function animationLoop(){
window.requestAnimFrame(animationLoop,canvas);
context.clearRect(0,0,canvas.width,canvas.height);
//利用缓冲公式,得到正交分解后的瞬时速度
ball.vx=(canvas.width/2-ball.x)*EASING;
ball.vy=(canvas.height/2-ball.y)*EASING;
//更新当前帧小球位置并绘制
ball.x+=ball.vx;
ball.y+=ball.vy;
ball.paint(context);
})();
};
</script>
</body>
</html>
</html>
很简单吧?那结合之前我们介绍过的拖动对象,我们如果把对象拖到一个位置,让对象缓冲运动来原始位置。实现也非常简单,如下:
window.onload=function(){
//初始化环境参数
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
//设置缓冲系数
var EASING=0.1;
var mouse=utils.getMousePosition(canvas);
//创建小球实例
var ball=new Ball(40);
ball.x=canvas.width/2;
ball.y=canvas.height/2;
//注册鼠标按下事件,检测鼠标是否位于小球内部
canvas.addEventListener("mousedown",function(event){
if(utils.containsPoint(mouse.x,mouse.y,ball.getBounds())){
console.log("inner");
ball.isDragged=true;
}
},false);
//注册鼠标移动事件,在鼠标位于小球内时拖动小球
canvas.addEventListener("mousemove",function(event){
if(ball.isDragged){
ball.x=mouse.x;
ball.y=mouse.y;
}
},false);
//注册鼠标抬起事件
canvas.addEventListener("mouseup",function(event){
ball.isDragged=false;
},false);
(function animationLoop(){
window.requestAnimFrame(animationLoop,canvas);
context.clearRect(0,0,canvas.width,canvas.height);
//在小球未拖动时处理缓冲移动
if(!ball.isDragged){
//利用缓冲公式,得到正交分解后的瞬时速度
ball.vx=(canvas.width/2-ball.x)*EASING;
ball.vy=(canvas.height/2-ball.y)*EASING;
//更新当前帧小球位置并绘制
ball.x+=ball.vx;
ball.y+=ball.vy;
}
ball.paint(context);
})();
};
上面的实现其实有很大的性能优化余地。当运动对象已经到达目标位置后,我们的程序还在重复计算对象的速度,重绘界面。只需要添加以下约束即可:
if (ball.x === targetX && ball.y === targetY) {
//具体运动代码
}
但其实上面的要求相当苛刻,在芝诺悖论中就描述了相关的问题(http://zh.wikipedia.org/wiki/芝诺悖论) 。在工程上我们可以找到简单的逼近方案,下面的代码很清晰地给出了结论:
var position = 0,
target = 100;
for (var i = 0; i < 20; i++) {
console.log(i + ": " + position);
position += (target - position) * 0.5;
}
可以看到,在最后一次输出时,position的值已经是99.99990463256836了。这与我们的结果已经非常接近了。我们可以根据缓冲系数得到一个次数,来进行性能优化。当然,在canvas游戏开发中,由于我们的最小单位是像素,所以在工程实现上可以有更简单的逼近方案,如下:
var animationFlag=null;
(function drawFrame () {
animationFlag = window.requestAnim(drawFrame, canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
var dx = targetX – ball.x;
//距离一像素以内时,停止处理
if (Math.abs(dx) < 1) {
ball.x = targetX;
window.cancelRequestAnimationFrame(animRequest);
} else {
var vx = dx * EASING;
ball.x += vx;
}
ball.draw(context);
}());
对于终点是动态确定的情形,也很容易实现,结合之前我们实现的鼠标位置获取,我们用鼠标位置来当作终点。如下代码:
window.onload = function () {
var canvas = document.getElementById('canvas'),
var context = canvas.getContext('2d'),
var mouse = utils.getMousePosition(canvas),
var ball = new Ball(),
var EASING = 0.05;
(function animationLoop () {
window.requestAnimFrame(animationLoop, canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
//将鼠标位置设动态设定为终点
var vx = (mouse.x - ball.x) * EASING,
vy = (mouse.y - ball.y) * EASING;
ball.x += vx;
ball.y += vy;
ball.draw(context);
}());
};
7.1.2 缓冲的使用场景
说了这么多,你可能以为缓冲只能使用到运动动画中。其实不然,它的使用场景非常丰富,我们可以对指定对象的多个属性变化来使用缓冲技术。
角度变化的缓冲
很容易理解,起始位置只是换成了角度而已。如下实现:
rotation += (targetRotation - rotation) * easing;
arrow.rotation = rotation * Math.PI / 180;
颜色变化的缓冲(渐变)
使用缓冲方式可以更加逼真地模拟色彩变化中的色值大小变化,透明度的变化。如果是处理色彩变化,最好是先把色值分为r,g,b后独立地对rgb三个值进行修正。如下实现:
//设置初始化值
var red = 255,green = 0,blue = 0,redTarget = 0,greenTarget = 0,blueTarget = 255;
//对R,G,B三角分别做处理
red += (redTarget - red) * easing;
green += (greenTarget - green) * easing;
blue += (blueTarget - blue) * easing;
//将R,G,B形式的色彩转换为16进制表示法
var color = red << 16 | green << 8 | blue;
透明度的处理也可以按此模式:
alpha += (targetAlpha - alpha) * easing;
ball.color = "rgba(255, 0, 0," + alpha + ")";
7.1.3 复杂缓冲
对于缓冲的处理,我们介绍了最简单的处理方式,复杂的方式通常是以一条或多条曲线来模拟整个速度的变化,参见【http://flashblog.robertpenner.com/(flash版本)】及javascript版本【https://github.com/lamberta/html5-animation/tree/master/xtras/easing-equations】
分享到:
相关推荐
9. **最佳实践**:分享HTML5 Canvas开发的最佳实践,包括代码组织、调试技巧以及如何确保兼容性。 10. **社区与资源**:可能还会介绍一些HTML5和Canvas的在线社区、工具、库和框架,帮助读者持续学习和提高。 总的...
在这个"HTML5 Canvas核心技术图形、动画与游戏开发"的PDF扫描版中,读者可以深入学习到Canvas的核心概念和实践技巧。 首先,Canvas的基本使用方法是通过JavaScript API来实现的。这个API提供了大量的绘图命令,如`...
在微信小程序中,Canvas是一个非常重要的组件,它允许开发者在...以上就是关于"小程序canvasDemo"项目中涉及的主要技术点,通过学习和实践,你可以掌握微信小程序中canvas的使用技巧,进一步提升你的小程序开发能力。
HTML5的Canvas是一个强大的绘图API,它允许开发者在网页上进行动态的、基于...随着对Canvas的深入理解和实践,你会发现它的潜力无穷无尽。在实际项目中,可以结合CSS3、WebGL等技术,构建更复杂的交互式Web应用。
HTML5 Canvas是Web开发中的一个强大工具,它允许开发者在网页上进行动态图形绘制,创造出丰富的交互式用户体验。在这个“html5_canvas_...这样的实现不仅方便分享,也为开发者提供了一个学习和实践Canvas API的好平台。
《canvas+js绘制图形的实践探索》 在Web开发领域,HTML5的canvas元素提供了一种强大的机制,允许开发者在浏览器上进行动态图形绘制。这篇博文将深入探讨如何结合JavaScript,利用canvas API来构建一个简单的绘图小...
这个功能在很多场景下都非常有用,比如网页分享、游戏截图、在线编辑器保存草图等。 首先,我们要了解canvas的基本用法。canvas是一个矩形画布,通过JavaScript来控制它的内容。我们可以通过`<canvas>`标签在HTML中...
HTML5 Canvas是Web开发中的一个关键技术,...通过学习和实践这些HTML5 Canvas的核心技术,开发者可以构建出交互性强、视觉效果丰富的Web应用程序,无论是数据可视化、游戏开发还是艺术创作,Canvas都能提供强大的支持。
9. **保存和导出**:Canvas上的内容可以导出为图像,或者使用toDataURL方法生成数据URL,方便分享和存储。 10. **实际应用**:书中实例可能涵盖游戏开发、图表绘制、数据可视化、地图应用等多个实际场景,帮助...
这篇博客"canvas画图测试"可能涉及了使用Canvas进行图形绘制的基础知识和实践技巧。Canvas API的使用通常包括以下几个核心知识点: 1. **Canvas元素**:在HTML中,`<canvas>`标签定义了一个可编程的画布,通过...
2. 用户界面(UI):Android游戏通常使用自定义View或SurfaceView来实现游戏画面,结合Canvas进行绘制。UI的设计也包括菜单、暂停、设置等交互元素。 3. 图形渲染:游戏可能使用OpenGL ES进行高性能的2D或3D图形...
在“HTML5 Canvas学习笔记(6)拼图游戏(数字版)”这篇博文中,作者分享了如何利用Canvas构建一个数字拼图游戏。下面我们将详细探讨这个知识点。 1. **HTML5 Canvas基础**: - Canvas是一个基于矢量图形的画布元素...
1. Canvas绘图:H5游戏常用Canvas API进行动态绘图,实现游戏场景的渲染。通过JavaScript操作Canvas的绘图方法,可以绘制角色、障碍物并实现动画效果。 2. Event Handling:JavaScript的事件监听和处理机制在游戏中...
这个技术的引入极大地扩展了网页的交互性和动态性,尤其在创建复杂的动画效果和游戏场景时表现得尤为出色。在这个特定的场景中,我们讨论的是如何使用HTML5 Canvas实现视频网站的文字弹幕动画特效。 首先,我们要...
H5游戏源码的分享,对于学习者来说是一次宝贵的实践机会,可以了解游戏逻辑、动画效果、用户交互等核心元素的实现方法。 【标签】"游戏":游戏是软件的一种类型,它可以提供娱乐、挑战或教育功能。H5游戏作为游戏的...
双十一抢钱游戏中,可能利用了Canvas来绘制游戏场景和动态效果,Web Audio API来处理游戏音效,以及JavaScript来实现游戏逻辑。 2. **CSS3**:CSS3用于定义H5小游戏的视觉样式和布局。它提供了更多的选择器、动画、...
在“H5自写的小游戏源码分享”这...同时,这也是一个很好的学习实践机会,可以提升你的JavaScript编程水平,理解游戏开发中的逻辑思维和问题解决能力。不断练习和学习,你将能够创造出更多有趣、引人入胜的HTML5游戏。
8. **性能优化**:分享关于Canvas性能的技巧,如批处理绘图操作、使用图像数据缓冲区和避免不必要的重绘。 9. **高级应用**:深入探讨更复杂的用例,如粒子系统、游戏开发、图表绘制和数据可视化。 10. **实践案例...
HTML5 Canvas API是Web开发中的一个强大工具,它允许开发者在网页上绘制2D图形,创建动态、交互式的游戏和应用程序。在这个项目中,“games:使用canvas api...在实践中,不断探索和创新,制作出更丰富、更有趣的游戏。
【标题】:“jQuery HTML5微信分享游戏:围住神经猫游戏源码下载” 【描述】:这个资源提供了基于jQuery和HTML5技术开发的微信分享...对于希望从事移动互联网游戏开发的初学者来说,这是一个非常有价值的实践案例。