雨天屏保

前些日子,一个同事说喜欢 B 站上的线上自习室,打开视频就这么安安静静的一个人待着也很舒服,我也很喜欢这种状态。大约三四年前我有一个网页,背景是嘈杂的都市路口,小雨稀疏得下着,听着耳机里传来雨水哗啦啦的声音,我可以特别放空。恰逢端午的小雨,我把代码重新部署上线

181d923b2ce291402b1426040056f799.gif

实现思路

画面的主要功能是下雨,雨滴的绘制可以拆分成两个阶段,分别是落地前的渐变矩形和落地后的扩展椭圆形,设定了一个地面阈值,当雨滴的y坐标小于阈值时,雨滴的形状是矩形,每帧的回调中,y坐标递增,否则就是半径递增,核心逻辑:

move() {
    if (this.yPosition < this.maxHeight) {
        this.yPosition += this.yVelocity;
        this.xPosition += this.xVelocity;
    } else {
        if (this.radius < 30) {
            this.radius += this.radiusGrowth;
        } else {
            this.playing = false;
        }
    }
    this.draw();
}

雨滴的形状也很简单都是基础形状,所以直接用graphic绘制即可

draw() {
    if (this.yPosition < this.maxHeight) {
      this.context.beginPath();
      this.context.fillStyle = RainController.RAIN_COLOR;
      this.context.fillRect(this.xPosition, this.yPosition, RainController.RAIN_WIDTH, RainController.RAIN_HEIGHT);
    } else {
        this.context.beginPath();
        this.context.strokeStyle = RainController.RAIN_COLOR;
        this.context.ellipse(this.xPosition, this.yPosition, this.radius, this.radius * RainController.ELLIPSE_FACTOR, 0, 0, 2 * Math.PI);
        this.context.stroke();
    }
}

因为是原生的canvas,所以用 requestAnimationFrame 来控制雨滴的数量和更新雨滴的绘制,同时为了让雨势更自然,我还做了一个数量变化的滞后逻辑,这样用户在调整雨滴数量的时候就不会过于突兀,核心的控制逻辑详见:

step() {
    this.clearCanvas();
    this.updateRainDrops();
    this.drawRainDrops();
    window.requestAnimationFrame(this.step.bind(this));
  }
  clearCanvas() {
    this.context.fillStyle = RainController.BACKGROUND_COLOR;
    this.context.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
  }
  updateRainDrops() {
    const currentTimestamp = Date.now();
    if (currentTimestamp - this.previousTimestamp > RainController.UPDATE_INTERVAL) {
      this.adjustRainDropCount();
      this.previousTimestamp = currentTimestamp;
    }

    this.rainDrops = this.rainDrops.reduce((updatedRainDrops, rainDrop) => {
      if (rainDrop.playing) {
        rainDrop.move();
        updatedRainDrops.push(rainDrop);
      } else if (rainDrop.alive) {
        rainDrop.initialize(this.canvasWidth, this.canvasHeight);
        updatedRainDrops.push(rainDrop);
      }
      return updatedRainDrops;
    }, []);
  }
  adjustRainDropCount() {
    const rainGap = this.targetRainCount - this.rainDrops.length;
    const adjustmentBatchSize = Math.abs(Math.floor(rainGap / 20)) + 1;
    if (rainGap > 0) {
      this.addRainDrops(adjustmentBatchSize);
    } else if (rainGap < 0) {
      this.removeRainDrops(adjustmentBatchSize);
    }
  }
  addRainDrops(count) {
    for (let i = 0; i < count; i++) {
      const rainDrop = new Rain(this.context);
      rainDrop.initialize(this.canvasWidth, this.canvasHeight);
      rainDrop.alive = true;
      this.rainDrops.push(rainDrop);
    }
  }
  removeRainDrops(count) {
    for (let i = 0; i < count * 3; i++) {
      const randomIndex = Math.floor(Math.random() * this.rainDrops.length);
      this.rainDrops[randomIndex].alive = false;
    }
  }
  drawRainDrops() {
    this.rainDrops.forEach(rainDrop => rainDrop.draw());
  }

我还增加了日期和番茄时钟功能,番茄时钟支持多个倒计时数字的设置,为了让控制面板不干扰整个画面,我还特意做了控制面板的隐藏,只有当鼠标悬浮在屏幕右下角的时候才会唤起面板,同时面板上还可以设置声音的开关、雨势的大小、全屏开关

ed1342031d150238c8b3322cd6aede33.jpeg
面板

因为功能定义是个自用的屏保,所以 它适合在PC端 打开,而且受浏览器的限制还得点击一下才会播放声音,完整的代码我就不贴了,喜欢的朋友可以打开网站,右键选择保存网页即可获取所有代码

点击查看原文可直接跳转网页

融球效果(shader)    颜色滤镜    水波扩散效果(shader)

镜面光泽效果    圆形头像(shader)    追光效果

shader 溶解效果    富文本打字机效果    放大镜效果

子弹跟踪效果    移动残影效果    刮刮卡实现

微信小游戏首包超出4M之后      设计稿生成游戏界面

GameJam线下48小时极限游戏开发体验  

马赛克效果(shader)       游戏场景碎片过渡效果

ee666e0b4e0502d06bdb03f7c0bce8b7.png


  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值