小游戏资源加载器
前面两章节,我们已经把背景动效和飞机的动效绘制出来了,现在,我们要把它们合并到一起了
不知道你有没有发现,背景图片和飞机图片都需要用到 onload
函数回调,所以我们要把公共部分拆出来然后分别判断是否加载完毕,对吧
Image
对象有一个 complete
属性用于判断图片是否加载完成
game.js
var c = wx.createCanvas(); var ctx = c.getContext('2d'); var img = wx.createImage(); var plane = wx.createImage(); var bgm = wx.createInnerAudioContext(); bgm.loop = true; var bgCanvas = null; var offset = 0; var w = 0; var h = 0; var screenWidth = c.width; var screenHeight = c.height; // 上一次飞机的位置 var lasted = { x: 0, y: 0 }; // 触摸区域是否在飞机内部 var in_plane = false; function init_bg() { bgCanvas = wx.createCanvas(); bgCanvas.width = screenWidth; bgCanvas.height = screenHeight + h; var bgctx = bgCanvas.getContext('2d'); var y = 0; var x = 0; // 底部多绘制一张图片 while (y < screenHeight + h) { x = 0; while (x < screenWidth) { bgctx.drawImage(img, x, y, w, h); x += w; } y += h; } } function reset() { ctx.save(); ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, c.width, c.height); ctx.restore(); } function draw_copy() { ctx.save(); ctx.textAlign = "center" // 居中对齐 ctx.textBaseline = "middle" //垂直居中绘制 ctx.fillStyle = "#aaa"; ctx.font = "16px Arial" // 字体大小 16 像素 ctx.fillText("简单教程,简单编程", c.width / 2, (c.height - 36)) ctx.fillText(" © 2015-2018 www.twle.cn", c.width / 2, (c.height - 18)); ctx.restore(); } function animate_it() { reset(ctx); ctx.drawImage(bgCanvas, 0, offset, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight); ctx.drawImage(plane, 0, 0, 128, 128, lasted.x - 64, lasted.y - 64, 128, 128); draw_copy(); offset++; if (offset % h == 0) { offset = 0; } requestAnimationFrame(animate_it); } wx.onShow(function () { bgm.play() }) wx.onAudioInterruptionBegin(function () { // 暂停音乐 bgm.stop(); // 中断动画 //cancelAnimationFrame(animate_it); }) wx.onAudioInterruptionEnd(function () { bgm.play() // 恢复动画 cancelAnimationFrame(animate_it); }) wx.onTouchStart(function (e) { var x = e.touches[0].clientX; var y = e.touches[0].clientY; if (plane_hit(x, y)) { in_plane = true; } }); wx.onTouchEnd(function (e) { if (in_plane) { lasted.x = e.touches[0].clientX; lasted.y = e.touches[0].clientY; in_plane = false; } }); // 触摸移动事件 wx.onTouchMove(function (e) { if (in_plane) { lasted.x = e.touches[0].clientX; lasted.y = e.touches[0].clientY; } }) function plane_hit(x, y) { return x > (lasted.x - 64) && x < (lasted.x + 64) && y > (lasted.y - 64) && y < (lasted.y + 64); } function load() { if (img.complete && plane.complete) { w = screenWidth > img.width ? img.width : screenWidth; h = img.height * (w / img.width); lasted.x = (screenWidth - 128) / 2; lasted.y = screenHeight - 128; bgm.play() init_bg(); ctx.drawImage(plane, 0, 0, 128, 128, lasted.x, lasted.y, 128, 128); draw_copy(); requestAnimationFrame(animate_it); } } reset(); img.onload = function () { load(); } plane.onload = function () { load(); } bgm.src = 'audio/bgm.mp3' img.src = "images/bg.jpg"; plane.src = "images/plane.png"
运行演示如下
资源加载器
但这样不是办法,如果还有更多的图片,还有其它音频资源,等等...每次都写一个 onload
那是会死人的
所以,索性,我们就来做一个资源加载器
var Resource = { _res: [], // [][] 资源对象数组, 0 表示资源 1 url 2 类型 3 是否加载完成 _load: function (idx, ops) { var res = this._res[idx]; if (!res[3]) { if (res[2] == "audio") this._load_audio(res[1], idx, ops) if (res[2] == "image") this._load_image(res[1], idx, ops); } }, _load_image: function (src, i, ops) { var img = wx.createImage(); var that = this; that._res[i][0] = img; img.onload = function () { that._res[i][3] = true; } img.src = src; }, _load_audio: function (src, i, ops) { var audio = wx.createInnerAudioContext(); if (ops != null) { for (var k in ops) { audio[k] = ops[k]; } } var that = this; that._res[i][0] = audio; audio.onCanplay(function () { that._res[i][3] = true; }); audio.src = src; }, loaded: function (callback) { for (var i = 0; i < this._res.length; i++) { if (!this._res[i][3]) { var that = this; setTimeout(function () { that.loaded(callback); }, 200); return; } } callback(); }, add: function (src, type, id, ops) { this._res.push([null, src, type, false, id]); this._load(this._res.length-1, ops); }, item: function (src) { for (var i = 0; i < this._res.length; i++) { if (this._res[i][1] == src) { return this._res[i][0]; } } return null; } }
范例演示如下
game.js
var Resource = { _res: [], // [][] 资源对象数组, 0 表示资源 1 url 2 类型 3 是否加载完成 _load: function (idx, ops) { var res = this._res[idx]; if (!res[3]) { if (res[2] == "audio") this._load_audio(res[1], idx, ops) if (res[2] == "image") this._load_image(res[1], idx, ops); } }, _load_image: function (src, i, ops) { var img = wx.createImage(); var that = this; that._res[i][0] = img; img.onload = function () { that._res[i][3] = true; } img.src = src; }, _load_audio: function (src, i, ops) { var audio = wx.createInnerAudioContext(); if (ops != null) { for (var k in ops) { audio[k] = ops[k]; } } var that = this; that._res[i][0] = audio; audio.onCanplay(function () { that._res[i][3] = true; }); audio.src = src; }, loaded: function (callback) { for (var i = 0; i < this._res.length; i++) { if (!this._res[i][3]) { var that = this; setTimeout(function () { that.loaded(callback); }, 200); return; } } callback(); }, add: function (src, type, id, ops) { this._res.push([null, src, type, false, id]); this._load(this._res.length-1, ops); }, item: function (src) { for (var i = 0; i < this._res.length; i++) { if (this._res[i][1] == src) { return this._res[i][0]; } } return null; } } var c = wx.createCanvas(); var ctx = c.getContext('2d'); Resource.add('images/bg.jpg','image'); Resource.add('audio/bgm.mp3', 'audio'); Resource.loaded(function () { var bgm = Resource.item('audio/bgm.mp3'); bgm.play(); var bg = Resource.item('images/bg.jpg'); console.log(bg) });
哇,能听到声音了,也能看到图片了
使用资源加载器
废话不多说,直接组装就可以了
game.js
var Resource = { _res: [], // [][] 资源对象数组, 0 表示资源 1 url 2 类型 3 是否加载完成 _load: function (idx, ops) { var res = this._res[idx]; if (!res[3]) { if (res[2] == "audio") this._load_audio(res[1], idx, ops) if (res[2] == "image") this._load_image(res[1], idx, ops); } }, _load_image: function (src, i, ops) { var img = wx.createImage(); var that = this; that._res[i][0] = img; img.onload = function () { that._res[i][3] = true; } img.src = src; }, _load_audio: function (src, i, ops) { var audio = wx.createInnerAudioContext(); if (ops != null) { for (var k in ops) { audio[k] = ops[k]; } } var that = this; that._res[i][0] = audio; audio.onCanplay(function () { that._res[i][3] = true; }); audio.src = src; }, loaded: function (callback) { for (var i = 0; i < this._res.length; i++) { if (!this._res[i][3]) { var that = this; setTimeout(function () { that.loaded(callback); }, 200); return; } } callback(); }, add: function (src, type, id, ops) { this._res.push([null, src, type, false, id]); this._load(this._res.length-1, ops); }, item: function (src) { for (var i = 0; i < this._res.length; i++) { if (this._res[i][1] == src) { return this._res[i][0]; } } return null; } } var c = wx.createCanvas(); var ctx = c.getContext('2d'); var img = wx.createImage(); var plane = wx.createImage(); var bgm = wx.createInnerAudioContext(); bgm.loop = true; var bgCanvas = null; var offset = 0; var w = 0; var h = 0; var screenWidth = c.width; var screenHeight = c.height; // 上一次飞机的位置 var lasted = { x: 0, y: 0 }; // 触摸区域是否在飞机内部 var in_plane = false; function init_bg() { bgCanvas = wx.createCanvas(); bgCanvas.width = screenWidth; bgCanvas.height = screenHeight + h; var bgctx = bgCanvas.getContext('2d'); var y = 0; var x = 0; // 底部多绘制一张图片 while (y < screenHeight + h) { x = 0; while (x < screenWidth) { bgctx.drawImage(img, x, y, w, h); x += w; } y += h; } } function reset() { ctx.save(); ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, c.width, c.height); ctx.restore(); } function draw_copy() { ctx.save(); ctx.textAlign = "center" // 居中对齐 ctx.textBaseline = "middle" //垂直居中绘制 ctx.fillStyle = "#aaa"; ctx.font = "16px Arial" // 字体大小 16 像素 ctx.fillText("简单教程,简单编程", c.width / 2, (c.height - 36)) ctx.fillText(" © 2015-2018 www.twle.cn", c.width / 2, (c.height - 18)); ctx.restore(); } function animate_it() { reset(ctx); ctx.drawImage(bgCanvas, 0, offset, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight); ctx.drawImage(plane, 0, 0, 128, 128, lasted.x - 64, lasted.y - 64, 128, 128); draw_copy(); offset++; if (offset % h == 0) { offset = 0; } requestAnimationFrame(animate_it); } wx.onShow(function () { bgm.play() }) wx.onAudioInterruptionBegin(function () { // 暂停音乐 bgm.stop(); // 中断动画 //cancelAnimationFrame(animate_it); }) wx.onAudioInterruptionEnd(function () { bgm.play() // 恢复动画 cancelAnimationFrame(animate_it); }) wx.onTouchStart(function (e) { var x = e.touches[0].clientX; var y = e.touches[0].clientY; if (plane_hit(x, y)) { in_plane = true; } }); wx.onTouchEnd(function (e) { if (in_plane) { lasted.x = e.touches[0].clientX; lasted.y = e.touches[0].clientY; in_plane = false; } }); // 触摸移动事件 wx.onTouchMove(function (e) { if (in_plane) { lasted.x = e.touches[0].clientX; lasted.y = e.touches[0].clientY; } }) function plane_hit(x, y) { return x > (lasted.x - 64) && x < (lasted.x + 64) && y > (lasted.y - 64) && y < (lasted.y + 64); } function start() { w = screenWidth > img.width ? img.width : screenWidth; h = img.height * (w / img.width); lasted.x = (screenWidth - 128) / 2; lasted.y = screenHeight - 128; bgm.play() init_bg(); ctx.drawImage(plane, 0, 0, 128, 128, lasted.x, lasted.y, 128, 128); draw_copy(); requestAnimationFrame(animate_it); } reset(); Resource.add('images/bg.jpg', 'image'); Resource.add('audio/bgm.mp3', 'audio'); Resource.add('images/plane.png', 'image'); Resource.loaded(function () { bgm = Resource.item('audio/bgm.mp3'); img = Resource.item('images/bg.jpg'); plane = Resource.item('images/plane.png'); start(); });
运行演示如下