鹅主题原型游戏运行越久卡顿越严重,求性能优化建议
游戏性能优化方案
你的卡顿核心原因是每帧都在创建新的DOM按钮,加上一些不必要的重复计算和渲染浪费,以下是具体优化点和代码修改:
核心问题修复(导致卡顿的主要原因)
gabFan()函数在draw()里被调用,而draw()每秒执行数十次,每次调用都会创建4个新按钮,导致页面DOM元素无限累积,内存和渲染开销爆炸。必须把按钮创建移到setup()中,只初始化一次:
修改后的核心结构:
// 把按钮变量提升为全局 let button0, button3, button2, button1; function setup() { createCanvas(windowWidth, windowHeight); // 在这里创建所有按钮,只执行一次 createFanButtons(); } function createFanButtons() { button0 = createButton("-1"); //heats up button0.size(90, 70); button0.position(windowWidth/2, windowHeight/2); button0.style("font-size", "48px"); button3 = createButton("3"); //3 button button3.mousePressed(fanButton); button3.size(90, 70); button3.position(windowWidth/2, windowHeight/2 + 70); button3.style("font-size", "48px"); button2 = createButton("2"); //2 button button2.size(90, 70); button2.position(windowWidth/2, windowHeight/2 + 140); button2.style("font-size", "48px"); button1 = createButton("1"); //1 button button1.size(90, 70); button1.position(windowWidth/2, windowHeight/2 + 210); button1.style("font-size", "48px"); } function gabFan() { fill(220); rect(windowWidth/2,windowWidth/2,windowWidth/2,windowHeight/2); fill(0); textSize(windowWidth/20); text("Thermostat: " + gabThermoStat + "/100", windowWidth/2+25, windowHeight/2) gabThermoStat = gabThermoStat + 1; // 这里不再创建按钮,只保留逻辑 }
其他性能优化点
替换setInterval计时器:
外部定时器和p5.js的draw()循环不同步,改用frameCount实现每秒减1,更稳定且减少线程开销:function draw() { // ...其他代码 // 每60帧(约1秒)减一次计时器 if (frameCount % 60 === 0 && timerValue > 0) { timerValue--; } }同时删除原来的
setInterval(timeIt, 1000)和timeIt()函数。简化重复计算:
gabGooseBod()里的mouseX-(mouseX/2)简化为mouseX/2,提前缓存重复使用的坐标值,减少冗余计算;修正超出范围的颜色值:function gabGooseBod() { const headX = mouseX / 2; const headY = mouseY - 25; push(); //goose neck stroke(240); strokeWeight(30); line(0, windowHeight, headX, headY); pop(); fill(240); //goose torso circle(0, windowHeight, 300); fill(255); //gooseHead(原300超出255,改为有效取值) rect(headX, headY, 50, 50); circle(headX, headY, 100); fill(0); circle(headX, headY, 40); //eye fill(255,166,0); circle(headX + 50, mouseY, 50); //goose bill & mouth // 激光修复:固定宽度,避免随鼠标变化的渲染开销,修正颜色值 fill(255,0,0,laserHue); rect(headX, headY - 40, 100, 30); if (mouseIsPressed) { laserHue = constrain(laserHue + 40, 0, 255); // 限制值范围,避免无效渲染 } else { laserHue = 0; } }优化游戏结束逻辑:
用noLoop()替代frameRate(0)或frameRate(2),直接停止draw()循环,彻底减少不必要的渲染:if (timerValue <= 0) { text(timerValue + " SECONDS, You WIN!", width / 3, height / 10); noLoop(); } if (gabThermoStat > 100) { gabThermoStat = 999; text("oops world heated", 50, 50); text("Oh no SECONDS, You LOSE!", width / 3, height / 10); noLoop(); } if (gabThermoStat <= 0) { gabThermoStat = -99; textSize(windowWidth/20); text("oops world frozen", 50, 50); text("NO SECONDS, You LOSE!", width / 3, height / 10); noLoop(); }音效播放优化:
避免重复触发音效,添加播放状态判断:function mousePressed() { //plays goose honk if (!gooseHonk.isPlaying()) { gooseHonk.play(); } }
完整优化后代码
let gabHeatColor = 0; let gabThermoStat = 30; var gooseHonk; let laserHue = 0; //denaplesk2 game timer let timerValue = 30; let startButton; let timerBar = 0; //will appear @ top screen // 全局按钮变量 let button0, button3, button2, button1; function preload() { soundFormats('wav'); gooseHonk = loadSound('spacejoe_bird-honk-2.wav'); } function mousePressed() { //plays goose honk if (!gooseHonk.isPlaying()) { gooseHonk.play(); } } function setup() { createCanvas(windowWidth, windowHeight); // 创建按钮,只执行一次 createFanButtons(); } function createFanButtons() { button0 = createButton("-1"); //heats up button0.size(90, 70); button0.position(windowWidth/2, windowHeight/2); button0.style("font-size", "48px"); button3 = createButton("3"); //3 button button3.mousePressed(fanButton); button3.size(90, 70); button3.position(windowWidth/2, windowHeight/2 + 70); button3.style("font-size", "48px"); button2 = createButton("2"); //2 button button2.size(90, 70); button2.position(windowWidth/2, windowHeight/2 + 140); button2.style("font-size", "48px"); button1 = createButton("1"); //1 button button1.size(90, 70); button1.position(windowWidth/2, windowHeight/2 + 210); button1.style("font-size", "48px"); } function draw() { background(140, 140, 72); strokeWeight(0); fill(107, 94, 43); //floor background rect(0, windowHeight/1.3, windowWidth, windowHeight); fill(140, 213, 237); //window rect(windowWidth/3, windowHeight/7, 200, 450); // 用frameCount实现每秒减1 if (frameCount % 60 === 0 && timerValue > 0) { timerValue--; } //timer > winstate or gameover fill(0); if (timerValue > 0) { text(timerValue + " SECONDS", width / 3, height / 10); } else { text(timerValue + " SECONDS, You WIN!", width / 3, height / 10); noLoop(); } if (gabThermoStat > 100) { gabThermoStat = 999; text("oops world heated", 50, 50); text("Oh no SECONDS, You LOSE!", width / 3, height / 10); noLoop(); } if (gabThermoStat <= 0) { gabThermoStat = -99; textSize(windowWidth/20); text("oops world frozen", 50, 50); text("NO SECONDS, You LOSE!", width / 3, height / 10); noLoop(); } gabFan(); gabGooseBod(); } function gabGooseBod() { const headX = mouseX / 2; const headY = mouseY - 25; push(); //goose neck stroke(240); strokeWeight(30); line(0, windowHeight, headX, headY); pop(); fill(240); //goose torso circle(0, windowHeight, 300); fill(255); //gooseHead rect(headX, headY, 50, 50); circle(headX, headY, 100); fill(0); circle(headX, headY, 40); //eye fill(255,166,0); circle(headX + 50, mouseY, 50); //goose bill & mouth fill(255,0,0,laserHue); rect(headX, headY - 40, 100, 30); // 固定激光宽度 if (mouseIsPressed) { laserHue = constrain(laserHue + 40, 0, 255); } else { laserHue = 0; } } function gabFan() { fill(220); rect(windowWidth/2,windowWidth/2,windowWidth/2,windowHeight/2); fill(0); textSize(windowWidth/20); text("Thermostat: " + gabThermoStat + "/100", windowWidth/2+25, windowHeight/2) gabThermoStat = gabThermoStat + 1; } function fanButton() { gabThermoStat = gabThermoStat - 20; print("-20, temp lowered"); }
内容的提问来源于stack exchange,提问作者Vabe Babe
相关产品推荐
相关产品推荐

