使用JavaScript和Canvas开发游戏之使用Canvas

3、通过Canvas元素实现高级图像操作

我们提供的服务有:成都网站建设、网站建设、微信公众号开发、网站优化、网站认证、迎江ssl等。为近千家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的迎江网站制作公司

http://www.brighthub.com/internet/web-development/articles/39509.aspx

这篇文章将带领大家学习使用JavaScript和Canvas元素操作图像了几种不同的方式,这些方式在Canvas元素出现之前是不可能的事儿。

上一篇文章演示了如何利用Canvas实现一个基本的图像动画。那个例子很简单,同样的效果通过修改IMG或DIV等标准HTML元素的一些属性,照样也可以轻易实现。下面我们就来演示一下画布元素的高级应用,展示一下它的真正威力。

首先,还是准备一个HTML页面。

 
 
 
  1.  
  2.  
  3.     
  4.        JavaScript Platformer 2
  5.        
  6.        
  7.           body { font-family: Arial,Helvetica,sans-serif;}
  8.        
  9.     
  10.    
  11.       

  12.          
  13.             Game Development with Javascript and the canvas element
  14.          
  15.       

  16.       
  17.          

    Your browser does not support the canvas element.

  18.       
  19.       
  20.       Change Alpha
  21.       Shear
  22.       Scale
  23.       Rotate
  24.    

与上个一例子的HTML页面相比,唯一的区别就是添加了一些按钮。单击这些按钮,就会设置currentFunction变量(稍后介绍)的值,用以改变在渲染循环中运行的函数。

以下是 jsplatformer2.js 的代码。

 
 
 
  1. // 每秒多少帧
  2. const FPS = 30;
  3. const SECONDSBETWEENFRAMES = 1 / FPS;
  4. const HALFIMAGEDIMENSION = 75;
  5. const HALFCANVASWIDTH = 300;
  6. const HALFCANVASHEIGHT = 200;
  7. var image = new Image();
  8. image.src = "jsplatformer2-smiley.jpg"; //还是第一个例子中的图像
  9. var canvas = null;
  10. var context2D = null;
  11. var currentFunction = null;
  12. var currentTime = 0;
  13. var sineWave = 0;
  14. window.onload = init;
  15. function init()
  16. {
  17.    canvas = document.getElementById('canvas');
  18.    context2D = canvas.getContext('2d');
  19.    setInterval(draw, SECONDSBETWEENFRAMES * 1000);
  20.    currentFunction = scale;
  21. }
  22. function draw()
  23. {
  24.     currentTime += SECONDSBETWEENFRAMES;
  25.     sineWave = (Math.sin(currentTime) + 1) / 2;
  26.     context2D.clearRect(0, 0, canvas.width, canvas.height);
  27.     context2D.save();
  28.     context2D.translate(HALFCANVASWIDTH - HALFIMAGEDIMENSION, HALFCANVASHEIGHT - HALFIMAGEDIMENSION);
  29.     currentFunction();
  30.     context2D.drawImage(image, 0, 0);
  31.     context2D.restore();
  32. }
  33. function alpha()
  34. {
  35.     context2D.globalAlpha = sineWave;
  36. }
  37. function shear()
  38. {
  39.     context2D.transform(1, 0, (sineWave - 0.5), 1, 0, 0);
  40. }
  41. function scale()
  42. {
  43.     context2D.translate(HALFIMAGEDIMENSION * (1 - sineWave), HALFIMAGEDIMENSION * (1 - sineWave));
  44.     context2D.scale(sineWave, sineWave);
  45. }
  46. function rotate()
  47. {
  48.     context2D.translate(HALFIMAGEDIMENSION, HALFIMAGEDIMENSION);
  49.     context2D.rotate(sineWave * Math.PI * 2);
  50.     context2D.translate(-HALFIMAGEDIMENSION, -HALFIMAGEDIMENSION);
  51. }

跟前面一样,这个JavaScript文件先定义了一些全局变量。

◆ FPS:每秒多少帧

◆ SECONDSBETWEENFRAMES:两帧之间间隔的秒数(FPS的倒数)

◆ HALFIMAGEDIMENSION:要绘制图像的宽度/高度的一半,用于把图像定位到画布的中心点

◆ HALFCANVASWIDTH:画布宽度的一半,用于配合HALFIMAGEDIMENSION使用,以便在画布上居中图像

◆ HALFCANVASHEIGHT:画布高度的一半,用于配合HALFIMAGEDIMENSION使用,以便在画布上居中图像

◆ currentFunction:渲染循环(参见上一篇文章)中运行的函数

◆ currentTime:应用已经运行了多少秒

◆ sineWave:0到1之间的一个值,用于控制图像的运动

◆ image:要在画布上绘制的图像

◆ canvas:画布元素的引用

◆ context2D:画布元素的2D上下文的引用

然后,跟前面一样,要设置在window的onload事件发生时立即调用init函数(关于init函数的介绍,请参见上一篇文章)。

draw函数

下面来看一看draw函数:

 
 
 
  1. function draw()
  2. {
  3.     currentTime += SECONDSBETWEENFRAMES;
  4.     sineWave = (Math.sin(currentTime) + 1) / 2;
  5.     context2D.clearRect(0, 0, canvas.width, canvas.height);
  6.     context2D.save();
  7.     context2D.translate(HALFCANVASWIDTH - HALFIMAGEDIMENSION, HALFCANVASHEIGHT - HALFIMAGEDIMENSION);
  8.     currentFunction();
  9.     context2D.drawImage(image, 0, 0);
  10.     context2D.restore();
  11. }

