「用前端重返童年🥤」为黑神话悟空定制红白机版游戏开始动画

简介: 「用前端重返童年🥤」为黑神话悟空定制红白机版游戏开始动画

正篇 — 用前端重返童年


网络异常,图片无法展示
|


我之前没有用过canvas,也是一点一点写的,代码质量不要吐槽哈~因为我知道这一次代码质量不行🌟


Hancao present to Game Science in 2021.


既然要出的是一个有情怀的前端作品,我也是花了很长时间在设计上,也试了很多方法去体现我的创意,但是效果并不是很好,边coding边摸索,最终就出来了本次作品的设计,正如我的标题所说,梦回童年的前端作品,效仿的便是老一代插卡游戏机中游戏的开机动画,不知道现在从事前端行业的伙伴年纪如何,但是像我这样刚入行一年的新人都见过,大家应该,八成,或许,大概,也都见过吧...


下面让我们一起见证,寒草用 前端技术黑神话悟空童年游戏经典开始动画结合的作品吧

这是前端工程师寒草在2021年献给游戏科学创作者们的礼物


重返80年代马赛克化的悟空

网络异常,图片无法展示
|


既然我们要重返童年,那么我们这个图片要紧跟时代啊,哪可以这么清晰。回想一下那个年代的游戏都是一个色块一个色块的马赛克,所以我们需要把悟空'马赛克化'

我们先搞一个canvas


<canvas id="my-canvas-monkey-king"></canvas>


之后我们在画布导入图片,并获取点阵信息,并间隔12像素去获取颜色并绘制


// 显示孙悟空
let canvas2 = document.getElementById("my-canvas-monkey-king");
let ctx2 = canvas2.getContext("2d");
var image2 = new Image();
image2.src = "monkey-king.jpeg";
image2.width = 700;
image2.height = 700;
image2.onload = function () {
    canvas2.width = image2.width;
    canvas2.height = image2.height;
    ctx2.drawImage(image2, 0, 0);
    var imageData2 = ctx2.getImageData(0, 0, image2.width, image2.height).data;
    // 将画布背景图黑
    ctx2.fillStyle = "#000";
    ctx2.fillRect(0, 0, image2.width, image2.height);
    var gap = 12;
    for (var h = 0; h < image2.height; h += gap) {
      for (var w = 0; w < image2.width; w += gap) {
        var position = (image2.width * h + w) * 4;
        var r = imageData2[position], g = imageData2[position + 1], b = imageData2[position + 2];
        // 因为我用的原图背景不是纯黑的,所以我直接筛除rgb相加小于165的点(为什么是165呢,因为600是整数,255 * 3 - 600 = 165)
        if (765 - (r + g + b) < 600) {
          ctx2.fillStyle = `rgb(${r}, ${g}, ${b})`;
          ctx2.fillRect(w, h, gap, gap);
        }
      }
    }
}


文字动效设计:悟空!出来吧~

网络异常,图片无法展示
|


这里做了一个logo马赛克化并且逐行绘制的效果,马赛克化的方法和之前一致,这个逐行绘制其实加入了一些细节,越到上面绘制起来越快,有点像一层层摞起来的文字一样~

我们再搞一个canvas


<canvas id="my-canvas-wukong"></canvas>


之后我们获取图片信息,按行存储在数组里,之后用定时器去获取每一行的信息,逐行绘制,每一次执行定时器的回调方法的时候也要记得减少定时器的时长。


