【笔记】直播编程写游戏 - 3
饮水思源:https://www.bilibili.com/video/av12198966
自定义log &显示分数:
//let log = console.log.bind(console); let e = sel => document.querySelector(sel); let log = function(s) { e("#id-text-log").value += s + '\n'; }; let imgFromPath = function(path) { let img = new Image(path); img.src = path; return img; };
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> canvas { border: 1px black solid; } </style> <script src="js/utils.js"></script> <script src="js/guagame.js"></script> <script src="js/paddle.js"></script> <script src="js/ball.js"></script> <script src="js/brick.js"></script> <script src="js/levels.js"></script> </head> <body> <canvas id="id-canvas" width="400" height="300"></canvas> <p>fps:<input id="id-input-speed" type="range" /></p> <script> let pause = false; let enableDebugMode = function(game, enable) { if (!enable) { return; } window.addEventListener("keydown", event => { if (event.key == 'p') { pause = !pause; } }); document.querySelector("#id-input-speed").addEventListener("input", event => { let newFps = Number(event.target.value); game.fps = newFps + 1; // 防止为0 }); }; let __main = function() { let game = makeGuaGame(); enableDebugMode(game, true); let paddle = makePaddle(); let ball = makeBall(); let bricks = loadLevel(1); game.registerAction('a', function() { paddle.moveLeft(); }); game.registerAction('d', function() { paddle.moveRight(); }); game.registerAction('f', function() { ball.fire(); }); game.update = function() { if (pause) { // 暂停球的移动 return; } ball.move(); if (paddle.collide(ball)) { ball.反弹(); } for (let i = 0; i != bricks.length; ++i) { if (bricks[i].collide(ball)) { bricks[i].hit(); ball.反弹(); game.score++; } } }; game.draw = function() { game.drawImage(paddle); game.drawImage(ball); for (let i = 0; i != bricks.length; ++i) { if (bricks[i].alive) { game.drawImage(bricks[i]); } } // 显示分数 game.context.font = "48px serif"; game.context.fillText("你的分数:" + game.score, 30, 100); }; game.begin(); }; __main(); </script> </body> </html>
图片加载相关的问题,例如游戏里有3个砖块,那么brick.png就会被反复加载3次,这样很浪费时间,我想到的解决方法是用map保存加载过的图片,在拿图片的时候进行一次判断,加载过就直接返回,没加载过才加载,这样就可以确保每张图片只会被加载一次,并且实现上只需要重写imgFromPath方法而不用改其它地方:
let imgMap = new Map(); // let count = 0; let imgFromPath = function(path) { let img = imgMap.get(path); if (img != undefined) { return img; } img = new Image(); img.src = path; // img.onload = function() { // ++count; // log(count, path); // }; 用来调试的时候观察实际加载的次数 imgMap.set(path, img); return img; };
在游戏开始前加载所有图片:
let log = console.log.bind(console); let imgPaths = { ball: "img/ball.png", brick: "img/brick.png", paddle: "img/paddle.png", }; let imgMap = new Map(); let imgFromPath = function(path) { let img = imgMap.get(path); if (img != undefined) { return img; } img = new Image(); img.src = path; imgMap.set(path, img); return img; }; let loadImgs = function() { let imgLoads = 0; // 已经加载完毕的图片数量 let imgNames = Object.keys(imgPaths); return new Promise(resolve => { for (let name of imgNames) { let img = imgFromPath(imgPaths[name]); img.onload = function() { log('imgLoads=' + imgLoads); if (++imgLoads >= imgNames.length) { resolve(); } }; } }); };
loadImgs().then(() => {
game.begin();
});