这个例子要演示4种效果:修改alpha值(透明度),以及缩放、旋转和切变图像。为了展示这些效果,需要基于某一范围内的值来应用变化。变量sineWave就用来定义这个范围值的基准。

标准的正弦函数能够在-1到1之间产生非常完美的波形图。首先,我们通过递增currentTime变量来反映动画已经运行了多长时间,然后再利用这个值在正弦曲线上找到一个点。给正弦函数返回的值(从-1到1)先加1再除以2,就可以把它们转换成0到1这个范围内的值。

 
 
 
  1. currentTime += SECONDSBETWEENFRAMES;
  2. sineWave = (Math.sin(currentTime) + 1) / 2;

然后,调用clearRect方法清空画布,以便为后面的绘图准备一个干净的版面。

 
 
 
  1. context2D.clearRect(0, 0, canvas.width, canvas.height);

应用到画布上面的效果是可以累积的,因而就可以利用几个简单的函数来“组合”出效果来。例如,在向屏幕上绘制之前,可能会有一艘飞船需要旋转、变换和缩放。因为所有效果都对画布起作用,所以这些效果会应用到将被绘制在屏幕上的所有对象,而不仅仅是某一幅图像或某一个形状(比如一艘飞船)。

其中,save和restore函数为应用这些累积的效果提供了一种简单的机制,可以将应用了这些效果的图像或图形绘制到画布上,然后“撤销”这些改变。后台的操作是什么呢?save函数把当前的绘制状态推进栈里,而restore函数则把最后一个状态弹出栈。还拿前面提到的飞船为例,需要执行下列操作:

◆ 调用save函数(保存当前的绘制状态)

◆ 旋转、变换和缩放上下文

◆ 绘制飞船

调用restore函数,移除自上一次调用save方法以来所添加的任何效果,也就是撤销之前的变化

在这里,我们就是要组合起来使用这两个方法。首先,在把任何效果应用到画布之前,先保存绘制状态。

 
 
 
  1. context2D.save();

保存了绘制状态之后,就该应用目标效果了。为此,首先调用translate函数,从而将随后要绘制的图像在画布上居中。

 
 
 
  1. context2D.translate(HALFCANVASWIDTH - HALFIMAGEDIMENSION, HALFCANVASHEIGHT - HALFIMAGEDIMENSION);

接下来,调用由变量currentFunction引用的函数。正是这些被引用的函数,是让图像发生alpha(透明度)变化以及缩放、旋转和切变的关键。这些函数我们稍后再介绍。

 
 
 
  1. currentFunction();

为图像应用完效果之后,就可以把它绘制到画布上面了。所以,接下来就是调用drawImage来绘图。

 
 
 
  1. context2D.drawImage(image, 0, 0);

最后,再调用restore函数,把自调用save函数以来应用的所有效果从画布上移除。

 
 
 
  1. context2D.restore();

alpha函数

 
 
 
  1. function alpha()
  2. {
  3.     context2D.globalAlpha = sineWave;
  4. }

通过修改上下文对象的globalAlpha属性,所有后续绘制操作的透明度都会被修改。将globalAlpha设置为0,意味着被绘制的任何对象都将完全透明,而将这个属性设置为1,则意味着任何绘制操作都会保持原有的透明度级别。在此,我们通过修改这个globalAlpha属性,可以实现笑脸的淡入和淡出效果。

shear函数

 
 
 
  1. function shear()
  2. {
  3.     context2D.transform(1, 0, (sineWave - 0.5), 1, 0, 0);
  4. }

切变操作是通过transform函数向画布应用一个矩阵来实现的。变换矩阵本身就是一个值得研究的主题,但对我们来说,如果不想理解背后的数学原理,可以在网上找到很多标准的2D变换矩阵(http://en.wikipedia.org/wiki/Transformation_matrix#Examples_in_2D_graphics),直接使用transform函数来应用它们即可。所谓切变,其实就是把图像的顶部或底部推到一边。

scale函数

 
 
 
  1. function scale()
  2.  {
  3.      context2D.translate(HALFIMAGEDIMENSION * (1 - sineWave), HALFIMAGEDIMENSION * (1 - sineWave));
  4. 56
  5.     context2D.scale(sineWave, sineWave);
  6.  }

顾名思义,scale(缩放)函数修改的是图像的大小。但在此之前,我们还调用了一次transalte函数。这是为了让缩放后的图像在画布上居中。如果你把这行代码注释掉,就会发现图像会从左上角向右下角膨胀。调用translate函数就是为抵消其圆心的位移,让图像始终居中。

rotate函数

 
 
 
  1. function rotate()
  2. {
  3.     context2D.translate(HALFIMAGEDIMENSION, HALFIMAGEDIMENSION);
  4.     context2D.rotate(sineWave * Math.PI * 2);
  5.     context2D.translate(-HALFIMAGEDIMENSION, -HALFIMAGEDIMENSION);
  6. }

与scale函数类似,rotate(旋转)函数的作用也正如其名:旋转图像。与scale函数同样类似的是,这里也额外调用了translate函数以确保图像围绕中心点而不是左上角旋转。建议大家把对translate函数的调用注释掉,自己看一看结果有什么不同。

刚刚我们看到了使用画布元素实现的4种也还算简单的效果,这些效果使用标准的HTML元素几乎是不可能做到的。其中,有的效果可以使用scale和rotate等内置函数来实现,而使用transform函数则可以完成大量的图像操作(切变只是其中之一)。

新闻标题:使用JavaScript和Canvas开发游戏之使用Canvas
网站路径:http://www.shufengxianlan.com/qtweb/news1/520301.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联