下载 App

一篇帖子搞定序列帧动画:从素材整理到角色、皮肤、怪物系统

精华04/18313 浏览开发交流
做 RPG、塔防、动作游戏,绕不开序列帧动画。角色走路、怪物攻击、技能特效,底层都是一帧一帧的图片快速切换。
这篇帖子从素材规范到代码实现,完整过一遍,不管你用什么引擎,思路都是通用的。欢迎留言补充。
horizontal linehorizontal line

一、先搞清楚你的素材类型

拿到素材包,先判断它是哪种结构,后续处理方式完全不同。

类型 A:精灵图集(Sprite Sheet)

所有帧拼在一张大图上,需要按坐标裁切。
┌──────────────────────────────┐
│ [帧0] [帧1] [帧2] [帧3] ... │  ← idle 动作
│ [帧0] [帧1] [帧2] [帧3] ... │  ← walk 动作
│ [帧0] [帧1] [帧2] [帧3] ... │  ← attack 动作
└──────────────────────────────┘
优点:单文件,加载快;缺点:需要记录每帧的坐标和尺寸(通常配套一个 .json 或 .xml 描述文件)。

类型 B:平铺帧序列(Flat Frame Sequence)

每帧是单独的图片文件,按编号命名。
walk_00.png  walk_01.png  walk_02.png  ...
优点:直观,方便单帧替换;缺点:文件数量多,加载时 IO 次数多。

类型 C:带方向的帧序列(带方向前缀)

在平铺基础上加方向维度,常见于等距视角游戏。
d0_walk_00.png  ← 方向0(S)walk 第0帧
d4_walk_00.png  ← 方向4(N)walk 第0帧
d6_walk_00.png  ← 方向6(E)walk 第0帧
或者更隐式的:所有帧平铺成一个序列,方向按固定间隔排列(比如每隔 10 帧换一个方向)。
拿到素材第一件事:确认是哪种类型,搞清楚方向和动作的组织方式,再动代码。
horizontal linehorizontal line

二、素材规范:和美术/外购素材对齐

2.1 方向定义

等距视角常用 8 方向,俯视角常用 4 方向。方向的编号没有统一标准,常见的有两种:
方案一:从北顺时针(Unity/Unreal 常见)
N(0)
  NW(7)   NE(1)
W(6)         E(2)
  SW(5)   SE(3)
       S(4)
方案二:从东逆时针(数学角度约定)
N
  NW       NE
W               E(0°)
  SW       SE
       S
  关键:收到外购素材时,必须问清楚或自己测试哪个编号对应哪个方向。
  不要假设,美术的"南"和你代码里的"南"很可能不是同一个方向。

2.2 建议的文件命名规范

```
{角色ID}{动作}{方向}_{帧编号}.png
示例:
herowalkd000.png
hero
walkd001.png
heroattackd200.png
boss
idled600.png
```
或者用目录区分:
assets/
  characters/
    hero/
      idle/  d0_00.png  d0_01.png  d4_00.png ...
      walk/  d0_00.png  d0_01.png  ...
      attack/ ...
    enemy_elite/
      ...
规范的命名让代码用循环批量加载,省去大量硬编码。
horizontal linehorizontal line

三、动画系统设计

3.1 最小数据结构

每套动画(AnimClip)需要记录:
lua
{
    frames = {"d0_walk_00", "d0_walk_01", "d0_walk_02"},  -- 帧列表
    fps = 8,          -- 播放速率
    loop = true,      -- 是否循环
    faceRight = true, -- 该方向的帧是否朝右
}
注册表(Registry)把所有角色的所有方向、所有动作都预先索引好:
lua
REGISTRY["hero_walk_d0"] = { frames = {...}, fps = 8, loop = true }
REGISTRY["hero_walk_d4"] = { frames = {...}, fps = 8, loop = true }
-- ...

3.2 方向扇区计算

