在 游戏官网 的设计中,酷炫的 角色展示动画 往往能吸引玩家的眼球。一个精心制作的角色动画不仅可以提升网站的视觉效果,更能传递游戏的风格和特点,给玩家留下深刻的印象。本文将解析各大游戏官网的源码(包括 剑与远征、原神、重返未来1999、异环、星际战甲、第五人格 等),探讨如何将游戏角色以更生动的方式呈现在玩家面前。
图片格式
GIF
案例:弹射世界物语
将动图制作为 GIF 文件,并使用 <img>
标签嵌入网页,对于开发者来说几分钟即可实现动画功能。整体来说 GIF 是一种 制作简单(很多图像处理软件都支持生成 GIF)、兼容性强(基本上所有浏览器都支持)的 轻量级 的方案。
<img src="https://worldflipperapi.leiting.com:8090/uploads/admin/202405/66507cba3bc3f.gif" alt="">
但 GIF 动画存在许多局限性。例如,256 色的限制(当然,现在也存在 hack 技术在一定的条件下克服);由于 GIF 图片保存了每一帧的内容,导致文件体积较大;通常会采用压缩方式来减小体积,但这也会导致动画模糊和失真。因此,在高分辨率的场景中,GIF 并不是一个理想的实现方式。
另一方面,对于像《弹射世界物语》这类案例中的像素小人动画,由于其尺寸较小且只需少量颜色(146 KB 大小),GIF 动画反而成为一种适合的选择。
APNG/WebP
APNG案例:放置七骑士
WebP案例:洛伊的移動要塞: Fortress Saga
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万 种颜色),因此能承载更丰富的颜色细节。
注意对比边缘锯齿
CSS / JS
序列帧
前端实现序列帧动画的方法有多种,常见方式包括:CSS 动画、JavaScript 控制、Canvas 绘制 和 WebGL 等等。其中,CSS 和 JavaScript 是最基础且易于实现的方法,适合简单的动画需求。而Canvas 和 WebGL 则适用于更复杂和高性能的动画场景。
案例:宫廷界
在准备好 sprite 素材之后,可以通过 Animation 动画来实现逐帧动画的连续播放。具体来说,可以利用 animation-timing-function
属性中的阶梯函数 steps(number_of_steps, direction)
,可以指定动画分成几个等间隔的步数,并设定播放方向(start
或 end
)。
.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 允许用户创建复杂的动画,同时保持高效的资源管理和动画效果的灵活性。
可以使用 Spine运行库(Runtime) 在网页中加载和渲染动画,且效果同 Spine 的预览中完全一致。
- HTML5 Canvas – JavaScript/TypeScript, 在线演示
- HTML5 WebGL – JavaScript/TypeScript,在线演示
- HTML5 Web Player – JavaScript/TypeScript, 在线演示
- Canvaskit – JavaScript/TypeScript, 运行时文档
- Phaser - JavaScript/TypeScript,运行时文档
- THREE.js – JavaScript/TypeScript, 在线演示
例如 晶核 用的 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 成为制作和共享透明背景视频的理想选择。
案例:《星球大战:猎人》
制作一个透明背景的 WebM 视频主要涉及两个关键步骤:
-
创建带有透明背景的视频内容:可以使用视频编辑软件(如 Adobe After Effects、Premiere Pro 或其他工具)制作和导出包含 Alpha 通道的视频内容。确保导出的文件格式支持透明度,例如
AVI
、MOV
或PNG
序列。 -
转换为WebM格式:使用视频转换软件或命令行工具(如 FFmpeg)将带有透明背景的视频转换为
WebM
格式。FFmpeg 是一个强大的开源命令行工具,可以使用以下命令将MOV
文件转换为WebM
文件:ffmpeg -i input.mov -c:v libvpx-vp9 -b:v 1M -pix_fmt yuva420p output.webm
在网页中插入一个具有透明背景的 WebM 视频,可以直接通过 <video>
标签实现。
<video src="https://www.datocms-assets.com/57214/1651768080-sentinel-1600-x-1600.webm" loop="" autoplay="" playsinline=""></video>
不兼容 safari
然而,这种格式在某些浏览器上可能存在兼容性问题。特别是在 Safari 浏览器上,WebM
格式的视频可能无法正常显示透明部分。
案例:星球大战:猎人
案例采用渐进增强的策略,当检测到用户在 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
视频能够被直接解码和播放。
案例:《剑与远征:启程》
同样也可以使用 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 以上的资源。
mix-blend-mode
案例:星际战甲
mix-blend-mode
描述了一个元素的内容应该如何与其直系父元素的内容以及元素的背景进行混合。该属性允许开发者创建各种多彩和复杂的视觉效果,通过指定混合模式来控制前景内容和背景内容的融合方式。
案例中视频源为黑色背景,背景图层应用 mix-blend-mode
****控制背景图和角色视频的混合。
mix-blend-mode: lighten;
分离通道
案例:重返未来:1999
将 Alpha 通道从原视频中分离出来,这样可以将透明度信息单独存储在一个灰度视频中。合并后的视频一部分是黑白的只包含 Alpha 通道的部分,另一部分则是包含 RGB 颜色信息的原视频。
案例的实现方式将图像数据分成两部分 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 有更好的性能。公司已有成熟的实现方案,如 VAP 和 PAG。
背景合成
比较 hack 一点的方法,即将背景图直接合成到视频源中。这种方法可以有效避免处理带有 alpha 通道的视频的兼容性问题,并减少资源的大小。
不过,这种方法需要注意不同设备的适配问题,通常需要制作两套视频源:
一套用于横屏,
一套用于竖屏。
判断当前设备是处于竖屏还是横屏状态,然后根据判断结果,设置视频元素的 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 计算和图形渲染技术,使得即使没有深入的计算机图形学知识,开发者也可以快速上手,创建出具有高度互动性的三维应用。
通过 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);
});
通过监听鼠标按下、移动和释放事件,实现一个简单的鼠标拖动旋转功能。
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 效果,并且实时响应用户输入,实现动态的视觉体验。
案例:浮生忆玲珑
素材一张作为深度图,
另一张作为颜色图。
片段着色器通过根据深度值偏移颜色图的 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次元的诱惑
需要生成 多角度图像序列,每张图片都代表被旋转一个小角度后的样子。需要覆盖在水平旋转 360度 中的所有角度。推荐的图片数量至少为 24 张,以确保动画的流畅度。
初始化 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/分离通道/背景合成 | 小 | 大部分现代浏览器 | 可根据需求选择合适的技巧,实现灵活的动画效果 | 部分技巧实现较为复杂,需要一定的技术经验 | 需要根据具体场景选择合适的技巧,以平衡效果和性能 |
互动 3D | Three.js 等库加载和渲染 3D 模型,通过鼠标或触屏交互实现动画效果 | 大 | 需要浏览器支持 WebGL | 可实现高度互动性的 3D 动画效果 | 资源占用较大,对设备性能要求较高 | 需要高度互动性的 3D 动画效果,如 3D 角色展示和交互 |
动态 3D | WebGL 处理深度图和颜色图,根据用户输入实时渲染 3D 效果 | 中等 | 需要浏览器支持 WebGL | 可实现逼真且动态的 3D 效果 | 实现较为复杂,需要一定的 WebGL 知识 | 需要展示逼真且动态的 3D 效果,如场景漫游和交互 |
spritespin | 顺序播放多角度图像序列 | 中等 | 需要 jQuery 库支持 | 易于使用,可实现 360 度旋转展示 | 功能较为单一,仅适用于旋转展示 | 需要 360 度旋转展示物品或角色的场景 |
注: 表格中 "文件大小" 指的是相对大小,实际文件大小取决于具体素材和压缩方式。
欢迎关注公众号【球球的前端奶茶屋】。