let canvas = document.getElementById("my-canvas-wukong");
let ctx = canvas.getContext("2d");
var image = new Image();
image.src = "wukong.png";
image.width = 240;
image.height = 240;
image.onload = function () {
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0);
var imageData = ctx.getImageData(0, 0, image.width, image.height).data;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, image.width, image.height);
let pointPixels = [];
let rowPoints = [];
for (var h = image.height - 3; h >= 0; h -= 3) {
  if (h !== image.height - 3) {
    pointPixels.push(rowPoints);
    rowPoints = [];
  }
  for (var w = image.width - 3; w >= 0; w -= 3) {
    var position = (image.width * h + w) * 4;
    var r = imageData[position], g = imageData[position + 1], b = imageData[position + 2];
    if (r + g + b !== 0) {
      rowPoints.push([w, h]);
    }
  }
}
ctx.fillStyle = "#fff";
let index = 0;
const length = pointPixels.length;
let delay = 30;
const fn = () => {
  let timer = setTimeout(() => {
    clearTimeout(timer);
    if (index != length) {
      const rowPoints = pointPixels[index];
      for (const rowPoint of rowPoints) {
        ctx.fillRect(rowPoint[0], rowPoint[1], 3, 3);
      }
      delay = delay - 0.125;
      index++;
      fn();
    } else {
      const dom = document.getElementById('operation');
      dom.style.opacity = 1;
    }
  }, delay)
}
fn();
}


梦回童年的游戏菜单


之后我们来设计一下我们的操作界面,我们先去回顾一下那些老游戏的界面:


网络异常,图片无法展示
|


emm,看上去我们已经把上面的title做完了,要设计下面操作菜单了,我也是按照经典的来:


网络异常,图片无法展示
|


这里文字用了文字阴影效果。下面的单人游玩和多人游玩使用了金箍棒作为选择指针~我想金箍棒也是悟空的标志了。下面还要留下我的署名:Hancao present to Game Science in 2021.,是不是就有游戏厂商注册商标那感觉了~


<style>
#operation {
      position: absolute;
      left: 30vw;
      top: 55vh;
      width: 40vw;
      height: 300px;
      text-align: center;
      transition: all 2s;
      opacity: 0;
    }
    #title {
      color: white;
      font-size: 40px;
      font-weight: 800;
      text-shadow: 8px 8px 8px #888888;
      cursor: pointer;
      text-decoration: none;
    }
    .select {
      margin-top: 32px;
      text-align: left;
      padding-left: 160px;
    }
    .option {
      overflow: hidden;
    }
    .op {
      display: inline-block;
      overflow: hidden;
      line-height: 45px;
      font-size: 30px;
      font-weight: 600;
      text-shadow: 8px 8px 8px #888888;
      color: #fff;
    }
    .jingubang {
      display: inline-block;
      height: 20px;
      width: 8px;
      background-color: #555151;
      border-top: 10px solid #7c7469;
      border-bottom: 10px solid #7c7469;
      margin-right: 16px;
    }
    .placeholder {
      display: inline-block;
      height: 20px;
      width: 8px;
      margin-right: 16px;
    }
    .hancao {
      font-size: 8px;
      margin-top: 48px;
      color: #fff;
    }
</style>
<div id="operation">
    <a id="title" href="https://www.heishenhua.com">
      BLACKMYTH WUKONG
    </a>
    <div class="select">
      <div class="option">
        <div class="jingubang"></div>
        <div class="op">
          1 PLAYER
        </div>
      </div>
      <div class="option">
        <div class="placeholder"></div>
        <div class="op">
          2 PLAYERS
        </div>
      </div>
    </div>
    <div class="hancao">
      Hancao present to Game Science in 2021.
    </div>
</div>


完整代码在此,复制粘贴,与我一同重返童年


完整代码在此,大家可以复制粘贴,记得 vscode 下载live server插件来运行,否则,canvas存在图片代理问题


tip: 完整效果见头图。代码质量堪忧,首先是canvas不太会,而且我是边设计边编码的,所以代码结构没有经过设计~


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>wukong</title>
  <style>
    body {
      margin: 0;
      background-color: #000;
    }
    #my-canvas-wukong {
      position: absolute;
      margin-left: 50vw;
      margin-top: 20vh;
      width: 16vw;
      height: 32vh;
    }
    #my-canvas-monkey-king {
      position: absolute;
      margin-left: 30vw;
      margin-top: 20vh;
      width: 16vw;
      height: 32vh;
    }
    #operation {
      position: absolute;
      left: 30vw;
      top: 55vh;
      width: 40vw;
      height: 300px;
      text-align: center;
      transition: all 2s;
      opacity: 0;
    }
    #title {
      color: white;
      font-size: 40px;
      font-weight: 800;
      text-shadow: 8px 8px 8px #888888;
      cursor: pointer;
      text-decoration: none;
    }
    .select {
      margin-top: 32px;
      text-align: left;
      padding-left: 160px;
    }
    .option {
      overflow: hidden;
    }
    .op {
      display: inline-block;
      overflow: hidden;
      line-height: 45px;
      font-size: 30px;
      font-weight: 600;
      text-shadow: 8px 8px 8px #888888;
      color: #fff;
    }
    .jingubang {
      display: inline-block;
      height: 20px;
      width: 8px;
      background-color: #555151;
      border-top: 10px solid #7c7469;
      border-bottom: 10px solid #7c7469;
      margin-right: 16px;
    }
    .placeholder {
      display: inline-block;
      height: 20px;
      width: 8px;
      margin-right: 16px;
    }
    .hancao {
      font-size: 8px;
      margin-top: 48px;
      color: #fff;
    }
  </style>
