谁是炮仗王🧨?(游戏)和船长、优弧、troy一起炸掘金!

1,478 阅读4分钟

我正在参加掘金社区游戏创意投稿大赛个人赛,详情请看:游戏创意投稿大赛

游戏地址(电脑): xiguapi027.gitee.io/juejin/#/ju…

游戏地址(手机): xiguapi027.gitee.io/juejin/#/ju…

开发语言:react

运行平台:Chrome

gitee地址:gitee.com/xiguapi027/…

github地址:github.com/027xiguapi/…

游戏已开源,欢迎大家体验,也可以自行修改

介绍

这篇文章我准备其实在今年春节的时候就有这个想法了,奈何时间不够,就一直拖到了现在。春节前我在第一眼看到春哥写的谁是炮仗王的文章后,我就想把它做成游戏,毕竟谁不想成功的炸掉掘金,并自己控制了?

动画5.gif

技术

  1. react: 17.+
  2. umijs: 3.5.20
  3. svg
  4. animejs: 3.2.1
  5. mojs: 1.3.0
  6. ts

详细配置如图:

image.png

游戏规则

首先点击炮仗开始游戏,在规定时间内,点击一定数量的炮仗,如果你成功完成,则会出现掘金屏裂效果。当然规定的时间短,你可以点击头像增加时间

实现

灵感

本游戏的灵感来自春节期间的两篇文章(站在巨人身上二次创作)

  1. 谁是炮仗王🧨?春哥手把手带你炸掘金!

  2. 用svg实现鞭炮计时器

在此本人感谢两篇文章的作者:摸鱼的春哥027西瓜皮

1.用svg做一个鞭炮

