前端动画:游戏官网源码解析

956 阅读14分钟

游戏官网 的设计中,酷炫的 角色展示动画 往往能吸引玩家的眼球。一个精心制作的角色动画不仅可以提升网站的视觉效果,更能传递游戏的风格和特点,给玩家留下深刻的印象。本文将解析各大游戏官网的源码(包括 剑与远征原神重返未来1999异环星际战甲第五人格 等),探讨如何将游戏角色以更生动的方式呈现在玩家面前。

图片格式

GIF

案例:弹射世界物语

chrome-capture-2024-10-17.gif

将动图制作为 GIF 文件,并使用 <img> 标签嵌入网页,对于开发者来说几分钟即可实现动画功能。整体来说 GIF 是一种 制作简单(很多图像处理软件都支持生成 GIF)、兼容性强(基本上所有浏览器都支持)的 轻量级 的方案。

<img src="https://worldflipperapi.leiting.com:8090/uploads/admin/202405/66507cba3bc3f.gif" alt="">

GIF 动画存在许多局限性。例如,256 色的限制(当然,现在也存在 hack 技术在一定的条件下克服);由于 GIF 图片保存了每一帧的内容,导致文件体积较大;通常会采用压缩方式来减小体积,但这也会导致动画模糊和失真。因此,在高分辨率的场景中,GIF 并不是一个理想的实现方式。

image.png

另一方面,对于像《弹射世界物语》这类案例中的像素小人动画,由于其尺寸较小且只需少量颜色(146 KB 大小),GIF 动画反而成为一种适合的选择。

6650ff8bbbe5c.gif

APNG/WebP

APNG案例:放置七骑士

chrome-capture-2024-10-21.gif

WebP案例:洛伊的移動要塞: Fortress Saga

chrome-capture-2024-10-28.gif

APNG(Animated Portable Network Graphics)是一个基于 PNG 的位图动画格式,由 Mozilla 在2004 年推出的。WebP 是一种同时提供有损压缩与无损压缩的图像格式,由谷歌于 2010 年推出。和 GIF 文件类似,使用 <img> 标签嵌入网页即可。

<img src="https://sgimage.netmarble.com/images/netmarble/skiagb/20230731/v9bx1690799132187.png" alt="路迪">

GIF 相比,APNG/Webp 格式的图像边缘没有白边。GIF 采用 LZW 压缩算法,而 APNG 采用 Deflate 压缩算法,WebP 则基于 VP8 视频格式的帧内编码,并以 RIFF 作为容器格式。在相同条件下,APNG/Webp 文件体积更小,效果更佳。GIF 是以 8 位色(256 种颜色)呈现图像,而APNG/WebP 支持 24 位真彩色(共有 1670万 种颜色),因此能承载更丰富的颜色细节。

chrome-capture-2024-10-21 1.gif

注意对比边缘锯齿

CSS / JS

序列帧

前端实现序列帧动画的方法有多种,常见方式包括:CSS 动画、JavaScript 控制、Canvas 绘制 和 WebGL 等等。其中,CSSJavaScript 是最基础且易于实现的方法,适合简单的动画需求。而CanvasWebGL 则适用于更复杂和高性能的动画场景。

案例:宫廷界

chrome-capture-2024-10-22.gif

在准备好 sprite 素材之后,可以通过 Animation 动画来实现逐帧动画的连续播放。具体来说,可以利用 animation-timing-function 属性中的阶梯函数 steps(number_of_steps, direction) ,可以指定动画分成几个等间隔的步数,并设定播放方向(startend)。

.animate {
    -webkit-animation: Show 1.5s steps(12) infinite;
    animation: Show 1.5s steps(12) infinite;
}

然后,通过使用 @keyframes 规则,并通过改变 background-position 的值,不断调整背景图的位置来展示不同的帧,从而实现动画帧切换。

@keyframes Show{
	from{ background-position-y: 0; }
	to{ background-position-y: 100%; }
}