</head>
<body>
  <canvas id="my-canvas-wukong">
  </canvas> 
  <canvas id="my-canvas-monkey-king">
  </canvas>
  <div id="operation">
    <a id="title" href="https://www.heishenhua.com">
      BLACKMYTH WUKONG
    </a>
    <div class="select">
      <div class="option">
        <div class="jingubang"></div> 
        <div class="op">
          1 PLAYER
        </div>
      </div>  
      <div class="option">
        <div class="placeholder"></div>
        <div class="op">
          2 PLAYERS
        </div>
      </div>  
    </div>
    <div class="hancao">
      Hancao present to Game Science in 2021.
    </div>
  </div>
  <script>
    setTimeout(() => {
      let canvas = document.getElementById("my-canvas-wukong");
    let ctx = canvas.getContext("2d");
    var image = new Image();
    image.src = "wukong.png";
    image.width = 240;
    image.height = 240;
    image.onload = function () {
      canvas.width = image.width;
      canvas.height = image.height;
      ctx.drawImage(image, 0, 0);
      var imageData = ctx.getImageData(0, 0, image.width, image.height).data;
      ctx.fillStyle = "#000";
      ctx.fillRect(0, 0, image.width, image.height);
      let pointPixels = [];
      let rowPoints = [];
      for (var h = image.height - 3; h >= 0; h -= 3) {
        if(h !== image.height - 3 ){
          pointPixels.push(rowPoints);
          rowPoints = [];
        }
        for (var w = image.width - 3; w >= 0; w -= 3) {
          var position = (image.width * h + w) * 4;
          var r = imageData[position], g = imageData[position + 1], b = imageData[position + 2];
          if (r + g + b !== 0) {
            rowPoints.push([w, h]);
          }
        }
      }
      ctx.fillStyle = "#fff";
      let index = 0;
      const length = pointPixels.length;
      let delay = 30;
      const fn = () => {
        let timer = setTimeout(() => {
          clearTimeout(timer);
          if(index != length){
            const rowPoints = pointPixels[index];
            for(const rowPoint of rowPoints){
              ctx.fillRect(rowPoint[0], rowPoint[1], 3, 3);
            }
            delay = delay - 0.125;
            index++;
            fn();
          } else {
            const dom = document.getElementById('operation');
            dom.style.opacity = 1;
          }
      }, delay)
      }
      fn();
    }
    // 显示孙悟空
    let canvas2 = document.getElementById("my-canvas-monkey-king");
            let ctx2 = canvas2.getContext("2d");
            var image2 = new Image();
            image2.src = "monkey-king.jpeg";
            image2.width = 700;
            image2.height = 700;
            image2.onload = function () {
              console.log(image2, canvas2, ctx2);
              canvas2.width = image2.width;
              canvas2.height = image2.height;
              ctx2.drawImage(image2, 0, 0);
              var imageData2 = ctx2.getImageData(0, 0, image2.width, image2.height).data;
              console.log(imageData2)
              ctx2.fillStyle = "#000";
              ctx2.fillRect(0, 0, image2.width, image2.height);
              var gap = 12;
              for (var h = 0; h < image2.height; h+=gap) {
                  for(var w = 0; w < image2.width; w+=gap){
                          var position = (image2.width * h + w) * 4;
                          var r = imageData2[position], g = imageData2[position + 1], b = imageData2[position + 2];
                          if(765 - (r + g + b) < 600) {
                            ctx2.fillStyle = `rgb(${r}, ${g}, ${b})`;
                            ctx2.fillRect(w,h,gap,gap);
                          }
                  }
              }
            }
    }, 5000);
  </script>
