在开发在线游戏时,绘制动画是非常重要的。本文介绍一个使用Canvas API实现的动画实例——游戏人物的跑步动画。
01、动画的概念及原理
1、动画
动画是通过一幅幅静止的、内容不同的画面(即帧)快速播放来呈现的,使人们在视觉上产生动的感觉。这是利用了人类眼睛的视觉暂留原理。利用人的这种生理特性可制作出具有高度想象力和表现力的动画影片。
2. 原理
人们在看画面时,画面会在大脑视觉神经中停留大约1/24秒,如果每秒更替24个画面或更多,那么前一个画面还没在人脑中消失之前,下一个画面进入人脑,人们就会觉得画面动起来了,它的基本原理与电影、电视一样,都是视觉原理。
在计算机上要实现动画效果,除了绘图外,还需要解决下面两个问题。
(1) 定期绘图,也就是每隔一段时间就调用绘图函数进行绘图。动画是通过多次绘图实现的,一次绘图只能实现静态图像。
可以使用setInterval()函数设置一个定时器,语法如下:
setInterval(函数名,时间间隔)
时间间隔的单位是毫秒(ms),每经过指定的时间间隔系统都会自动调用指定的函数完成绘画。
(2) 清除先前绘制的所有图形。物体已经移动开来,可原来的位置上还保留先前绘制的图形,这样当然不行。解决这个问题最简单的方法是使用clearRect(x, y, width, height)方法清除画布中指定区域的内容。
图1是一个方向(一般都是4个方向)的跑步动作序列图。假如想获取一个姿态的位图,可利用Canvas的上下文2D对象的drawImage(image, sourceX, sourceY, sourceWidth,sourceHeight,destX,destY,destWidth,destHeight)方法将源位图上某个区域(sourceX,sourceY,sourceWidth,sourceHeight)复制到目标区域的(destX,destY)坐标处,显示大小为(destWidth,destHeight)。
■ 图1 一个方向的跑步动作序列
【例1】实现从跑步动作序列Snap1.jpg文件中截取的第3个动作(帧)。
分析:在Snap1.jpg文件中,每个人物动作的大小为60×80px,所以截取源位图的sourceX=120,sourceY=0,sourceWidth=60,sourceHeight=80就是第3个动作(帧)。
<canvas id="myCanvas" height=250 width=250>您的浏览器不支持 canvas。</canvas>
<script type="text/javascript">
function draw()
{
var canvas=document.getElementById("myCanvas"); // 获取网页中的canvas对象
var ctx = canvas.getContext("2d"); //获取canvas对象的上下文
var imageObj = new Image(); // 创建图像对象
imageObj.src = "Snap1.jpg";
imageObj.onload = function(){
//从原图(120, 0)位置开始截取中间一块宽60*高80的区域,原大小显示在屏幕(0,0)处
ctx.drawImage(imageObj, 120, 0, 60, 80, 0, 0, 60, 80);
};
}
window.addEventListener("load", draw, true);
</script>
例1的运行结果如图2所示,在页面上仅仅显示第3个动作。
■ 图2 静态显示第3个动作
02、游戏人物的跑步动画
【例2】实现游戏人物的跑步动画。
首先定义一个Canvas元素,画布的长度和宽度都是300px,代码如下:
<!DOCTYPE html>
<html>
<head>
<title>HTML5 Canvas实现游戏人物的跑步动画</title>
</head>
<body>
<canvas id="myCanvas" width="300" height="300"></canvas>
</body>
</html>
在JavaScript代码中定义一个Image对象,用于显示Snap1.jpg。然后定义一个init()函数,初始化Image对象,并设置定时器,代码如下:
<script type="text/javascript">
var imageObj = new Image(); // 创建图像对象
var x =300;
var n =0; // 计数器
function init(){
imageObj.src = 'Snap1.jpg';
imageObj.onload = function(){
setInterval(draw,100);// 定时器,每0.1秒执行一次draw()函数
};
// 此处省略draw()函数的代码
window.addEventListener("load", init, true);
</script>
使用了定时器,每隔100毫秒就会在Snap1.jpg图片截取一张60×80px大小的小图并绘制出来,且每次向左移15px,直到最左端时重新从右侧开始,不停循环,就可见游戏人物在屏幕上不停地奔跑。
下面分析draw()函数的实现。例5-14中仅仅显示人物的第三个动作,而为了实现动画,需要clearRect(x,y,width,height)不断清除先前绘制的动作图形,再绘制后续的动作。所以需要一个计数器n,记录当前绘制到第几动作(帧)了。
function draw()
{
var canvas=document.getElementById("myCanvas"); // 获取网页中的canvas对象
var ctx = canvas.getContext("2d"); //获取canvas对象的上下文
ctx.clearRect(0,0,300,300); // 清除canvas画布
//从原图(60*n)位置开始截取中间一块宽60*高80的区域,显示在屏幕(x,0)处
ctx.drawImage(imageObj, 60*n, 0, 60, 80, x, 0, 60, 80);
if(n>=8){
n=0;
}else{
n++;
}
if(x>=0){
x=x-30; //前移30像素
}else{
x=300; //回到右侧
}
}
例2的运行结果是一个游戏人物不停且重复地从右侧跑到左侧的动画。
03、雪花飘落动画
在HTML5中制作雪花飘落动画,需要使用Canvas画圆arc(x,y,r,start,stop)以构成圆形雪花;网页加载时,需要生成一定数量(如200个)的不同半径及位置的雪花,故半径、坐标为随机数;雪花在飘落过程中,其半径不变,坐标在一定幅度内变化。
制作雪花飘落动画,首先产生一个画布Canvas。
<script type="text/javascript">
var canvas=document.getElementById("myCanvas")
var context = canvas.getContext("2d"); //2d即指二维平面
var w =window.innerWidth
var h =window.innerHeight
canvas.width = w;
canvas.height =h;
然后再生成200个雪花的对象组。当生成雪花时,每个雪花半径、位置都不同。如果把每个雪花当成一个对象,那么这个对象的属性就包含半径、坐标(X、Y)。一个雪花对象可以写成var snowOject={x: 1,y: 10,r: 5},代表一个坐标为(1,10)、半径为5的圆形雪花。
注意/
本示例中由于半径和坐标都为随机数,故使用Math.random()方法分别为200个雪花生成半径、坐标(X、Y);动画有200个雪花,所以为了方便后面操作,就用一个数组保存这200个雪花对象。
var count =200 //雪花的个数
var snows=[] //雪花对象数组
for (var i=0 ; i< count;i++){
snows.push({
x:Math.random()*w, //Math.random()用于生成0~1的随机数
y:Math.random()*h,
r:Math.random()*5,
})
}
在绘制时设置雪花的样式。
function draw(){
context.clearRect(0,0,w,h)
context.beginPath()
for(var i=0; i<count;i++){
var snow = snows[i];
context.fillStyle ="rgb(255,255,255)" //设置雪花的样式
context.shadowBlur=10;
context.shadowColor="rgb(255,255,255)";
//moveTo 移动到指定的坐标
context.moveTo(snow.x,snow.y);
// 使用canvas arc()创建一个圆形
//x,y,r:圆的中心的x坐标和y坐标,r为半径
//0,Math.PI * 2起始弧度和结束弧度
context.arc(snow.x,snow.y,snow.r,0,Math.PI * 2);
}
context.fill(); //画布填充
move();
}
move()函数让雪花它们飘动起来,就是雪花不停地移动位置。超出页面则重新设置位置和雪花大小。
function move(){
for (var i=0;i<count;i++){
var snow =snows[i];
snow.y +=(7-snow.r)/10 //从上往下飘落
snow.x+=((5-snow.r)/10)//从左到右飘落
if(snow.y>h){
snows[i]={
x:Math.random()*w,
y:Math.random()*h,
r:Math.random()*5,
}
}
}
}
最后设置刷新频率。
setInterval(draw,10); //每10毫秒刷新一次
</script>
页面中定义一个Canvas元素,画布的长度和宽度都是300px。
<body>
<canvas id="myCanvas" height=500 width=500 class="my">您的浏览器不支持 canvas。</canvas>
</body>
例子的运行结果如图3所示。
■ 图3 雪花飘落