前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >黑客帝国 - 矩阵雨

黑客帝国 - 矩阵雨

作者头像
Jimmy_is_jimmy
发布2022-11-22 16:33:56
5570
发布2022-11-22 16:33:56
举报
文章被收录于专栏:call_me_Rcall_me_R

theme: fancy

上次编写的文章 韩式浪漫 - 落雪唯美,我们整了个雪花的效果。

咦,那么我们可不可以扩展下,整一个 黑客帝国矩阵雨的效果 呢?

答案是肯定的,下面来整活。

该效果主要完成的功能有两点:

  • 矩阵雨绘制
  • 红蓝药丸编写

矩阵雨绘制

我们同样使用 canvas 来实现。基本思路如下:

  • 初始化画布,画笔
  • 初始化矩阵雨有多少列
  • 01 的初始化绘制的字符串
  • 在画布上绘制,以随机的 01 填充,计算绘制的 xy 轴的距离,并重复绘制
  • 监听视图窗口的更改,更新画布的大小和矩阵雨多少列的数据

实现的代码不多,这里贴上 JavaScript 文件的代码。代码即文档,若难以理解,请结合代码中的注释去学习。

代码语言:javascript
复制
(function() {
  let canvas = document.getElementById('canvas'); // 画布
  let ctx = canvas.getContext('2d'); // 画笔
  let width = canvas.width = window.innerWidth; // 设置 canvas 的大小,然后赋值给 width,方便后面的计算
  let height = canvas.height = window.innerHeight;
  let font = 12;
  let cols = 0;
  let dys = []; // 垂直距离的移动距离数组

  let matrix = '';
  let matrixSize = 20; // 矩阵雨的随机数量
  for(let i = 0; i < matrixSize; i += 1) {
    matrix += Math.floor(Math.random() * 2);
  }

  initData();
  // 初始化关键数据
  function initData() {
    // 列数据
    cols = width / font;
    // 随机生成 dy 垂直移动的距离
    for(let i = 0; i < cols; i += 1) {
      dys[i] = Math.floor(Math.random() * cols);
    }
  }

  

  function draw(){
    // ctx.clearRect(0, 0, width, height); 
    ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
    ctx.fillRect(0, 0, width, height); // 填充画布
    ctx.fillStyle = "#00ff00";
    ctx.font = `${font}px`;
    for(let i = 0; i < cols; i += 1) {
      let txt = matrix[Math.floor(Math.random() * matrixSize)];
      ctx.fillText(txt, i * font, dys[i] * font);
      if(dys[i] * font > height) {
        dys[i] = Math.floor(Math.random() * cols);
      }
      dys[i] += 1; // 垂直距离的设置
    }
    requestAnimationFrame(draw); // 重新绘制
  }

  draw();
  
  // 监听窗口更改
  window.addEventListener('resize', () => {
    // 重置画布的大小
    width = canvas.width = window.innerWidth;
    height = canvas.height = window.innerHeight;
    // 重新初始化关键数据
    initData();
  });
})()

需要注意的是,draw() 函数中,不可添加 ctx.clearRect(0, 0, width, height); 代码,不然就是雪花飘落的效果了。读者可以放开该代码,自行验证。

clearRect 是清空画布的指定区域

疑问点🤔️?细心的读者可能会提问:怎么效果图看起来有种类似拖尾的渐变效果?

这就很有意思了。但是实现挺简单的。你可以想象一下,写上文字的多个半透明的纸张依次叠加在一起的场景。也就是下面代码实现的功能:

代码语言:javascript
复制
// 透明度是 0.05 的黑色颜料
ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
ctx.fillRect(0, 0, width, height); // 填充画布

初始化绘制是 0.05 的透明度,第二次绘画的时候,初始化的透明度视觉效果增加到了 0.1,依次类推 0.150.2 .... 一直到 1.0 或以上的时候,你就对初始化的绘制文字看不出了。

红蓝药丸编写

我们通过 css 来实现 -- box-shadowlinear-gradient 并结合 ::before 或者 ::after 伪元素。

代码语言:javascript
复制
// 这里使用 less 预处理器编写
.pill{
  position: relative;
  width: @pillWidth;
  height: @pillHeight;
  border-radius: @pillRadius;
  // 高亮
  box-shadow: 0 1px 10px rgba(255,255,255,.1),
    0 15px 10px rgba(255,255,255,.1),
    0 0 10px rgba(255,255,255,.1),
    0 -5px 5px rgba(255,255,255,.4);
}
// 红色药丸
.red {
  background: linear-gradient(180deg,#ff4213 0%,#ab4225 100%) , 
    linear-gradient(180deg,#ff4213 0%,#ab4225 100%);
}
// 蓝色药丸
.blue {
  background: linear-gradient(180deg,#0000ff 0%,#add8e6 100%), 
    linear-gradient(180deg,#0000ff 0%,#add8e6 100%);
}
.pill:after{
  content: '';
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: @pillWidth;
  height: @pillHeight;
  border-radius: @pillRadius;
  // 阴影
  box-shadow: 0 0 15px rgba(56,56,56,.7) inset, // inset 表明内阴影
    0 0 5px rgba(23,23,23,.5) inset,
    0 -7.5px 5px rgba(23,23,23,.5) inset,
    0 0 1.5px rgba(	0, 255, 0,.3), 
    0 9px 20px rgba(	0, 255, 0,.4), 
    -1.5px 0 3px rgba(0,0,0,.4) inset,
    1.5px 0 1.5px rgba(0,0,0,.4) inset,
    0 5px 5px rgba(	0, 255, 0, .1), 
    0 6px 5px rgba(	0, 255, 0, .2), 
    0 12px 10px rgba(	0, 255, 0,.4);
}

整体效果

实现的体验效果如下,读者可以进入阅读全部的代码👇

代码片段

本文正在参加「金石计划 . 瓜分6万现金大奖」

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-11-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • theme: fancy
    • 矩阵雨绘制
      • 红蓝药丸编写
        • 整体效果
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档