You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

鹅主题原型游戏运行越久卡顿越严重,求性能优化建议

游戏性能优化方案

你的卡顿核心原因是每帧都在创建新的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;
  // 这里不再创建按钮,只保留逻辑
}

其他性能优化点

  1. 替换setInterval计时器:
    外部定时器和p5.js的draw()循环不同步,改用frameCount实现每秒减1,更稳定且减少线程开销:

    function draw() {
      // ...其他代码
      // 每60帧(约1秒)减一次计时器
      if (frameCount % 60 === 0 && timerValue > 0) {
        timerValue--;
      }
    }
    

    同时删除原来的setInterval(timeIt, 1000)和timeIt()函数。

  2. 简化重复计算:
    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;
      }
    }
    
  3. 优化游戏结束逻辑:
    用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();
    }
    
  4. 音效播放优化:
    避免重复触发音效,添加播放状态判断:

    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:14:55