Spine

Spine 是一款专业的 2D 骨骼动画软件,由 Esoteric Software 开发。它被广泛应用于游戏、动画和其他互动媒体的制作中。通过使用骨骼和插槽的方式,Spine 允许用户创建复杂的动画,同时保持高效的资源管理和动画效果的灵活性。

案例:原神晶核崩坏:星穹铁道

chrome-capture-2024-10-29.gif

可以使用 Spine运行库(Runtime) 在网页中加载和渲染动画,且效果同 Spine 的预览中完全一致。

例如 晶核 用的 spine-pixi Runtime

const spineObject = new PIXI.spine.Spine(spineData);
spineObject.skeleton.setToSetupPose();
spineObject.update(0);
spineObject.state.setAnimation(0, "daiji", true);

透明背景视频

首先,我们需要准备带有透明背景的视频文件,而 WebM 是适合此场景的视频格式,因其支持 Alpha 通道(透明度信息)。WebM 是一种开放、免版税的媒体文件格式,专为网络视频传输设计。它由 Google 开发,由于其开放性和高效性,WebM 成为制作和共享透明背景视频的理想选择。

案例:《星球大战:猎人》

chrome-capture-2024-10-30.gif

制作一个透明背景的 WebM 视频主要涉及两个关键步骤:

  1. 创建带有透明背景的视频内容:可以使用视频编辑软件(如 Adobe After EffectsPremiere Pro 或其他工具)制作和导出包含 Alpha 通道的视频内容。确保导出的文件格式支持透明度,例如 AVIMOVPNG 序列。

  2. 转换为WebM格式:使用视频转换软件或命令行工具(如 FFmpeg)将带有透明背景的视频转换为 WebM 格式。FFmpeg 是一个强大的开源命令行工具,可以使用以下命令将 MOV 文件转换为 WebM 文件:

    ffmpeg -i input.mov -c:v libvpx-vp9 -b:v 1M -pix_fmt yuva420p output.webm
    

视频资源链接

image.png

在网页中插入一个具有透明背景的 WebM 视频,可以直接通过 <video> 标签实现。

<video src="https://www.datocms-assets.com/57214/1651768080-sentinel-1600-x-1600.webm" loop="" autoplay="" playsinline=""></video>

不兼容 safari

然而,这种格式在某些浏览器上可能存在兼容性问题。特别是在 Safari 浏览器上,WebM 格式的视频可能无法正常显示透明部分。

image 1.png

案例:星球大战:猎人

案例采用渐进增强的策略,当检测到用户在 iOS 设备上或使用 Safari 浏览器时,系统会渲染图片组件,而在其他环境下展示 WebM 透明视频。

{isIOS || isSafari ? (
  <GatsbyImage
    image={getImage(character?.animationFallbackImage)}
    className="inline-block w-full max-w-2xl h-auto -mb-20 md:-mb-56"
  />
) : (
  <video
    src={character?.animation?.url}
    loop
    muted
    autoPlay
    playsInline
    className="inline-block w-full max-w-2xl h-auto -mb-20 md:-mb-56"
  ></video>
)}

兼容 safari

Safari 浏览器中,带有 alpha 通道的 HEVC 视频能够被直接解码和播放。

案例:《剑与远征:启程》

chrome-capture-2024-11-4.gif

同样也可以使用 ffmpeg 来进行编码,-c:v hevc_videotoolbox 指定使用 HEVC 编码器,-pix_fmt yuva420p 指定包含 alpha 通道的像素格式。

ffmpeg -i input.mov -c:v hevc_videotoolbox -profile:v main10 -pix_fmt yuva420p output.mov

为了确保视频的兼容展示,可以定义一个视频元素,并提供两种格式的源文件。注意 HEVC 要首先出现,因为 Safari 支持 VP9,但不支持带 alpha 通道的 VP9

