【实例】html5-canvas中实现背景图片的移动

本例来自于《HTML5 Canvas核心技术 图形、动画与游戏开发》

在线演示 (图有点多,请多刷新几次)

本例还有一点代码不理解,我用注释和问号标注出来了,有大神看到求解答,谢谢

本例子难点主要在通过当前的FPS计算图像下一帧的显示坐标,这也是我不理解的地方

还有就是requestAnimationFrame这个,这个是用来以浏览器最合适的方式循环执行一些代码

[html] view plain copy
 
 print?
  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <meta charset="utf-8">  
  5.         <title>图片运动实例</title>  
  6.         <style type="text/css">  
  7.             body {  
  8.                 background: #DDDDDD;  
  9.             }  
  10.             #canvas {  
  11.                 border: thin solid black;  
  12.             }  
  13.             input {  
  14.                 margin-left: 15px;  
  15.             }  
  16.         </style>  
  17.     </head>  
  18.     <body>  
  19.         <canvas id="canvas" width="1000" height="440">  
  20.             您的浏览器不支持canvas,请更新到最新的浏览器  
  21.         </canvas>  
  22.         <input type="button" name="animateButton" id="animateButton" value="运动" />  
  23.         <hr />  
  24.         <div>  
  25.             <table border="1" cellspacing="" cellpadding="">  
  26.                 <tr>  
  27.                     <td>FPS</td>  
  28.                     <td><span id="FPS"></span></td>  
  29.                 </tr>  
  30.                 <tr>  
  31.                     <td>SKY_VELOCITY/fps</td>  
  32.                     <td><span id="SKY_VELOCITY"></span></td>  
  33.                 </tr>  
  34.                 <tr>  
  35.                     <td>GRASS_VELOCITY/fps</td>  
  36.                     <td><span id="GRASS_VELOCITY"></span></td>  
  37.                 </tr>  
  38.                 <tr>  
  39.                     <td>TREE_VELOCITY/fps</td>  
  40.                     <td><span id="TREE_VELOCITY"></span></td>  
  41.                 </tr>  
  42.                 <tr>  
  43.                     <td>FAST_TREE_VELOCITY/fps</td>  
  44.                     <td><span id="FAST_TREE_VELOCITY"></span></td>  
  45.                 </tr>  
  46.                   
  47.             </table>  
  48.         </div>  
  49.     </body>  
  50.     <script type="text/javascript">  
  51.       
  52.         var canvas = document.getElementById("canvas"),  
  53.             context = canvas.getContext("2d"),  
  54.             animateButton = document.getElementById("animateButton"),  
  55.               
  56.             //创建多个图像对象  
  57.             sky = new Image(),  
  58.             tree = new Image(),  
  59.             nearTree = new Image(),  
  60.             grass = new Image(),  
  61.             grass2 = new Image(),  
  62.             redRect = new Image,  
  63.               
  64.               
  65.             paused = true,  
  66.             lastTime = 0,   
  67.             fps = 0,    //当前的帧速率  
  68.               
  69.             //都是不同图像  
  70.             skyOffset = 0,  
  71.             grassOffset = 0,  
  72.             treeOffset = 0,  
  73.             nearTreeOffset = 0,  
  74.               
  75.             TREE_VELOCITY = 20,  
  76.             FAST_TREE_VELOCITY = 40,  
  77.             SKY_VELOCITY = 8,  
  78.             GRASS_VELOCITY = 75;  
  79.           
  80.         //以下是检测对象  
  81.         var SKY_VELOCITYFps = document.getElementById("SKY_VELOCITY");  
  82.         var GRASS_VELOCITYFps = document.getElementById("GRASS_VELOCITY");  
  83.         var TREE_VELOCITYFps = document.getElementById("TREE_VELOCITY");  
  84.         var FAST_TREE_VELOCITYFps = document.getElementById("FAST_TREE_VELOCITY");  
  85.         var FPS = document.getElementById("FPS");  
  86.               
  87.         //擦除方法  
  88.         function erase() {  
  89.             context.clearRect(0, 0, canvas.width, canvas.height);             
  90.         }  
  91.           
  92.         function draw() {  
  93.             context.save();  
  94.               
  95.             //fps是共用的  
  96.               
  97.             //应该是确定当前图像位置的坐标X  
  98.             //???以下四行还是有点不太理解,只知道这个可以用来循环的显示image对象,至于SKY_VELOCITY/fps是什么还不清楚  
  99.             skyOffset = skyOffset canvas.width ? skyOffset + SKY_VELOCITY/fps : 0;  
  100.             grassOffset = grassOffset canvas.width ? grassOffset + GRASS_VELOCITY/fps : 0;  
  101.             treeOffset = treeOffset canvas.width ? treeOffset + TREE_VELOCITY/fps : 0;  
  102.             nearTreeOffset = nearTree canvas.width ? nearTree + FAST_TREE_VELOCITY/fps : 0;  
  103.               
  104.             //检测数据  
  105.             SKY_VELOCITYFps.innerHTML = SKY_VELOCITY/fps;  
  106.             GRASS_VELOCITYFps.innerHTML = GRASS_VELOCITY/fps;  
  107.             TREE_VELOCITYFps.innerHTML = TREE_VELOCITY/fps;  
  108.             FAST_TREE_VELOCITYFps.innerHTML = FAST_TREE_VELOCITY/fps;  
  109.             FPS.innerHTML = fps;  
  110.               
  111.             //像下面几行这样写的后果:canvas运动到后面的时候就可能没有图像对象了  
  112. //          skyOffset += SKY_VELOCITY/fps;  
  113. //          grassOffset += GRASS_VELOCITY/fps;  
  114. //          treeOffset += TREE_VELOCITY/fps;  
  115. //          nearTreeOffset += FAST_TREE_VELOCITY/fps;  
  116.               
  117.             //开始绘制天空  
  118.             context.save();  
  119.             //改变坐标原点  
  120.             context.translate(-skyOffset, 0);  
  121.             //绘制一个天空  
  122.             context.drawImage(sky, 0, 0);  
  123.             //在即将天空结尾的时候在绘制一个天空用来衔接  
  124.             context.drawImage(sky, sky.width-2, 0);  
  125.             //将改变的坐标原点改回来  
  126.             context.restore();  
  127.               
  128.             //开始绘制远处的树  
  129.             //此处绘制的位置有的地方出现在canvas.width之外  
  130.             context.save();  
  131.             //改变坐标原点  
  132.             context.translate(-treeOffset, 0);  
  133.             //以改变原点后的坐标上绘制好多个树  
  134.             context.drawImage(tree, 100, 240);  
  135.             context.drawImage(tree, 1100, 240);  
  136.             context.drawImage(tree, 400, 240);  
  137.             context.drawImage(tree, 1400, 240);  
  138.             context.drawImage(tree, 700, 240);  
  139.             context.drawImage(tree, 1700, 240);  
  140.             //恢复坐标原点  
  141.             context.restore();  
  142.               
  143.             //绘制近处的树木,他的运行速度更加的块  
  144.             context.save();  
  145.             context.translate(-nearTreeOffset, 0);  
  146.             context.drawImage(nearTree, 250, 220);  
  147.             context.drawImage(nearTree, 1250, 220);  
  148.             context.drawImage(nearTree, 800, 220);  
  149.             context.drawImage(nearTree, 1800, 220);  
  150.             context.restore();  
  151.               
  152.               
  153.               
  154.             //绘制绿地  
  155.             context.save();  
  156.             context.translate(-grassOffset, 0);  
  157.             //在canvas底部绘制草地image对象  
  158.             context.drawImage(grass, 0, canvas.height-grass.height);  
  159.             context.drawImage(grass, grass.width, canvas.height-grass.height);  
  160.             context.drawImage(grass2, 0, canvas.height-grass2.height);  
  161.             context.drawImage(grass2, grass2.width, canvas.height-grass2.height);  
  162.             context.restore();  
  163.               
  164.         }  
  165.           
  166.         //计算当前的FPS  
  167.         function calculateFps(now) {  
  168.             //1000毫秒除以距离上一次计算FPS的时间意思是,或者距离上一次绘制图像  
  169.             //这段时间里面执行了多少次  
  170.             //除以1000是因为now和lastTime都是以毫秒为单位的  
  171.             //反正fps就是一秒内能够执行绘制多少次嘛~所以的  
  172.             var fps = 1000 / (now - lastTime);  
  173.             lastTime = now;  
  174.             return fps;  
  175.         }  
  176.           
  177.         function animate(now) {  
  178.             //如果当前时间还没有定义  
  179.             if(now === undefined) {  
  180.                 //就把当前时间赋值给now  
  181.                 now = +new Date;  
  182.             }  
  183.             fps = calculateFps(now);  
  184.               
  185.             //只要不是暂停状态就执行  
  186.             if(!paused) {  
  187.                 //擦除canvas  
  188.                 //原例子中是用兼容的手法实现requestAnimationFrame,所以需要erase  
  189. //              erase();  
  190.                 //马上绘制新的  
  191.                 draw();  
  192.             }  
  193.             //以最适合的速度执行animate中的内容,这个比较适合动画的处理,类似于setTimeout  
  194.             requestAnimationFrame(animate);  
  195.         }  
  196.           
  197.         animateButton.onclick = function(e) {  
  198.             paused = paused ? false : true;  
  199.             if(paused) {  
  200.                 animateButton.value = "运动";  
  201.             } else {  
  202.                 animateButton.value = "暂停";  
  203.             }  
  204.         };  
  205.           
  206. //      canvas.width = canvas.width;  
  207. //      canvas.height = canvas.height;  
  208.         sky.src = "sky.png";  
  209.         tree.src = "smalltree.png";  
  210.         nearTree.src = "tree-twotrunks.png";  
  211.         grass.src = "grass.png";  
  212.         grass2.src = "grass2.png";  
  213.           
  214.         sky.onload = function(e) {  
  215.             draw();  
  216.         };  
  217.           
  218. //      requestAnimationFrame(animate);  
  219.         //启动  
  220.         animate();  
  221.     </script>  
  222. </html>  
原文地址:https://www.cnblogs.com/wangluochong/p/5814334.html