svg 代码如下:

   <svg width="200" height="250" xmlns="http://www.w3.org/2000/svg" version="1.1" enable-background="new 0 0 200 200"
        xml:space="preserve">
        <g>
            <title>Layer 1</title>
            <g id="bomb">
                <path id="motion-path" fill="none" d="m0,0l0,5a10,10 0 0 1 -20,0a18,18 0 0 0 -36,0l0,30" />
                <path stroke="null" fill="#E7402E"
                    d="m149.17433,213.24695c0,11.83309 -7.94387,21.51372 -17.65204,21.51372l-58.69101,0c-9.70908,0 -17.65295,-9.68062 -17.65295,-21.51372l0,-108.80346c0,-11.83309 7.94387,-21.51482 17.65295,-21.51482l58.69101,0c9.70817,0 17.65204,9.68173 17.65204,21.51482l0,108.80346z"
                    id="svg_1" />
                <path stroke="null" fill="#F4DD50"
                    d="m131.1467,234.76267c9.91474,0 18.02763,-8.789 18.02763,-19.531l0,-2.806c0,-10.741 -0.41538,-19.53 -0.92215,-19.53l-94.1517,0c-0.50769,0 -0.92215,8.789 -0.92215,19.53l0,2.806c0,10.742 8.1129,19.531 18.02856,19.531l59.93981,0z"
                    id="svg_2" />
                <path stroke="null" fill="#3D100B"
                    d="m131.48444,237.69167l-59.61522,0c-11.37036,0 -20.62089,-10.076 -20.62089,-22.461l0,-2.807c0,-5.244 0.0964,-10.195 0.27267,-13.943c0.08814,-1.863 0.19096,-3.344 0.30756,-4.396c0.07069,-0.637 0.14414,-1.113 0.23227,-1.498c0.56921,-2.496 2.42831,-2.622 2.79462,-2.622l93.64185,0c0.36631,0 2.22541,0.126 2.79554,2.622c0.08814,0.385 0.16158,0.861 0.23135,1.498c0.1166,1.055 0.21942,2.533 0.30664,4.396c0.17627,3.748 0.2745,8.699 0.2745,13.943l0,2.807c-0.00092,12.385 -9.25145,22.461 -20.62089,22.461l0,0zm-74.41551,-41.868c-0.22126,2.823 -0.44068,8.557 -0.44068,16.602l0,2.806c0,9.154 6.83691,16.603 15.24189,16.603l59.6143,0c8.40406,0 15.2428,-7.447 15.2428,-16.603l0,-2.806c0,-8.045 -0.21942,-13.778 -0.43976,-16.602l-89.21856,0l0.00001,0z"
                    id="svg_3" />
                <path stroke="null" fill="#3D100B"
                    d="m131.68897,237.69167l-59.02419,0c-11.25764,0 -20.41645,-11.31481 -20.41645,-25.22252l0,-110.91463c0,-13.90771 9.15882,-25.22252 20.41645,-25.22252l59.02419,0c11.25764,0 20.41645,11.31481 20.41645,25.22252l0,38.0477c0,1.81581 -1.19348,3.29136 -2.6642,3.29136s-2.66329,-1.47443 -2.66329,-3.29136l0,-38.0477c0,-10.27946 -6.76913,-18.64317 -15.09169,-18.64317l-59.02146,0c-8.32074,0 -15.09078,8.36259 -15.09078,18.64317l0,110.91463c0,10.27833 6.76913,18.64317 15.09078,18.64317l59.02419,0c8.31983,0 15.09078,-8.36259 15.09078,-18.64317l0,-35.36161c0,-1.81693 1.19348,-3.29024 2.66329,-3.29024c1.47072,0 2.66329,1.47331 2.66329,3.29024l0,35.36161c-0.00182,13.90771 -9.16063,25.22252 -20.41736,25.22252z"
                    id="svg_4" />
                <path fill="#3D100B"
                    d="m149.17433,176.31867c-1.618,0 -2.93,-1.313 -2.93,-2.93l0,-12.109c0,-1.619 1.312,-2.93 2.93,-2.93s2.931,1.311 2.931,2.93l0,12.109c-0.001,1.618 -1.313,2.93 -2.931,2.93z"
                    id="svg_5" />
                <path fill="#FFFFFF"
                    d="m112.045,91.86l-7.031,0c-1.618,0 -2.93,-1.312 -2.93,-2.93c0,-1.618 1.312,-2.93 2.93,-2.93l7.031,0c1.618,0 2.93,1.312 2.93,2.93c0,1.618 -1.312,2.93 -2.93,2.93zm-47.115,32.125c-1.618,0 -2.93,-1.312 -2.93,-2.93l0,-16.062c0,-10.473 7.107,-18.992 15.842,-18.992l12.913,0c1.618,0 2.93,1.312 2.93,2.93c0,1.618 -1.312,2.93 -2.93,2.93l-12.912,0c-2.529,0 -4.957,1.287 -6.836,3.624c-2.029,2.524 -3.147,5.901 -3.147,9.509l0,16.063c0,1.616 -1.311,2.928 -2.93,2.928z"
                    id="svg_6" />
                <g stroke="null" id="svg_7">
                    <path stroke="#3D100B" id="fuse" fill="none" stroke-width="5"
                        d="m174.004,43.03652l0,5.51568c0,6.09305 -6.09177,11.03271 -13.59835,11.03271c-7.51559,0 -13.59835,-4.93965 -13.59835,-11.03271c0,-10.96721 -10.96441,-19.85888 -24.48423,-19.85888s-24.47908,8.89299 -24.47908,19.85888l0,33.09945" />
                </g>
                <circle fill="#F4DD50" cx="102" cy="141.97467" r="33.982" id="svg_10" />
                <rect x="120.36745" y="125.38426" transform="matrix(0.7071 0.7071 -0.7071 0.7071 101.112 -39.4959)"
                    fill="#F4DD50" width="23.614" height="23.615" id="svg_11" />
                <g id="spark">
                    <path id="ember" transform="scale(2.1 2.1) translate(83 20)" stroke="#F3A37C" stroke-width="1.25"
                        d="m-4.5,-1.5l3,0l1.5,-3l1.5,3l3,0l-2.5,2.5l1.5,3.25l-3.5,-2l-3.5,2l1.5,-3.25l-2.5,-2.5z"
                        fill="#FFF9EE" />
                    <g id="sparkles" transform="scale(0)">
                        <g fill="#F3A37C">
                            <circle transform="rotate(10) translate(12 0)" cx="0" cy="0" r="2">
                            </circle>
                            <circle transform="rotate(170) translate(12 0)" cx="0" cy="0" r="2">
                            </circle>
                            <circle transform="rotate(90) translate(12 0)" cx="0" cy="0" r="2">
                            </circle>
                            <circle transform="rotate(-60) translate(13 0)" cx="0" cy="0" r="2">
                            </circle>
                            <circle transform="rotate(-120) translate(13 0)" cx="0" cy="0" r="1.75">
                            </circle>
                        </g>
                    </g>
                </g>
                <text transform="rotate(180 105.781 146.791) matrix(1.14815 0 0 1.23535 89.2675 95.9221)" fill="#e7402e"
                    font-family="'MicrosoftYaHei'" font-size="29" id="svg_13" x="2" y="54" stroke-width="3"
                    font-weight="bold"></text>
            </g>
        </g>
    </svg>