<video muted="muted" poster="https://oss-resource.farlightgames.com/p/SDK/200000/0/100000/2024-02-01/c678d276f1d712d59c358ca5b6e0395d.png">
		<source src="https://oss-resource.farlightgames.com/p/SDK/200000/0/100000/2024-02-01/c678d276f1d712d59c358ca5b6e0395d.mp4" type="video/mp4;codecs=hvc1">
		<source src="https://oss-resource.farlightgames.com/p/SDK/200000/0/100000/2024-02-05/c678d276f1d712d59c358ca5b6e0395d.webm" type="video/webm">
</video>

视频技巧版

但是 HEVC 编码在处理带有 alpha 通道的素材时,需要额外的数据量来保存透明度信息,因此通常来说文件较大。例如,示例中时长 3s、分辨率 1920 x 1400 的视频达到 3M,如果视频的时间更长、色彩更加丰富,可能需要加载 10M 以上的资源。

image 2.png

mix-blend-mode

案例:星际战甲

mix-blend-mode 描述了一个元素的内容应该如何与其直系父元素的内容以及元素的背景进行混合。该属性允许开发者创建各种多彩和复杂的视觉效果,通过指定混合模式来控制前景内容和背景内容的融合方式。

videoframe_5553.jpg

案例中视频源为黑色背景,背景图层应用 mix-blend-mode ****控制背景图和角色视频的混合。

mix-blend-mode: lighten;

分离通道

案例:重返未来:1999

Alpha 通道从原视频中分离出来,这样可以将透明度信息单独存储在一个灰度视频中。合并后的视频一部分是黑白的只包含 Alpha 通道的部分,另一部分则是包含 RGB 颜色信息的原视频。

视频源地址

image.png

案例的实现方式将图像数据分成两部分 data1 和 data2。遍历 data2 的像素,如果红色通道值小于或等于 90,则将 alpha 通道设置为 0 表示透明;否则,复制 data1 像素值,并设置 alpha 通道为 255 表示不透明。

context.drawImage(video, 0, 0, canvas.width, canvas.height);
var data1 = context.getImageData(0, 0, canvas.width, canvas.height / 2);
var data2 = context.getImageData(
  0,
  canvas.height / 2,
  canvas.width,
  canvas.height / 2
);
for (let i = 0; i < data2.data.length; i += 4) {
  if (data2.data[i] <= 90) {
    data2.data[i + 3] = 0;
  } else {
    data2.data[i] = data1.data[i];
    data2.data[i + 1] = data1.data[i + 1];
    data2.data[i + 2] = data1.data[i + 2];
    data2.data[i + 3] = 255;
  }
}
show(data2);

尽管使用 Canvas 可以方便地处理图像和视频帧,但 WebGL 利用 GPU 进行并行处理,通常会比 Canvas 有更好的性能。公司已有成熟的实现方案,如 VAPPAG

背景合成

比较 hack 一点的方法,即将背景图直接合成到视频源中。这种方法可以有效避免处理带有 alpha 通道的视频的兼容性问题,并减少资源的大小。

案例:崩坏3 异环 星之破晓

chrome-capture-2024-11-8.gif

不过,这种方法需要注意不同设备的适配问题,通常需要制作两套视频源:

一套用于横屏,

视频源地址

image.png

一套用于竖屏。

视频源地址

image.png

判断当前设备是处于竖屏还是横屏状态,然后根据判断结果,设置视频元素的 src 属性以加载对应的视频。

function isPortrait() {
    if (window.screen.orientation && window.screen.orientation.type) {
        return this.includes(window.screen.orientation.type, 'portrait');
    }

    if (this.ios() && window.screen.orientation) {
        return 90 !== Math.abs(window.screen.orientation);
    }

    return window.innerHeight > window.innerWidth;
}

互动3D

Three.js

案例:第五人格

