用CSS实现星际飞狐飞行器,战斗吧!!!

814 阅读7分钟

我正在参加 码上掘金体验活动,详情:show出你的创意代码块

概述

看到这个设计原型时,我相信很多人的 DNA 都被触动了(虽然我未生于那个年代,但被那个年代深深的吸引)。上世纪九十年代,业界还在探索 3D 射击游戏的时候,任天堂首先推出了初代《星际火狐》,可以说《星际火狐》算是最早一批的 3D 效果的飞行射击游戏了。

这个 CSS 实现的飞行器就源于《星际火狐》初代。

code.juejin.cn/pen/7090550…

飞行器实现

飞行器看起来非常炫酷,你有可能会想这实现起来会有多复杂,哎~,那你就错了,且看我是如何一步一步分解炫酷的飞行器。

飞行器主体可以分为三部分: cockpit 飞行器主体;wing_left 左翼;wing_right 右翼

我们来看一下飞行器的俯视图:

top-map-trans.png

从俯视图(写到这里突然发现也不算是俯视图,大家暂且这么理解着)可以看出,飞行器是由多个不规则的三角形组成的,同时还可以看到一些三维立体感,可见这些三角形发生了偏转。

开始抢答,在前端中看到奇奇怪怪的三角形,你的第一想法是什么? 利用 border 实现

哎~你别说,我还就没这么用,皮不皮。

CSS3 有个属性叫 clip-path ,这个属性不得了,简直就是多边形的真神。(哦呦,谢天谢地了)

