Canvas图片无法渲染问题求助:demo.js加载图片后控制台提示成功但画面不显示
Canvas图片无法渲染问题求助:demo.js加载图片后控制台提示成功但画面不显示
我最近在做一个简单的JavaScript模拟游戏,把代码拆成了两个文件:script.js负责处理启动界面的过渡逻辑(比如点击Start后的文本闪烁、屏幕淡出、锁定点击、隐藏光标,大概4秒后加载游戏场景),相当于"游戏引擎";demo.js则负责存放游戏场景的数据,比如加载背景图片。
现在遇到了一个奇怪的问题:当我在demo.js里尝试加载背景图片时,控制台能正常打印图片加载完成的日志,但Canvas上就是看不到背景;可如果把同样的加载代码放到script.js里,背景就能正常渲染出来。我确认过文件路径是对的,实在搞不懂哪里出问题了,想请大家帮忙看看!
先给大家说下我的逻辑:
- 启动界面在
script.js里管理,点击Start后完成过渡效果,然后加载demo.js的内容 demo.js负责游戏场景的内容,比如加载背景图片
script.js
const canvas = document.getElementById('myCanvas'); const ctx = canvas.getContext('2d'); const testModeButton = document.getElementById('TestMode'); // Canvas setup canvas.width = 600; canvas.height = 600; canvas.style.display = 'block'; canvas.style.margin = '0 auto'; canvas.style.background = 'rgba(0, 0, 0, 0.25)'; // Change mouse cursor canvas.addEventListener('mouseenter', () => { canvas.style.cursor = 'url(file/mouse.cur), auto'; }); canvas.addEventListener('mouseleave', () => { canvas.style.cursor = 'auto'; }); // Test mode border on/off let testModeBorder = false; ctx.save(); ctx.globalAlpha = 0; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.restore(); ctx.strokeStyle = 'rgba(255, 99, 71, 0.8)'; ctx.lineWidth = 3; // Test mode click event testModeButton.addEventListener('click', function() { console.log('Test Mode clicked'); testModeBorder = !testModeBorder; // Toggle border drawing console.log('Draw border:', testModeBorder); }); // Background const titleBackgroundVideo = document.createElement('video'); titleBackgroundVideo.src = 'file/space.mp4'; titleBackgroundVideo.autoplay = true; titleBackgroundVideo.loop = true; titleBackgroundVideo.muted = true; // Title logo const titleImage = new Image(); titleImage.src = 'file/imp.png'; let titleImageWidth = 400, titleImageHeight = 250; let titleImageX = (canvas.width - titleImageWidth) / 2, titleImageY = 60; // Title menu text let startText = 'Start'; let endText = 'Exit'; let showText = true; // Function to draw text on the title menu function drawText(titleText, positionY, color = 'white') { if (!showText) return; ctx.save(); ctx.font = '30px Arial'; ctx.fillStyle = color; const textWidth = ctx.measureText(titleText).width; const titleTextX = (canvas.width - textWidth) / 2; ctx.fillText(titleText, titleTextX, positionY); ctx.restore(); } // Blinking text effect let startBlinkInterval = null; let endBlinkInterval = null; function startBlinkingText(target, interval = 100) { let textBlinkInterval = setInterval(() => { if (target === 'start') { startText = startText === 'Start' ? '' : 'Start'; } else if (target === 'end') { endText = endText === 'Exit' ? '' : 'Exit'; } }, interval); return textBlinkInterval; } // Clickable area rectangle const clickAreaWidth = 50; const clickAreaHeight = 50; const clickAreaX = (canvas.width - clickAreaWidth) / 2; const clickAreaY = (canvas.height - clickAreaHeight) / 2; // Draw clickable area function drawClickArea(x, y, width, height) { ctx.save(); ctx.fillStyle = 'rgba(255, 173, 173, 0)'; ctx.fillRect(x, y, width, height); ctx.restore(); } // Screen filter (used for fade effects) let filterOn = false; let alphaStart = 0; let alphaEnd = 1; let startTime = Date.now(); let frameCount = 0; let filterSettings = { speed: 0.004 }; // Function to animate screen filter function animateScreenFilter(x, y, width, height, start, end, callback) { filterOn = true; alphaStart = start; alphaEnd = end; function animate() { if (filterOn) { drawScreenFilter(x, y, width, height); requestAnimationFrame(animate); } else if (callback) { callback(); } } animate(); } // Rendering function function renderTitleScreen() { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(titleBackgroundVideo, 0, 0, canvas.width, canvas.height); if (testModeBorder) { ctx.strokeRect(0, 0, canvas.width, canvas.height); } ctx.drawImage(titleImage, titleImageX, titleImageY, titleImageWidth, titleImageHeight); drawText(startText, canvas.height / 2 + 90, 'white'); drawClickArea(clickAreaX - 38, clickAreaY + 80, clickAreaWidth + 78, clickAreaHeight - 3); drawText(endText, canvas.height / 2 + 140, 'white'); drawClickArea(clickAreaX - 38, clickAreaY + 130, clickAreaWidth + 78, clickAreaHeight - 3); requestAnimationFrame(renderTitleScreen); } // Mouse click lock function function enableClickAfterDelay(canvas, delayInSeconds, cursorStyle = 'url(file/mouse.cur), auto') { setTimeout(() => { isClickDisabled = false; console.log('Click is enabled again.'); canvas.style.cursor = cursorStyle; const event = new MouseEvent('mouseenter', { bubbles: true }); canvas.dispatchEvent(event); }, delayInSeconds * 1000); } // Menu click event canvas.addEventListener('click', function(event) { if (isClickDisabled) return; const rect = canvas.getBoundingClientRect(); const mouseX = event.clientX - rect.left; const mouseY = event.clientY - rect.top; if ( mouseX >= clickAreaX - 38 && mouseX <= clickAreaX - 38 + clickAreaWidth + 78 && mouseY >= clickAreaY + 80 && mouseY <= clickAreaY + 80 + clickAreaHeight - 3 ) { console.log('Start Click Area clicked!'); isClickDisabled = true; clearInterval(startBlinkInterval); startBlinkInterval = startBlinkingText('start', 100); canvas.style.cursor = 'none'; enableClickAfterDelay(canvas, 3, 'pointer'); filterSettings.speed = 0.003; animateScreenFilter(0, 0, canvas.width, canvas.height, 0, 1); titleBackgroundVideo.pause(); } if ( mouseX >= clickAreaX - 38 && mouseX <= clickAreaX - 38 + clickAreaWidth + 78 && mouseY >= clickAreaY + 130 && mouseY <= clickAreaY + 130 + clickAreaHeight - 3 ) { console.log('Exit Click Area clicked!'); isClickDisabled = true; clearInterval(endBlinkInterval); endBlinkInterval = startBlinkingText('end', 100); canvas.style.cursor = 'none'; filterOn = true; animateScreenFilter(0, 0, canvas.width, canvas.height, 0, 1); titleBackgroundVideo.pause(); setTimeout(() => { window.close(); }, 1850); } }); requestAnimationFrame(renderTitleScreen);
demo.js
const img = new Image(); function mainScreen() { img.src = 'file/demo_back01.jpg'; img.onload = function() { ctx.drawImage(img, 0, 0, canvas.width, canvas.height); console.log('The image has been loaded.'); }; }; function showMainScreen() { mainScreen(); };
index.html
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="TestMod" style="color: gray; position: fixed;">MainTestMod</div> <canvas id="myCanvas"></canvas> <script src="startBar.js"></script> <script src="script.js"></script> </body> <style> body { background-color: rgb(63, 23, 126); margin: 0; } </style> </html>
style.css
html, body { height: 100%; overflow: hidden; /* Prevent scrolling */ } body { background-color: black; display: flex; justify-content: center; align-items: center; position: relative; /* Set parent element to relative to overlap the canvas and menu bar */ } canvas { width: 1080px; height: 100%; display: block; z-index: 1; /* Ensure the canvas is below the menu bar */ } #menu-bar { position: fixed; /* Fixed at the top */ top: 0; /* Position at the top of the browser */ left: 0; width: 100%; height: 6vh; /* Occupy 6% of the top area */ background-color: #c0c0c0; z-index: 2; opacity: 0; /* Initially hidden */ display: flex; /* Arrange menu items horizontally */ justify-content: flex-start; /* Align to the left */ align-items: center; /* Vertically center */ padding-left: 0; /* Add left padding */ border: 2px outset white; } #menu-bar:hover { opacity: 1; /* Make menu visible when hovered */ } .menu-item { list-style: none; font-size: 16px; cursor: pointer; position: relative; margin-right: 30px; /* Space between menu items */ padding: 0 0 6px 0; display: inline-block; /* Arrange items horizontally */ } .submenu { visibility: hidden; /* Hide submenu by default */ opacity: 0; position: absolute; top: 100%; left: 0; background-color: #c0c0c0; border: 2px outset white; padding: 5px 0; z-index: 3; transition: opacity 0.2s ease; }
我现在怀疑是不是demo.js里的ctx或者canvas变量作用域的问题?或者是renderTitleScreen()的动画循环一直在清空画布,把demo.js画的背景覆盖掉了?希望有大佬能帮我找出问题所在,谢谢啦!
备注:内容来源于stack exchange,提问作者Da.D
相关产品推荐
相关产品推荐

