Canvas游戏开发:草块Tile无法正常渲染的问题求助
Canvas游戏草块Tile无法显示的修复方案
问题根源
你的代码存在两个核心问题导致草块无法绘制:
- Map类未正确引用全局变量:
Map类的grassLand方法中使用了this.tiley、this.tilex、this.tileSize、this.tiles,但这些变量是全局定义的,并非Map实例的属性,导致循环条件不成立,根本没执行绘制逻辑。 - 图片异步加载未处理:
Image对象加载是异步的,游戏循环启动时草块图片可能还没加载完成,调用drawImage时图片资源无效,自然无法显示。
修复步骤
- 修正Map类的变量引用:将
this.xxx改为直接访问全局变量,或者把这些变量作为参数传入Map类(后者更符合封装原则)。 - 等待图片加载完成再启动游戏:监听所有图片的
load事件,等全部加载完毕后再启动游戏循环。
修复后的完整代码
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; // Variables var tileSize = 32; var tilex = Math.ceil(canvas.width / tileSize); var tiley = Math.ceil(canvas.height / tileSize); var tiles = []; var player = []; var playerState = 'idle'; var keyPresses = {}; var userSize = 128; var loadedImagesCount = 0; var totalImages = 156 + 40; // 156个tile图 + 40个玩家图 // Event Listeners window.addEventListener('keydown', keyDownListener, false); function keyDownListener(event) { keyPresses[event.key] = true; }; window.addEventListener('keyup', keyUpListener, false); function keyUpListener(event) { keyPresses[event.key] = false; playerState = 'idle'; }; // 图片加载完成计数函数 function checkAllImagesLoaded() { loadedImagesCount++; if (loadedImagesCount === totalImages) { // 所有图片加载完成后启动游戏循环 setInterval(gameLoop, 1000/24); } } //TileImages grass, stone, and structure for (let i = 0; i < 156; i++) { tiles[i] = new Image(); tiles[i].src = 'performanceTask Assets/tiles/tile' + i.toString() + '.png'; tiles[i].onload = checkAllImagesLoaded; }; //Player Images idle and movement for (let i = 0; i < 40; i++) { player[i] = new Image(); player[i].src = 'performanceTask Assets/player/player' + i.toString() + '.png'; player[i].onload = checkAllImagesLoaded; }; class Map { xTileLocation = 0; yTileLocation = 0; grassLand() { // 直接使用全局变量,或者可以在构造函数传入这些参数 for (let i = 0; i < tiley; i++) { for (let j = 0; j < tilex; j++) { ctx.drawImage(tiles[0], this.xTileLocation, this.yTileLocation, tileSize, tileSize); this.xTileLocation += tileSize; }; this.xTileLocation = 0; this.yTileLocation += tileSize; }; this.xTileLocation = 0; this.yTileLocation = 0; }; }; class Player { x = canvas.width/2; y = canvas.height/2; tick = 0; playerImage = player; state = playerState; movementSpeed = 5; draw() { this.state = playerState // Movement if (keyPresses.w) { this.y -= this.movementSpeed; playerState = 'moving'; } if (keyPresses.s) { this.y += this.movementSpeed; playerState = 'moving'; } if (keyPresses.a) { this.x -= this.movementSpeed; playerState = 'moving'; } if (keyPresses.d) { this.x += this.movementSpeed; playerState = 'moving'; } // IDLE STATE if (this.state == 'idle') { if(this.tick==20 || this.tick > 20) { this.tick = 0; }; ctx.drawImage(this.playerImage[this.tick], this.x - 64, this.y + 64, 128, 128); } else { if (this.state == 'moving') { if(this.tick < 21 || this.tick == 39) { this.tick = 21; }; ctx.drawImage(this.playerImage[this.tick], this.x -64, this.y + 64, 128, 128); } } this.tick = this.tick + 1; }; }; let user = new Player(); let map = new Map(); function gameLoop() { ctx.clearRect(0, 0, canvas.width, canvas.height); map.grassLand(); user.draw(); };
内容的提问来源于stack exchange,提问作者Godlydonuts
相关产品推荐
相关产品推荐