/* polygon 定义多边形等 */
/* polygon 实现的原理是连接指定点,最终显示所有点连接形成的闭合区域 */
clip-path: polygon(<fill-rule>?, [ <length-percentage> <length-percentage> ]#);

clip-path 的原点为左上角

cockpit 实现

cockpit 是飞行器的主舱,这里一定注意别上面看了个俯视图就以为当前部分只有两个三角形构成,我是有底的,有背的。

好的,好的,我知道了,那咱们就来瞅瞅 html 部分。

<div class="cockpit">
  <div class="under"></div>
  <div class="back"></div>
  <div class="left"></div>
  <div class="right"></div>
  <div class="edge_left"></div>
  <div class="edge_right"></div>
</div>

咦,他咋六部分那?我们后面的那两个三角形,一块绘制在主体部分。你看看,年轻人,一定要稳重,你不交代好,我咋能知道。

我们来实现一波 leftright

clip-path 的原点为左上角,polygon 是基于点连线实现,因此,因此 left 部分我们需要定义三个点,看图说话,左顶点位于最左边的上 1/4 处,因此位置应为 (0, 25%)。其余点大致类似

.left {
  width: 30px;
  height: 150px;
  background: linear-gradient(0deg, white 0%, #cccccc 100%);
  -webkit-clip-path: polygon(100% 0%, 0% 25%, 100% 100%);
  clip-path: polygon(100% 0%, 0% 25%, 100% 100%);
}
.right {
  width: 30px;
  height: 150px;
  background: linear-gradient(0deg, #aaaaaa 0%, #888888 100%);
  -webkit-clip-path: polygon(0% 0%, 100% 25%, 0% 100%);
  clip-path: polygon(0% 0%, 100% 25%, 0% 100%);
}

body-leri.png

你看看,这不是像模像样吗?

然后我们把剩下的部分依次进行上述设计,整体造型就成功设计出来了。

top-map.png

给飞行器的组成添加 position: absolute 定位以及 transform-rotate 语法,还是以 cockpit 为例子:

/* 我们以 cockpit 为例子 */

/* 底部 */
.under {
  position: absolute;
  width: 60px;
  height: 150px;
  background: linear-gradient(0deg, #666666 0%, #333333 100%);
  -webkit-clip-path: polygon(14.5% 23.5%, 85.5% 23.5%, 50% 100%);
  clip-path: polygon(14.5% 23.5%, 85.5% 23.5%, 50% 100%);
  /* 设置旋转中心 */
  transform-origin: 50% 100%;
  transform: rotateX(10.7deg) rotateY(180deg);
}
/* 后部 */
.back {
  position: absolute;
  width: 60px;
  height: 150px;
  background: radial-gradient(ellipse at center, #2ca4f4 0%, #0d25bf 67%);
  -webkit-clip-path: polygon(14.5% 25%, 85.5% 25%, 50% 6%);
  clip-path: polygon(14.5% 25%, 85.5% 25%, 50% 6%);
  transform-origin: 50% 25%;
  transform: translateZ(-21.5px) rotateX(-45deg) rotateY(180deg);
}
/* 左面 */
.left {
  width: 30px;
  height: 150px;
  background: linear-gradient(0deg, white 0%, #cccccc 100%);
  -webkit-clip-path: polygon(100% 0%, 0% 25%, 100% 100%);
  clip-path: polygon(100% 0%, 0% 25%, 100% 100%);
  transform-origin: 100% 0;
  transform: rotateY(-45deg);
}
/* 右面 */
.right {
  width: 30px;
  height: 150px;
  background: linear-gradient(0deg, #aaaaaa 0%, #888888 100%);
  -webkit-clip-path: polygon(0% 0%, 100% 25%, 0% 100%);
  clip-path: polygon(0% 0%, 100% 25%, 0% 100%);
  transform-origin: 0 0;
  transform: rotateY(45deg);
}

top-map-trans.png

我们来看一下立体造型:

top-map-liti.png

怎么样,炫酷不,fly fly 飞飞飞。

cockpit 实现总结

其实从上面的分析可以发现,整体飞行器实现并不复杂,我们主要使用了下面的方法

  • clip-path 绘制各种不规则三角形
  • position: absolute 实现图形定位
  • transform-rotate 实现图像旋转实现立体效果

大家一定要学起来啊,这几个属性太强了。

动画效果

飞行器它不会飞那还叫飞行器吗?这部闹着玩呐,来,咱们通过 animation 让他动起来。

如果想飞行效果够炫酷,那必须是三轴同步飞行,因此我给这个飞行器分别添加了 x y z 轴的旋转动画。

/* 绕 x 轴旋转动画 */
@keyframes flyX {
  0% {
    transform: translateX(0px);
  }
  25% {
    transform: translateX(180px);
  }
  50% {
    transform: translateX(0px);
  }
  75% {
    transform: translateX(-180px);
  }
  100% {
    transform: translateX(0px);
  }
}
/* 绕 y 轴旋转动画 */
@keyframes flyY {
  0% {
    transform: translateY(0px);
  }
  25% {
    transform: translateY(200px);
  }
  50% {
    transform: translateY(0px);
  }
  75% {
    transform: translateY(-200px);
  }
  100% {
    transform: translateY(0px);
  }
}

/* 绕 z 轴旋转动画 */
@keyframes flyZ {
  0% {
    transform: translateZ(0px);
  }
  25% {
    transform: translateZ(150px);
  }
  50% {
    transform: translateZ(0px);
  }
  75% {
    transform: translateZ(-150px);
  }
  100% {
    transform: translateZ(0px);
  }
}

然后我们将三个动画分别设置在飞行器的外层,形成下面的 HTML 结构。

<div class="fly_x">
  <div class="fly_y">
    <div class="fly_z">
      <!-- 飞行器主体 -->
      <div class="body"></div>
    </div>
  </div>
</div>

然后分别给 fly_x,fly_y,fly_z 添加动画效果。

.fly_x {
  /* 实现 3d 效果 */
  transform-style: preserve-3d;
  -webkit-animation: flyX 10152ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
  animation: flyX 10152ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
}
.fly_y {
  transform-style: preserve-3d;
  -webkit-animation: flyY 18891ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
  animation: flyY 18891ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
}
.fly_z {
  transform-style: preserve-3d;
  -webkit-animation: flyZ 14259ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
  animation: flyZ 14259ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
}

我们来看一下动画效果:

fly-ben.gif

乍一看还挺炫酷,但看习惯了咋感觉笨笨的。这可不行,我们再给最外层添加一个 Z 轴的旋转,模拟相机效果。

#awing {
  position: relative;
  transform-style: preserve-3d;
  transform: scale(1.5) rotateX(80deg);
  -webkit-animation: 10000ms cameraRotate cubic-bezier(0.545, 0.08, 0.52, 0.975)
    infinite alternate;
  animation: 10000ms cameraRotate cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite
    alternate;
}
@keyframes cameraRotate {
  0% {
    transform: scale(1.5) rotateX(70deg) rotateZ(20deg);
  }
  100% {
    transform: scale(1.5) rotateX(70deg) rotateZ(340deg);
  }
}

fly-cool.gif

咋样,现在看起来是不是炫酷多了,但总感觉飞行器还缺点什么,缺点啥呐?

火焰效果

飞行器飞起来没有火焰哪能有感觉,这里实现也有点看点,大家一定想不到。

我们先定义一个火焰 boost,样式如下:

.boost {
  position: absolute;
  width: 10px;
  height: 50px;
  margin-left: -5px;
  background: #00aaff;
}

然后我们添加多个 boost ,并且为每个 boost 定制动画效果,我这里举三个例子:

@keyframes boost1 {
  0% {
    transform: translateZ(-26px) translateY(-59px) translateX(3px) rotateY(
        157deg
      );
    opacity: 0.6;
  }
  100% {
    transform: translateZ(-14px) translateY(-300px) translateX(39px) rotateY(
        157deg
      );
    opacity: 0;
  }
}

@keyframes boost2 {
  0% {
    transform: translateZ(-19px) translateY(-48px) translateX(0px) rotateY(
        220deg
      );
    opacity: 0.6;
  }
  100% {
    transform: translateZ(-12px) translateY(-300px) translateX(-31px) rotateY(
        220deg
      );
    opacity: 0;
  }
}

@-webkit-keyframes boost3 {
  0% {
    transform: translateZ(-21px) translateY(-56px) translateX(7px) rotateY(
        64deg
      );
    opacity: 0.6;
  }
  100% {
    transform: translateZ(-6px) translateY(-300px) translateX(-4px) rotateY(
        64deg
      );
    opacity: 0;
  }
}

然后我们来看一下添加火焰后的效果:

fly-cool-fire.gif

怎么样够炫酷吗?这样还不够,我们继续优化一下火焰效果。

filter

CSS 里面有个 filter 属性,filter 属性有下列几种属性值:

  • blur(px): 对图像应用模糊效果。较大的值将产生更多的模糊。
  • contrast(%): 调整图像的对比度。0% 将使图像完全变黑。默认值是 100%,代表原始图像
  • grayscale(%): 将图像转换为灰阶。0% (0) 是默认值,代表原始图像。100% 将使图像完全变灰(用于黑白图像)
  • 还有几个属性,就不详细讲了,本项目主要使用前两个属性

boost 类名添加下面样式,然后我们来看一下最终结果:

filter: blur(15px) contrast(15);

fly-cool-fire-wonder1.gif

码上掘金代码是 scss 实现的,文章中是以 css 为角度讲解的。
部分代码实现借鉴大佬。