效果如图:

image.png

2. 实现计时器

简单来说,分三步:

  1. 用 svg 技术画一个 🧨。
  2. 用 animejs 绘制引线变短动画。
  3. 用 animejs 绘制火星移动动画。 实现效果如下,具体实现可以参考用svg实现鞭炮计时器 动画3.gif

3. 炮仗爆炸,炸碎掘金

简单来说,分三步:

  1. 用 div 做一个爆炸闪光(原理遮罩由小变大再变小)。
  2. 用 德劳内三角化 制作裂纹。
  3. 用 canvas 让碎片坠落向深远。 具体实现可以参考谁是炮仗王🧨?春哥手把手带你炸掘金! 效果入下图: 动画.gif

4. 游戏规则-炮仗点击后跑动

在点击炮仗之后,炮仗会跑,实现效果如下: 动画2.gif 实现的原理很简单就是,点击炮仗之后给它一个随机的位子,用animejs是实现跑动动画。代码如下:

anime({
      targets: '.spark',
      left: Math.ceil(document.body.clientWidth * 0.9 * Math.random()) - 50,
      top: Math.ceil(document.body.clientHeight * 0.9 * Math.random()) - 130,
      scale: 0.5,
      duration: 200,
      easing: 'linear',
    });

5. 游戏规则-炮仗点击有反馈

因为点击动作太单调了,于是我增加了炮仗的点击有反馈,就是用mojs实现点击完后的星光闪现,实效果如下: 动画3.gif 代码如下:

new mojs.Burst({
      // 爆裂范围 {从多大 : 到多大}
      radius: { 0: 150 },
      // 动画挂载的父元素, 如果不填默认挂载到 <body>
      parent: '.spark',
      // 动画延迟的贝塞尔曲线函数
      easing: mojs.easing.bezier(0.1, 1, 0.3, 1),
      // 动画延迟时间
      duration: 1500,
      // 在动画动之前等待的时间 (这里一般设置150ms方便减少低端机型可能会存在的卡顿)
      delay: 300,
      // 扩散的粒子配置
      children: {
        duration: 750,
        // 粒子大小变换 {从多大 : 到多大}
        // rand(from, to) rand函数可以帮我们随机出一个区间的值
        radius: { 0: `rand(5, 75)` },
        // 形状选择, 这里我们选择了 “圆形”
        shape: 'circle',
        // 粒子可选的填充色
        fill: [
          '#1abc9c',
          '#2ecc71',
          '#00cec9',
          '#3498db',
          '#9b59b6',
          '#fdcb6e',
          '#f1c40f',
          '#e67e22',
          '#e74c3c',
          '#e84393',
        ],
      },
      // 透明度
      opacity: 0.6,
      // 生成的粒子数量
      count: 20,
    }).play();

6. 游戏规则-增加ICON(船长、优弧、troy)

为了增加游戏的趣味性,我特意邀请了三位掘金大佬来加入本游戏,其实就是微信群里获取的微信头像(ps:希望大佬不会介意)

// dom
<div className="czIcon icon" ref={czIconRef} onClick={onClickCZ}></div>
<div className="yhIcon icon" ref={yhIcon} onClick={onClickYH}></div>
<div className="tonyIcon icon" ref={tonyIcon} onClick={onClickTony}></div>
// css
.icon {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  position: fixed;
  cursor: pointer;
}

.czIcon {
  background-image: url('/imgs/cz.jpg');
  left: 20px;
  top: -120px;
}

.yhIcon {
  background-image: url('/imgs/yh.jpg');
  left: 120px;
  top: -220px;
}

.tonyIcon {
  background-image: url('/imgs/tony.jpg');
  left: 20px;
  top: -220px;
}

7. 游戏规则-点击ICON(头像),时间延长

原理就是控制anime的时间轴的进度,使计时器时间倒退,这里有一个坑,就是控制时间轴要暂停才行,代码如下:

// 先暂停
animation.pause();
// 时间倒退
animation.seek(animation.currentTime - time);
// 计时开始
animation.play();

6. 游戏规则-游戏结果

  1. 时间内没有点击到有效个数的炸弹(游戏失败)。

image.png 2. 成功完成游戏,最后会出现炸裂掘金的动画(游戏成功)。

动画4.gif

求赞

感谢你看到最后,最后再说两句

  1. 如果你持有不同的看法或者问题,欢迎你在文章下方进行留言、评论。
  2. 如果对你有帮助,或者你认可本文的话,欢迎点个赞,支持一下!

56fbe5154105202c842ed0e43a9cd87.jpg