</body>
</html>


结束语 — 热爱,所以期待


网络异常,图片无法展示
|


首先,文章中关于游戏和前端的看法仅仅代表我的主观想法,欢迎评论区指正,以及感谢大帅老师的文章与代码对我有思路上的指引~


本篇文章到此就结束了,我们不需要去捧杀黑神话悟空,持续期待就好了。以及大家或许能从我的文章看出我们可以用技术去完成很多很多好玩的事情,我也希望我的存在可以为前端开发者带来更多的创造力,更多的idea,让大家对这个行业更热爱~


这可能就是我现在作为一个有趣的,有奇奇怪怪的点子的前端工程师可以为社区带来的东西吧。(当然我也有硬核内容,比如寒草的编译原理哈哈哈)

相关文章
|
6月前
|
前端开发
前端毕业设计|基于Vue+Nodejs实现游戏资讯平台(二)
前端毕业设计|基于Vue+Nodejs实现游戏资讯平台
|
6月前
|
前端开发 JavaScript
前端必看的8个HTML+CSS技巧 (六) 裁剪图像的动画
前端必看的8个HTML+CSS技巧 (六) 裁剪图像的动画
|
4天前
|
前端开发 JavaScript API
前端开发的秘密武器:这些工具让你轻松应对各种复杂动画效果!
【10月更文挑战第30天】前端开发中,动画效果为页面增添了无限生机。CSS3的@keyframes规则和JavaScript动画库如GSAP、Anime.js等,使开发者能轻松实现从简单到复杂的动画效果。掌握动画原理和设计原则,结合工具和库,可以创造出既美观又实用的动画,提升用户体验。
17 4
|
6月前
|
JSON 前端开发 JavaScript
前端使用lottie-web,使用AE导出的JSON动画贴心教程
前端使用lottie-web,使用AE导出的JSON动画贴心教程
589 2
|
3月前
|
iOS开发 Android开发 MacOS
从零到全能开发者:解锁Uno Platform,一键跨越多平台应用开发的神奇之旅,让你的代码飞遍Windows、iOS、Android、macOS及Web,技术小白也能秒变跨平台大神!
【8月更文挑战第31天】从零开始,踏上使用Uno Platform开发跨平台应用的旅程。只需编写一次代码,即可轻松部署到Windows、iOS、macOS、Android及Web(通过WASM)等多个平台。Uno Platform为.NET生态带来前所未有的灵活性和效率,简化跨平台开发。首先确保安装了Visual Studio或VS Code及.NET SDK,然后选择合适的项目模板创建新项目。项目结构类似传统.NET MAUI或WPF项目,包含核心NuGet包。通过简单的按钮示例,你可以快速上手并构建应用。Uno Platform让你的技术探索之旅充满无限可能。
62 0
|
4月前
|
前端开发 JavaScript API
只会用插件可不行,这些前端动画技术同样值得收藏-JavaScript篇(下)
只会用插件可不行,这些前端动画技术同样值得收藏-JavaScript篇(下)
48 0
|
4月前
|
监控 JavaScript 前端开发
只会用插件可不行,这些前端动画技术同样值得收藏-JavaScript篇(上)
只会用插件可不行,这些前端动画技术同样值得收藏-JavaScript篇(上)
50 0
|
4月前
|
前端开发 JavaScript UED
只会用插件可不行,这些前端动画技术同样值得收藏-CSS篇
只会用插件可不行,这些前端动画技术同样值得收藏-CSS篇
93 0
|
4月前
|
前端开发 JavaScript
前端 JS 经典:数字变化动画
前端 JS 经典:数字变化动画
59 0
|
4月前
|
前端开发 API 开发者
前端 CSS 经典:边框转圈动画效果
前端 CSS 经典:边框转圈动画效果
171 0