Canvas 飞机大战游戏1:loading页面
原始页面是网页端demo,我从0开始学习,并调整为移动端H5页面。
另外对原文做了部分调整:修改了index页面循环不停止,部分代码冗余等问题,并增加注释。
本文为游戏的loading页面。初始化canvas,加载音乐,背景图片等游戏资源,显示开始游戏按钮。
效果图:
两点疑问:
1、RAF为什么不会报栈溢出
RAF(function() { _this.loop();//如果直接用settimeout(this.loop(),1000/60),会报 Maximum call stack size exceeded栈溢出错误 });
11.30号解答:setTimeout导致了方法的重复执行。
事例中用callback方法规避了这个问题,也可用setInterval实现。stage的loop方法完全可以省略,改写成:
var stage = { start: function() { var _this=this; this.init(); setInterval(function(){ _this.update(); },1000/60); }, …… }
2、如果直接调用update方法,使用setInterval调用this.loading.loop为什么会报错。
update: function() { setInterval(this.loading.loop(),1000); if(this.loading.getComplete()) { ctx.clearRect(0, 0, canvas.width, canvas.height); } }
11.30号解答:是this指向问题,如果直接用this。此时this指向的是window,而不是stage对象。见:https://www.cnblogs.com/liangtao999/p/11687073.html
var _this=this; setInterval(function(){ _this.loading.loop(); },1000/60);
HTML部分
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no"> <title>Canvas飞机大战</title> <link rel="stylesheet" href="css/index.css" /> </head> <body> <div class="game"> <div id="gameStart" style="display: none;"> <span id="gs-start">游戏开始</span><br><br> <span>游戏说明:方向键移动,按“Z”“C”键旋转飞机</span> </div> <div class="movebg"></div> <canvas id="canvas" class="showBg">您的浏览器不支持canvas,请更新浏览器</canvas> </div> </body> <script type="text/javascript" src="js/data.js"></script> <script type="text/javascript" src="js/loading.js"></script> <script> //设置canvas的宽高 var canvas = document.getElementById("canvas"); canvas.width = window.screen.width; canvas.height = screen.height; var ctx = canvas.getContext("2d"); //定义 var gS = document.getElementById("gameStart"), gss = document.getElementById("gs-start"); //定时刷新 window.RAF = (function() { return function(callback) { window.setTimeout(callback, 1000/60); }; })(); var stage = { start: function() { this.init(); this.loop(); }, init: function() { var _this = this; this.loading = new Loading(datas, canvas, function() { //datas在data.js中定义 gS.style.display = "block"; canvas.className = "showBg" document.getElementById("bgm").play(); gss.addEventListener("click", function() { gS.style.display = "none"; // _this.addElement(); }, false) }); }, loop: function() {//递归函数,调用loading页面loop方法,加载loading页面 var _this = this; var isloop=this.update(); if(isloop){ RAF(function() { _this.loop(); }); } }, update: function() { var stage = this; var boomnum = 0, misslenum = 0; this.loading.loop(); if(this.loading.getComplete()) { ctx.clearRect(0, 0, canvas.width, canvas.height);//放在init的回调函数里面也是一样 return false; } return true; }, }; stage.start(); </script> </html>
loading.js
var Loading = function() { var loadingComplete = false; //是否加载完成状态 var dateCount = null; function init(datas, canvas, callback) { this.canvas = canvas; this.x = this.canvas.width / 2; this.y = this.canvas.height / 2; this.r = 80; this.elew = 10; this.angle = 0; //旋转角度 this.percent = 0; //图片音乐资源加载的百分比 this.writePercent = 0; //canvas中显示的加载百分比 this.callback = callback; this.loadImg(datas); //加载图片及音乐 } init.prototype = { loadImg: function(datas) { var _this = this; var dataIndex = 0; //资源加载计数器 li(); function li() { if(datas[dataIndex].indexOf("mp3") >= 0) { //加载音乐 var audio = document.createElement("audio"); audio.preload = "auto"; audio.src = datas[dataIndex]; audio.addEventListener("canplaythrough", loadMp3); //当浏览器预计能够在不停下来进行缓冲的情况下持续播放指定的音频/视频时,会发生 canplaythrough 事件 if(datas[dataIndex].indexOf("bgm") >= 0) { //设置背景音乐 audio.id = "bgm"; audio.loop = true; audio.volume = 0.8; } function loadMp3() { //进度 audio.removeEventListener("canplaythrough", loadMp3); dataIndex++; if(dataIndex === datas.length) { _this.percent = 100; } else { _this.percent = parseInt(dataIndex / datas.length * 100); li(); //等同于li.call(_this); } document.body.appendChild(audio); } } else { preLoadImg(datas[dataIndex], function() { //进度 dataIndex++; if(dataIndex === datas.length) { _this.percent = 100; } else { _this.percent = parseInt(dataIndex / datas.length * 100); li(); } }) } } }, paint: function() { var ctx = this.canvas.getContext("2d"); ctx.fillStyle = "rgba(0,0,0,0.01)" //画了个正方形:黑色 透明度0.01 ctx.fillRect(this.x - this.r - this.elew - 5, this.y - this.r - this.elew - 5, (this.r + this.elew + 5) * 2, (this.r + this.elew + 5) * 2) ctx.fillStyle = "#FFF"; ctx.save(); ctx.translate(this.x, this.y); //移到canvas的中心点 ctx.rotate(this.angle); //旋转角度 angle ctx.fillRect(-this.elew / 2, -this.r + this.elew / 2, this.elew, this.elew); //内圈起始点 ctx.fillRect(-5,-75,10,10) ctx.fillRect(-this.elew / 2, this.r - this.elew / 2, this.elew, this.elew);//外圈起始点 ctx.fillRect(-5,75,10,10) ctx.restore(); ctx.clearRect(this.x - 48, this.y - 12, 96, 24); //画布中间清除出一块区域放文字 ctx.font = "18px 微软雅黑"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText("加载中" + this.writePercent + "%", this.x, this.y); //加载文字 this.angle = this.angle > 2 * Math.PI ? 0 : this.angle + 0.05; //弧度+0.05,旋转180度为1*math.PI,1000/60毫秒旋转0.05度。 }, update: function() { var _this = this; this.writePercent++; if(this.writePercent === 100) { setTimeout(function() { _this.callback();//整个loading的回调,告知html页面 loadingComplete = true; }, 500); } }, getComplete: function() { return loadingComplete; }, loop: function() { if(this.percent !== this.writePercent) { this.update(); } if(!loadingComplete) { //没有完成前一直画loading this.paint(); } }, } return init; }(); function preLoadImg(src, callback) { //加载图片 var img = new Image(); img.src = src; img.onload = function() { callback(); } }
data.js
var datas = [ "image/explosion.png", "image/plasma.png", "image/ship.png", "image/bg_1_1.jpg", "mp3/bgm.mp3", "mp3/boom.mp3", "mp3/shot.mp3" ]
index.css
/*alltag*/ * { padding: 0; margin: 0; overflow: hidden; } .game { width: 100; margin: auto; height: 100%; position: relative; } /*canvas*/ #cas { display: block; border: 1px solid; margin: auto; background-color: #000; } .showBg { background-color: transparent !important; } /*移动背景*/ .movebg { width: 100%; height: 200%; background: url(../image/bg_1_1.jpg); background-size: 100% 50%; position: absolute; top: 0px; transform: translateY(-50%); animation: bganimate 10s infinite linear; z-index: -1; } @keyframes bganimate { from { transform: translateY(-50%); } to { transform: translateY(0); } } /*开始游戏按钮*/ #gameStart { position: absolute; width: 100%; height: 200px; text-align: center; color: #FFF; font: 20px "微软雅黑"; top: 310px; display: none; } #gameStart #gs-start { display: inline-block; width: 180px; height: 60px; background-color: #CCC; color: #000; cursor: pointer; line-height: 60px; border-radius: 10px; border: 5px solid #FFF; } #gameStart #gs-start:hover { color: #f00; }
原文地址:
https://www.cnblogs.com/axes/p/3582843.html
setInterval(function(){stage.loading.loop();},1000/60);