拿到移动向量 (dx, dy)
之后,计算角度,映射到最近的方向扇区:
lua
-- 屏幕坐标:X 右为正,Y 下为正
local function getDirectionSector(dx, dy)
    if math.abs(dx) < 0.01 and math.abs(dy) < 0.01 then
        return nil  -- 静止,保持当前方向
    end
    local angle = math.atan(dy, dx) * (180 / math.pi)
    if angle < 0 then angle = angle + 360 end
    -- 每个扇区 45°,加 22.5° 是为了让边界对齐方向中心
    local sector = math.floor((angle + 22.5) / 45) % 8
    return sector
end
然后用映射表把 sector 转成素材里的方向编号:
lua
-- 按你的素材实际标注填写,不要猜
local SECTOR_TO_DIR = {
    [0] = 6,  -- 向右(E) → 素材 dir6
    [1] = 7,  -- 右下(SE) → 素材 dir7
    [2] = 0,  -- 向下(S) → 素材 dir0
    [3] = 1,  -- 左下(SW) → 素材 dir1
    [4] = 2,  -- 向左(W) → 素材 dir2
    [5] = 3,  -- 左上(NW) → 素材 dir3
    [6] = 4,  -- 向上(N) → 素材 dir4
    [7] = 5,  -- 右上(NE) → 素材 dir5
}
把映射集中放在这一张表里,发现方向对不上只改这里,不用到处找代码。

3.3 帧推进逻辑

```lua
function updateAnimation(anim, dt)
    anim.timer = anim.timer + dt
    local frameDuration = 1.0 / anim.clip.fps
while anim.timer >= frameDuration do
    anim.timer = anim.timer - frameDuration
    anim.frameIndex = anim.frameIndex + 1
    if anim.frameIndex > #anim.clip.frames then
        if anim.clip.loop then
            anim.frameIndex = 1
        else
            anim.frameIndex = #anim.clip.frames
            anim.finished = true
        end
    end
end
return anim.clip.frames[anim.frameIndex]
end
```
horizontal linehorizontal line

四、镜像复用 vs 原生帧

什么时候可以用镜像?

1、角色完全左右对称(圆形小球、无武器的简单怪物)
2、素材制作量有限,预算不够做全 8 方向

什么时候不该用镜像?

1、等距视角角色(阴影、肩宽、武器握法都是不对称的)
2、角色身上有文字或图案
3、用了高质量外购素材,原生帧都有,没必要用镜像降质量

先确认素材完整性,再决定方案

收到素材包之后,做一个简单验算:
```
总帧数 ÷ 动作数 ÷ 每个动作平均帧数 = 方向数
例:360 帧 ÷ 3 个动作 ÷ 约 10 帧/动作 ≈ 12(异常,重新算)
    360 帧 ÷ 3 个动作 ÷ 15 帧/方向 = 8(8 方向,完整!)
```
如果方向数能整除 8,基本就是完整 8 方向,不需要镜像。
horizontal linehorizontal line

五、皮肤系统设计

皮肤的本质是:同一套动画逻辑,换一套帧图。

方案一:注册表替换

每套皮肤预先注册一套 REGISTRY,切换皮肤时替换使用的注册表。
```lua
-- 默认皮肤
SKINS["default"]["herowalkd0"] = { frames = {"herowalkd0_00", ...} }
-- 黄金皮肤
SKINS["gold"]["herowalkd0"]    = { frames = {"herogoldwalkd000", ...} }
-- 切换皮肤
function setSkin(character, skinName)
    character.registry = SKINS[skinName]
end
```

方案二:纹理替换(只换图,不换帧序列)

适合帧数完全一致的皮肤(同一套骨架,换贴图颜色/材质):
lua
-- 加载不同皮肤纹理
character.texture = loadTexture("skins/" .. skinName .. "/walk_sheet.png")
-- 帧坐标不变,只换纹理引用

方案三:染色/调色(Shader 方案)

适合颜色变体皮肤:
lua
-- 用颜色矩阵调整色相,不需要多份素材
character.colorMatrix = HUE_ROTATE(120)  -- 红→绿
  建议先用方案一,简单直接,出问题好排查。方案三是进阶优化,先把游戏做出来再考虑。