Three.js 是一个功能强大的 JavaScript 库,可以帮助开发者轻松在 Web 页面中创建和展示 3D 动画模型。该库封装了一系列复杂的 3D 计算和图形渲染技术,使得即使没有深入的计算机图形学知识,开发者也可以快速上手,创建出具有高度互动性的三维应用。

chrome-capture-2024-11-11.gif

通过 GLTFLoader 加载 3D模型,AnimationMixer 加载动画,设置 rotation 对模型进行交互旋转。

创建 GLTFLoader 来加载3D模型,加载与模型相关的动画,并创建 AnimationMixer 来控制动画。

var loader = new THREE.GLTFLoader();
var modelUrl = e; // 假设e是模型的URL

loader.load(modelUrl, function(gltf) {
    var model = gltf.scene;
    var animations = gltf.animations;
    var mixer = new THREE.AnimationMixer(model);
    var action = mixer.clipAction(animations[0]);
    action.loop = THREE.LoopRepeat; 
    action.play();
    scene.add(model);
});

通过监听鼠标按下、移动和释放事件,实现一个简单的鼠标拖动旋转功能。

chrome-capture-2024-11-11.gif

container.addEventListener("mousedown", function(e) {
    v.sx = e.pageX; 
    v.sy = e.pageY; 
    v.rt = u.rotation.y; 
    v.h = true; 
});

// 添加鼠标移动事件监听器
window.addEventListener("mousemove", function(e) {
    if (v.h) { 
        v.ex = e.pageX;
        v.ey = e.pageY; 
        var offsetX = v.ex - v.sx; 
        u.rotation.y = v.rt + 0.01 * offsetX; 
    }
});

// 添加鼠标释放事件监听器
window.addEventListener("mouseup", function() {
    v.h = false; 
});

动态3D

可以利用 WebGL 实现一张静态图复杂且逼真的 3D 效果,并且实时响应用户输入,实现动态的视觉体验。

案例:浮生忆玲珑

chrome-capture-2024-11-12.gif

素材一张作为深度图,

image 3.png

另一张作为颜色图。

image 4.png

片段着色器通过根据深度值偏移颜色图的 UV 坐标,实现基于深度图和鼠标输入的 3D 效果。

const fragment = `#ifdef GL_ES
  precision mediump float;
  #endif

  uniform vec4 resolution;
  uniform vec2 mouse;
  uniform vec2 threshold;
  uniform float time;
  uniform float pixelRatio;
  uniform sampler2D image0;
  uniform sampler2D image1;

  vec2 mirrored(vec2 v) {
    vec2 m = mod(v,2.);
    return mix(m,2.0 - m, step(1.0 ,m));
  }

  void main() {
    // uvs and textures
    vec2 uv = pixelRatio*gl_FragCoord.xy / resolution.xy ;
    vec2 vUv = (uv - vec2(0.5))*resolution.zw + vec2(0.5);
    vUv.y = 1. - vUv.y;
    vec4 tex1 = texture2D(image1,mirrored(vUv));
    vec2 fake3d = vec2(vUv.x + (tex1.r - 0.5)*mouse.x/threshold.x, vUv.y + (tex1.r - 0.5)*mouse.y/threshold.y);
    gl_FragColor = texture2D(image0,mirrored(fake3d));
  }`;

spritespin

Spritespin.js 是一个基于 jQuery 的插件,专注于通过顺序播放图片,实现 360度 全方位旋转的动画效果。Spritespin 能根据提供的一系列图片,按照顺序轮播这些图片,从而模拟出物品在空间中旋转的效果。

案例:2.5次元的诱惑

chrome-capture-2024-11-13.gif

需要生成 多角度图像序列,每张图片都代表被旋转一个小角度后的样子。需要覆盖在水平旋转 360度 中的所有角度。推荐的图片数量至少为 24 张,以确保动画的流畅度。

MergedImages.jpg

