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

屏幕红色转黑色淡入淡出效果仅生效一次的原因排查

红色到黑色淡入淡出效果重复调用失效问题解决

问题场景

我实现了一个从红色透明渐变到黑色的屏幕淡入淡出效果,首次调用功能正常,但后续重置状态后再次调用,效果完全失效。相关代码如下:

原效果类代码

export class FadeEffects {
    constructor(game) {
        this.game = game;
        this.width = 640;
        this.height = 480;
        this.fadeFinished = false;
        this.fade = 255;
    }

    // 从红色透明渐变到黑色
    fadeRed() {
        let fadeOut = setInterval(() => {
            console.log('in interval');
            this.fade -= 1;
            if (this.fade === 0) {
                this.fade = 255;
                this.fadeFinished = true;
                clearInterval(fadeOut);
            }
        }, 25);

        return this.fadeFinished;
    }

    draw(context) {
        context.fillStyle = "rgba(" + this.fade + ", 0, 0, 0.5";
        context.fillRect(0, 0, this.width, this.height);
    }
}

原调用逻辑

if(!this.fadeFinished && toRemove === 'TRUE'){
    this.fadeFinished = this.fadeEffect.fadeRed();
    this.fadeEffect.draw(context);
}

核心问题分析

  1. 异步状态同步错误:setInterval 是异步执行的,调用 fadeRed() 时会立刻返回初始的 fadeFinished(false),后续异步修改的 fadeFinished 无法同步到调用处的赋值,导致调用逻辑里的 this.fadeFinished 被错误设为false,判断逻辑彻底混乱。
  2. 重复创建定时器:每次满足调用条件时都会执行 fadeRed(),创建多个定时器同时修改 this.fade,状态被反复干扰,即使重置 fadeFinished,多个定时器的叠加也会让效果异常。
  3. 调用逻辑重复触发:只要 !this.fadeFinished && toRemove === 'TRUE',就会反复调用 fadeRed(),短时间内生成大量定时器,直接破坏状态。
  4. 颜色格式错误:draw 方法里的 rgba 字符串少了闭合的 ),存在渲染隐患。

修复方案

修正后的效果类代码

export class FadeEffects {
    constructor(game) {
        this.game = game;
        this.width = 640;
        this.height = 480;
        this.fadeFinished = false;
        this.fade = 255;
        this.fadeTimer = null; // 存储定时器引用,防止重复创建
    }

    // 从红色透明渐变到黑色
    fadeRed() {
        // 已有定时器在运行时直接返回,避免重复触发
        if (this.fadeTimer) return;

        this.fadeFinished = false;
        this.fade = 255; // 重置渐变初始值

        this.fadeTimer = setInterval(() => {
            this.fade -= 1;
            // 用<=0避免因定时器延迟导致的数值跳过0的情况
            if (this.fade <= 0) {
                this.fade = 255;
                this.fadeFinished = true;
                clearInterval(this.fadeTimer);
                this.fadeTimer = null; // 清除引用,允许下次调用
            }
        }, 25);
    }

    draw(context) {
        // 修复rgba格式错误
        context.fillStyle = `rgba(${this.fade}, 0, 0, 0.5)`;
        context.fillRect(0, 0, this.width, this.height);
    }
}

修正后的调用逻辑

// 仅在效果未开始、触发条件满足且无运行中定时器时,启动一次渐变
if (!this.fadeFinished && toRemove === 'TRUE' && !this.fadeEffect.fadeTimer) {
    this.fadeEffect.fadeRed();
}
// 只要渐变未完成,就持续绘制(保证每一帧都更新渐变状态)
if (!this.fadeFinished) {
    this.fadeEffect.draw(context);
}

修复说明

  • 新增 fadeTimer 属性:跟踪当前是否有渐变定时器在运行,彻底避免重复创建定时器的问题。
  • 移除 fadeRed() 的返回值:直接通过实例属性 fadeFinished 同步状态,解决异步导致的状态不同步问题。
  • 分离绘制逻辑:保证渐变过程中每一帧都能重新绘制,让渐变效果平滑显示。
  • 修复 rgba 格式错误:确保颜色渲染正常。
  • 调整终止条件为 this.fade <= 0:避免因定时器执行延迟导致 fade 直接跳过0的情况,保证渐变能正确终止。

内容的提问来源于stack exchange,提问作者Jleger91

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 16:53:29