horizontal linehorizontal line

六、常见坑速查

| 现象 | 最可能的原因 | 排查方法 |
|------|------------|---------|
| 所有方向都走背面 | 翻转逻辑 bug(falsy 值穿透) | 逐个 print 翻转值,检查分支是否走对 |
| 某几个方向走背面 | 方向映射表填错 | 强制固定方向测试,逐个确认素材对应关系 |
| 方向对,但镜像方向别扭 | 用了镜像但素材其实有原生帧 | 检查素材完整性,补提取缺失方向 |
| 纵向 S/N 对调 | 素材方向标注与代码约定不一致 | 在映射表里交换 S/N 的值 |
| 动画播放速率忽快忽慢 | 帧推进没有用 dt 累积,而是每帧固定推进 | 用累积时间而不是帧计数控制帧切换 |
| 切换皮肤后动画乱帧 | 切换皮肤时没有重置帧计数器 | setSkin 时同时 reset frameIndex 和 timer |
horizontal linehorizontal line

七、总结

做好序列帧动画,核心就三件事:
1. 搞清楚素材结构:方向怎么排,动作怎么分,每个方向几帧
2. 映射表集中管理:方向扇区 → 素材编号的映射放在一个地方,发现问题只改一处
3. 皮肤和逻辑分离:动画逻辑不依赖具体图片路径,换皮肤只换数据
猜你想搜
taptap 制造序列帧动画
别再烧积分了!从每次 2000 到每次 50 的血泪经验截图
别再烧积分了!从每次 2000 到每次 50 的血泪经验
适用场景:所有在用 TapTap Code 开发游戏的小白 难度:★☆☆☆☆ 背景最近群里总有人"炫耀"一次操作花了几千积分,说实话这不是值得高兴的事——这是在告诉所有人你的开发方式有根本性问题。我也走过这条弯路,所以来说说怎么改。 积分消耗的本质是什么积分 = AI 处理的 token 数量 = 你发给 AI 的内容 + AI 回给你的内容所以烧积分的本质只有两种: 你让 AI 做了大量无效/重
精华
82 赞
23 回复
如何提升你游戏中的UI美术水平截图
如何提升你游戏中的UI美术水平
一、请为你的游戏挑选一款合适的字体 很多开发者没有注意到其实UI界面中最重要的元素是字体,一款合适的字体能给整个游戏的界面感官带来蜕变。 请看案例 那么如何挑选适合自己的字体呢? 我总结出了一些小经验可供参考: 黑体:通用 宋体:古风、武侠、修仙 楷体:古风、武侠、修仙 圆体:卡通、动漫、Q版 科技:科幻、未来、电子 顺手分享一个免费可商用字体网站: 当然 如果你不知道自己的游戏适合什么风格
精华
126 赞
44 回复
永恒虚空持续开发日记1——关于游戏中的新名词:场频截图
永恒虚空持续开发日记1——关于游戏中的新名词:场频
写在前边:首先感谢TapTap制造版主大大@汪崽 对于作品潜力的肯定,给与了我积分计划二的权限[表情_不好意思]。这边也在加紧开发改进各种功能中,期望尽快给大家带来成熟的版本。[表情_猫咪举手] 大家好,我是永恒虚空的制作人黑猫不详,大家叫我黑猫就好。从今天开始我将以后置开发日记的形式给大家分享我在TapTap制造中制作的游戏永恒虚空的开发过程,新人希望大家多多关照! 今天先给大家介绍我作品中最重
投票
3 赞
01:29
官方阅,申请积分计划2,希望官方继续支持我完成这款游戏,截图
官方阅,申请积分计划2,希望官方继续支持我完成这款游戏,
视频内容只是一部分, 本游戏耗时3个月,目前完成进度百分之80, 是生存游戏,进入修仙界,走剧情找到宗门加入, 这时游戏才是真正开始, 提升实力境界后就可以变强,获取功法法术法宝, @视频内是游戏里挑战妖族入侵一种主流玩法,游戏就是围绕着这个来进行, 还有很多地方可以战斗,获得资源修炼变强,比如去藏书阁学习功法, 去法宝楼抽法宝,每一个宗门数十个法宝抽取 去修仙界探索,获得各自的资源,可能遇见妖兽
1 赞
3 回复
2D 等轴测视角:完整理论截图
2D 等轴测视角:完整理论
2D 等轴测视角:完整理论 一、视角的本质 什么是等轴测 人站在高处斜着往下看地面,地面上的方格子不再是正方形,而变成了菱形。这就是等轴测的视觉本质。 俯视(正上方看下去): 等轴测(斜上方看下去): ┌──┬──┬──┐ ◇ ├──┼──┼──┤ ◇ ◇ ├──┼──┼──┤ ◇ ◇ ◇ └──┴──┴──┘ ◇ ◇ ◇ 正方形网格经过旋转 + 压缩,变成了菱形网格。 为什么是 2:1
6 赞
浅记《阿方的旅程》开发历程截图
浅记《阿方的旅程》开发历程
预计阅读时长10分钟,欢迎您先品鉴游戏,再回来看这篇“流水账” 这是我第一次实际接触“用自然语言制作游戏”,也是我第一次接触游戏开发工作,所以一切都是从零开始,跌跌撞撞,懵懵懂懂。[表情_豹哭] 我是通过获得的本次开发资格,6月22日晚,在微信公众号收到了测试资格的消息,最开始公布主题“跳跃”的时候,脑子里最先想到的就是几款非常经典的游戏「马里奥」「Flappy Bird」「Doodle Jump
10 赞
1 回复
01:07
我给制造开发了一个半自动的开发工作流截图
我给制造开发了一个半自动的开发工作流
随着多模态模型识图能力增强,尝试一下AI 是否能自己修复bug,自己检查。 1,基于画面修复代码 2,点击TapTap制造 菜单,切换屏幕显示 3,截图验证 刚跑通一个小闭环,给大家分享一下 随着模型能力增强,Token费用走低,这种半自动开发是未来常态了
1 赞
2 回复
游戏自荐《少女终焉契约》截图
游戏自荐《少女终焉契约》
之前玩放置类型的rpg游戏的时候我就在想,现在游戏的操作有的太过于繁琐了,有没有一款休闲一点的,想上线就上线,离线的时候角色能自动行动的游戏呢?感谢TapTap制造,我按照我的想法开发出了现在这款游戏。 一、故事背景和UI 游戏的故事背景是传统的异世界穿越故事,玩家被女神召唤到异世界,随后组建工会,招募美少女,打怪升级探索世界。所以我选择了更加二次元萌系画风的UI风格,主页为各个主要的功能,点开来
8 赞
3 回复
开发日志(day2)坚持去做就是好的开始截图
开发日志(day2)坚持去做就是好的开始
今天主要是修复了一下昨天遇到的很多问题,闪帧;装备的等级没有随怪物等级参考;再次进入地下城,怪物状态竟然显示(已倒下);不会自动更换目标,导致会反复鞭尸;等很多的问题,不过通过昨天的经验,有效的向ai提出问题并且发送截图发给ai调试,也是把这些问题成功排除,甚至还有多余的free额度来生成新的内容。 新增的内容有返回城镇;返回主界面;中途退出地下城保留进入前的状态;完成地下城的面板结算;当然最有感
1 赞
1 回复
【UI教程】如何将已有的效果图应用为实际的UI界面截图
【UI教程】如何将已有的效果图应用为实际的UI界面
在经过了一些折腾和比较折磨的尝试后,我总算是摸清楚了嗒啦啦怎么把UI效果图转换为实际游戏中的UI组件,今天就给大家带来这部分的经验分享。 tips:1.本篇教程需要各位掌握最基本的ps使用,具体的操作部分我会大致讲解,但仍需各位自行学习ps的基本操作,部分可以由ai代劳的环节我会注明。 2.本篇教程需要在以我前两篇教程作为前置环节,请在阅读这两篇前置教程后再进行本篇教程内容的学习 在按照前
12 赞
5 回复