初始化 Spritespin 插件:

  • source:指定图像的路径,使用 SpriteSpin.sourceArray 方法生成。
  • width 和 height:设置 sprite 图像的宽度和高度。
  • sense:设置动画的方向,1 表示反向。
  • animate:设置是否自动播放动画,true 表示自动播放。
  • loop:设置是否循环播放动画,true 表示循环播放。
  • responsive:设置是否响应式,false 表示不响应式。
  • frameTime:设置每帧的显示时间,单位为毫秒。
  • frame:设置初始帧。
  • stopFrame:设置停止帧。
  • onLoad:当 sprite 图像加载完成后执行的回调函数,添加 load 类并显示相关元素。
  • onDraw:在每帧绘制时执行的回调函数,处理动画的逻辑。
$(o).spritespin({
	  source: SpriteSpin.sourceArray("/skin/images/home/" + a + "/" + t + "/{frame}.png", {
	      frame: [0, 35],
	      digits: 2
	  }),
	  width: 740,
	  height: 1040,
	  sense: -1,
	  animate: true,
	  loop: true,
	  responsive: false,
	  frameTime: 80,
	  frame: 29,
	  stopFrame: 0,
	  onLoad: function() {},
	  onDraw: function() {}
});

总结

游戏官网角色展示动画的实现方式多种多样,从轻量级的 APNG/WebP 到功能强大的 WebGL,从简单的序列帧到复杂的骨骼动画,可以根据项目需求和自身技术栈选择合适的方案。希望本文的源码解析能提供一些思路和启发,帮助创作出更加生动的网页动画效果。

方案原理文件大小兼容性优点缺点适用场景
GIF编码多帧图像小(像素风)所有浏览器制作简单,兼容性强色彩支持有限(256色),文件大小较大(高分辨率),压缩会导致模糊失真尺寸较小、颜色简单的动画,如像素风动画
APNG/WebP基于 PNG/VP8 的动画格式大部分现代浏览器支持真彩色,文件体积更小,效果更好部分旧版浏览器不支持需要更高色彩质量和较小文件大小的动画
CSS/JS 序列帧通过 CSS/JS 控制背景图片或元素位置实现动画帧切换所有浏览器易于实现,适合简单动画复杂动画实现困难,性能可能受限简单、循环播放的动画
Spine骨骼动画,通过控制骨骼节点实现动画效果需要运行库支持动画流畅,资源占用低,可实现复杂动画需要学习 Spine 软件和相关 API需要复杂动画效果和高效资源管理的场景,如游戏角色动画
透明背景视频WebM/HEVC(Safari) 格式视频,支持 Alpha 通道中等WebM 部分浏览器不兼容,Safari 仅支持 HEVC动画效果流畅自然,可实现复杂动画WebM 格式兼容性问题,HEVC 文件较大需要展示带有透明背景的视频动画,如游戏角色展示
视频技巧版mix-blend-mode/分离通道/背景合成大部分现代浏览器可根据需求选择合适的技巧,实现灵活的动画效果部分技巧实现较为复杂,需要一定的技术经验需要根据具体场景选择合适的技巧,以平衡效果和性能
互动 3DThree.js 等库加载和渲染 3D 模型,通过鼠标或触屏交互实现动画效果需要浏览器支持 WebGL可实现高度互动性的 3D 动画效果资源占用较大,对设备性能要求较高需要高度互动性的 3D 动画效果,如 3D 角色展示和交互
动态 3DWebGL 处理深度图和颜色图,根据用户输入实时渲染 3D 效果中等需要浏览器支持 WebGL可实现逼真且动态的 3D 效果实现较为复杂,需要一定的 WebGL 知识需要展示逼真且动态的 3D 效果,如场景漫游和交互
spritespin顺序播放多角度图像序列中等需要 jQuery 库支持易于使用,可实现 360 度旋转展示功能较为单一,仅适用于旋转展示需要 360 度旋转展示物品或角色的场景

注: 表格中 "文件大小" 指的是相对大小,实际文件大小取决于具体素材和压缩方式。

欢迎关注公众号【球球的前端奶茶屋】