用户角色精灵图制作角色的完整流程

2026-05-29
380113 分钟
...

在 2D RPG 游戏里,角色通常不是用一张单独图片完成的,而是用一张“角色精灵图”来做。

所谓角色精灵图,通常是一张包含多个动作帧的大图。比如角色向下走有 4 帧,向左走有 4 帧,向右走有 4 帧,向上走有 4 帧。Godot 会根据这些帧不断切换图片,看起来角色就动起来了。

这篇文章主要介绍:拿到一张角色精灵图之后,如何在 Godot 中把它做成一个可以正常移动、播放动画、和地图产生遮挡关系的角色。

一、先理解角色精灵图是什么

角色精灵图一般长这样:

 1向下走的动画帧
 2向左走的动画帧
 3向右走的动画帧
 4向上走的动画帧

或者有些资源是这样的:

 1向下
 2向上
 3向左
 4向右

不同素材的排列顺序不一定一样,所以第一步不是急着导入,而是先确认:

每一帧多大
一共有几行
一共有几列
每一行分别代表什么方向
有没有待机动画
有没有攻击受伤死亡动画
背景是否透明

如果你的角色资源是 32x32 的,那么意思是:

每一个角色动作帧占 32 像素宽32 像素高

如果一张图宽 128,高 128,并且每帧是 32x32,那么它就是:

4 x 4

也就是一共 16 帧。

二、角色精灵图导入 Godot 前要注意什么

在导入之前,最好先检查这几个点。

1. 背景最好是透明的

角色精灵图一般应该是 PNG 格式,并且背景透明。

如果是白底、黑底、灰底,导入 Godot 后会出现一个方块背景,看起来很难受。

推荐格式:

PNG
透明背景
每一帧严格对齐网格

不推荐:

JPG
带白底
帧之间间隔不统一
角色位置忽上忽下

2. 每一帧尺寸要统一

比如角色每帧是 32x32,那么每一帧都应该严格占 32x32。

不要出现这种情况:

第一帧 32x32
第二帧 33x32
第三帧 31x32

否则动画播放时,角色会抖动、错位。

3. 角色脚底位置最好一致

这是初学者很容易忽略的问题。

角色动画的重点不是头部对齐,而是脚底对齐。

因为角色站在地图上的位置,是以“脚底”为视觉参考的。如果每一帧脚底位置不一样,角色走路时会像在上下跳。

正确情况:

每一帧角色脚底都在同一条水平线上

错误情况:

有的帧脚底高一点
有的帧脚底低一点

三、推荐的角色场景结构

在 Godot 中,玩家角色一般不要直接用 Sprite2D 作为根节点。

更推荐使用:

Player
├── AnimatedSprite2D
├── CollisionShape2D
├── Camera2D
└── RemoteTransform2D / Marker2D / 其他辅助节点

对于 2D RPG,根节点通常使用:

CharacterBody2D

完整结构可以是:

Player / CharacterBody2D
├── AnimatedSprite2D
├── CollisionShape2D
├── Camera2D
└── InteractionArea / Area2D
    └── CollisionShape2D

每个节点的作用如下。

四、CharacterBody2D 是什么

CharacterBody2D 是 Godot 专门用来做“可移动角色”的 2D 节点。

比如:

玩家
NPC
怪物
可移动单位

都可以用它。

它的核心作用是:

负责移动
负责碰撞
负责速度
负责和墙石头等障碍物发生阻挡关系

前端类比的话,可以把它理解成:

角色的逻辑容器

就像你在 Vue 或 React 中写一个 Player 组件:

<Player>
  <角色图片 />
  <碰撞区域 />
  <摄像机 />
</Player>

CharacterBody2D 自己不负责显示图片,它只是角色的主体节点。

真正显示角色的是它下面的 AnimatedSprite2D

五、AnimatedSprite2D 是什么

AnimatedSprite2D 是负责播放角色动画的节点。

它可以播放:

向下走
向左走
向右走
向上走
待机
攻击
受伤
死亡

它需要配合一个资源使用:

SpriteFrames

SpriteFrames 就是 Godot 里专门管理动画帧的资源。

你可以把它理解成:

角色动画配置表

里面会定义:

动画名称
每个动画包含哪些帧
每秒播放多少帧
是否循环播放

例如:

idle_down
walk_down
walk_left
walk_right
walk_up

六、CollisionShape2D 是什么

CollisionShape2D 是角色的碰撞形状。

它决定角色在地图里“真实占用的碰撞范围”。

注意,它不一定要和角色图片一样大。

对于 RPG 角色,碰撞区域通常只需要覆盖脚底附近。

比如一个 32x32 的角色,不建议碰撞框设置为完整 32x32。

更推荐:

宽度12 18
高度8 14
位置角色脚底附近

因为角色的头部可以被树冠、屋顶遮住,但脚底才是真正站在地上的位置。

推荐效果:

角色图片高度32
碰撞框只放在下半部分

示意:

角色图片
┌────────────┐
头部
身体
腿部
脚底
└────────────┘

碰撞区域
      ┌────┐
脚底
      └────┘

不要这样:

碰撞框覆盖整个角色

否则角色会在靠近树、墙、桌子时显得距离很远,好像空气墙。

七、Camera2D 是什么

Camera2D 是摄像机。

如果它放在 Player 下面,就可以让镜头跟随角色移动。

常见设置:

Enabled开启
Position Smoothing开启
Position Smoothing Speed5 10

这样镜头不会死死贴着角色,而是有一点平滑跟随。

如果是 RPG 游戏,Camera2D 通常放在玩家角色下面:

Player
└── Camera2D

这样角色走到哪里,镜头就跟到哪里。

八、创建角色场景的完整流程

下面是完整流程。

第一步:创建 Player 场景

在 Godot 中新建一个场景。

根节点选择:

CharacterBody2D

命名为:

Player

然后保存为:

res://scenes/player/player.tscn

推荐目录:

res://
├── assets/
│   └── characters/
│       └── player.png
├── scenes/
│   └── player/
│       └── player.tscn
└── scripts/
    └── player/
        └── player.gd

第二步:添加 AnimatedSprite2D

在 Player 下添加:

AnimatedSprite2D

结构变成:

Player / CharacterBody2D
└── AnimatedSprite2D

选中 AnimatedSprite2D,在 Inspector 中找到:

Sprite Frames

新建一个:

SpriteFrames

点击进去,开始配置动画。

第三步:创建动画名称

建议创建这些动画:

idle_down
idle_left
idle_right
idle_up

walk_down
walk_left
walk_right
walk_up

为什么不要只叫 walk

因为 RPG 角色是四方向移动,每个方向的动画帧不同。

所以最好拆开。

如果以后加攻击,也可以继续加:

attack_down
attack_left
attack_right
attack_up

第四步:从精灵图中切帧

在 SpriteFrames 面板里,点击添加帧。

选择角色精灵图。

Godot 会让你设置切割方式。

如果你的角色图是:

4
4

就设置:

Horizontal4
Vertical4

如果你的角色图是:

3
4

就设置:

Horizontal3
Vertical4

如果每帧是 32x32,也要确认切出来的每一格正好是 32x32。

然后把对应帧放进对应动画里。

例如,假设资源排列是:

 1向下走
 2向左走
 3向右走
 4向上走

那么可以这样配置:

walk_down 1 行的所有帧
walk_left 2 行的所有帧
walk_right 3 行的所有帧
walk_up 4 行的所有帧

待机动画可以用每一行动画的中间帧:

idle_down向下行的中间帧
idle_left向左行的中间帧
idle_right向右行的中间帧
idle_up向上行的中间帧

如果一行动画是 4 帧,可以选第 1 帧或第 2 帧作为待机帧。

第五步:设置动画播放速度

角色走路动画不应该太快。

常见 FPS:

4 FPS
6 FPS
8 FPS

如果是像素 RPG,我建议先设置:

6 FPS

也就是每秒播放 6 帧。

如果太快,角色会像抽风。

如果太慢,角色会像拖着脚走。

第六步:添加 CollisionShape2D

在 Player 下添加:

CollisionShape2D

结构变成:

Player / CharacterBody2D
├── AnimatedSprite2D
└── CollisionShape2D

选中 CollisionShape2D,在 Shape 中创建:

RectangleShape2D

然后调整大小。

对于 32x32 角色,可以先用这个范围:

Size14 x 10
Position0, 8

大概让它覆盖角色脚底区域。

也可以用:

CapsuleShape2D

如果你希望碰撞更圆滑一点。

RPG 角色通常用矩形就够了。

第七步:调整 AnimatedSprite2D 的位置

这是很关键的一步。

角色图片默认是以中心点为原点显示的。

但是 RPG 游戏里,我们通常希望角色的“脚底”作为排序和站位参考。

所以你需要调整 AnimatedSprite2D 的位置,让角色脚底接近 Player 节点的原点。

比如 32x32 角色,可以设置:

AnimatedSprite2D Position0, -16

或者根据实际图片调整。

目标是:

Player 节点的原点在角色脚底附近

这样以后做 Y Sort 的时候,角色和树、石头、房子遮挡关系才会自然。

九、为什么角色原点最好放在脚底

这是 2D RPG 里非常重要的概念。

Godot 做上下遮挡时,经常会用 Y 坐标判断谁在前面。

简单说:

Y 坐标越大越靠前显示
Y 坐标越小越靠后显示

比如:

角色在树的下面角色应该盖住树干
角色在树的上面树冠/树干应该盖住角色

Godot 判断这个关系时,看的不是角色图片整体,而是节点的 Y 坐标。

所以如果角色节点的原点在身体中心,排序就容易不准确。

更合理的是:

角色节点原点 = 角色脚底位置

因为脚底才代表角色实际站在地图上的位置。

这也是为什么很多 RPG 角色会这样设计:

Player / CharacterBody2D
├── AnimatedSprite2D  向上偏移
└── CollisionShape2D  放在脚底

十、添加角色移动脚本

给 Player 挂载脚本:

res://scripts/player/player.gd

基础脚本如下:

extends CharacterBody2D

@export var move_speed: float = 100.0

@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D

var last_direction: Vector2 = Vector2.DOWN

func _physics_process(delta: float) -> void:
    var input_vector := Vector2.ZERO

    input_vector.x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
    input_vector.y = Input.get_action_strength("move_down") - Input.get_action_strength("move_up")

    input_vector = input_vector.normalized()

    velocity = input_vector * move_speed
    move_and_slide()

    update_animation(input_vector)


func update_animation(input_vector: Vector2) -> void:
    if input_vector != Vector2.ZERO:
        last_direction = input_vector

        if abs(input_vector.x) > abs(input_vector.y):
            if input_vector.x > 0:
                animated_sprite.play("walk_right")
            else:
                animated_sprite.play("walk_left")
        else:
            if input_vector.y > 0:
                animated_sprite.play("walk_down")
            else:
                animated_sprite.play("walk_up")
    else:
        if abs(last_direction.x) > abs(last_direction.y):
            if last_direction.x > 0:
                animated_sprite.play("idle_right")
            else:
                animated_sprite.play("idle_left")
        else:
            if last_direction.y > 0:
                animated_sprite.play("idle_down")
            else:
                animated_sprite.play("idle_up")

这段代码做了几件事:

读取输入方向
根据方向设置 velocity
调用 move_and_slide() 让角色移动并处理碰撞
根据方向播放对应动画
没有移动时播放对应方向的待机动画

十一、配置输入按键

上面的脚本里用到了这些输入动作:

move_up
move_down
move_left
move_right

你需要在 Godot 中配置。

路径:

Project > Project Settings > Input Map

添加:

move_up
move_down
move_left
move_right

然后绑定按键。

推荐:

move_upW、↑
move_downS、↓
move_leftA、←
move_rightD、→

这样键盘 WASD 和方向键都能控制角色。

十二、把 Player 放进地图场景

如果你已经有一个地图场景,比如:

World.tscn

结构可能是:

World / Node2D
├── GroundLayer / TileMapLayer
├── ObjectLayer / TileMapLayer
└── Player / CharacterBody2D

你可以把 player.tscn 拖进 World 场景里。

推荐结构:

World / Node2D
├── GroundLayer
├── DecorationLayer
├── ObjectLayer
├── Player
└── UI

如果你要做遮挡排序,可以再整理成:

World / Node2D
├── GroundLayer
├── YSortObjects / Node2D
│   ├── ObjectLayer
│   ├── Trees
│   ├── Stones
│   └── Player
└── UI

在 Godot 4 中,可以给父节点开启:

Y Sort Enabled

或者对相关节点设置:

Y Sort Enabled开启

这样同一个 Y Sort 分组下的节点会根据 Y 坐标自动排序。

十三、角色和地图遮挡关系怎么做

这是你之前经常遇到的问题:角色为什么会盖住树?为什么树不能挡住角色?为什么角色走到树后面没有被遮住?

核心原因通常是:

角色石头房子不在同一个 Y Sort 排序体系里

或者:

节点原点不在正确位置

对于 RPG 来说,建议这样做:

地面层不参与 Y Sort
草地装饰看情况
石头房子角色参与 Y Sort
UI不参与 Y Sort

结构示例:

World
├── GroundLayer
├── YSortLayer
│   ├── Trees
│   ├── Stones
│   ├── Houses
│   └── Player
└── CanvasLayer
    └── UI

注意:

GroundLayer 不需要参与 Y Sort
Player 需要参与 Y Sort
石头房子这些会挡住角色的对象需要参与 Y Sort

并且这些对象的原点最好都在“底部中心”。

比如树:

树的原点在树干底部

角色:

角色的原点在脚底

石头:

石头的原点在底部中心

这样排序才自然。

十四、角色移动时常见问题

1. 角色不动

常见原因:

没有配置 Input Map
脚本没有挂到 Player
CharacterBody2D 没有调用 move_and_slide()
move_speed 0
输入动作名称和代码不一致

比如代码里写的是:

move_right

但 Input Map 里写成了:

right

那就不会生效。

2. 角色动画不播放

常见原因:

AnimatedSprite2D 没有 SpriteFrames
动画名称写错
脚本里的节点路径不对
动画没有帧

比如代码里写:

animated_sprite.play("walk_down")

但是 SpriteFrames 里面动画叫:

down_walk

那就不会播放。

名称必须完全一致。

3. 角色移动方向和动画方向不一致

常见原因:

精灵图方向行数搞反了
walk_up 配成了 walk_down 的帧
walk_left walk_right 配反了

解决方式:

重新检查精灵图每一行代表的方向

不要只看资源说明,最好在 Godot 里实际播放一遍。

4. 角色走路时抖动

常见原因:

每一帧角色没有对齐
角色脚底位置不一致
AnimatedSprite2D offset 设置不合理
帧切割错了

解决方式:

确认每帧尺寸一致
确认切割网格正确
确认角色脚底对齐

5. 角色和树的遮挡关系不对

常见原因:

没有开启 Y Sort
角色和树不在同一个 Y Sort 父节点下
角色原点不在脚底
树的原点不在树干底部
TileMapLayer Z Index 设置不合理

解决方式:

 Player 和会遮挡角色的对象放到同一个 YSortLayer
开启 Y Sort Enabled
调整 Player 和对象的原点
必要时调整 Z Index

6. 角色碰撞范围很奇怪

常见原因:

CollisionShape2D 太大
碰撞框覆盖了整个身体
碰撞框位置没有放在脚底

解决方式:

缩小碰撞框
把碰撞框移动到脚底附近

十五、推荐的最终 Player 节点结构

一个比较正式的玩家角色结构可以是:

Player / CharacterBody2D
├── AnimatedSprite2D
├── CollisionShape2D
├── Camera2D
├── InteractionArea / Area2D
│   └── CollisionShape2D
└── DebugLabel / Label

其中:

AnimatedSprite2D显示角色动画
CollisionShape2D角色物理碰撞
Camera2D镜头跟随
InteractionArea检测面前的 NPC宝箱采集物
DebugLabel调试用可以以后删掉

更正式一点,可以加一个方向检测点:

Player / CharacterBody2D
├── AnimatedSprite2D
├── CollisionShape2D
├── Camera2D
├── FacingMarker / Marker2D
└── InteractionArea / Area2D
    └── CollisionShape2D

FacingMarker 可以表示玩家当前面对的位置。

比如玩家朝下时,它在角色下面;玩家朝左时,它在角色左边。

之后做交互时很好用:

 E 和面前的 NPC 对话
 E 打开面前的宝箱
 E 采集面前的植物

十六、角色交互区域怎么做

如果你希望玩家按 E 和物体互动,可以添加:

InteractionArea / Area2D

它下面也需要:

CollisionShape2D

结构:

Player
├── AnimatedSprite2D
├── CollisionShape2D
└── InteractionArea
    └── CollisionShape2D

这个区域不是用来阻挡角色的,而是用来检测附近有没有可交互对象。

比如:

NPC
宝箱

采集物
路牌

当玩家朝下时,交互区域放在角色下方。

当玩家朝上时,交互区域放在角色上方。

当玩家朝左时,交互区域放在角色左边。

当玩家朝右时,交互区域放在角色右边。

这样玩家就可以和“面前”的东西互动。

十七、角色精灵图资源的推荐命名

资源不要乱放,建议一开始就整理好目录。

推荐:

res://assets/characters/player/player_walk.png
res://assets/characters/player/player_idle.png
res://assets/characters/player/player_attack.png

如果只有一张总图,可以:

res://assets/characters/player/player_spritesheet.png

场景:

res://scenes/player/player.tscn

脚本:

res://scripts/player/player.gd

动画资源如果单独保存:

res://resources/animations/player_sprite_frames.tres

这样后期项目变大也不会乱。

十八、开发顺序建议

不要一开始就做复杂战斗、背包、换装。

角色制作建议按这个顺序来:

第一步能显示角色
第二步能播放 idle 动画
第三步能用键盘移动
第四步移动时播放 walk 动画
第五步停止时保持最后方向
第六步加入碰撞
第七步加入摄像机跟随
第八步处理 Y Sort 遮挡
第九步加入交互区域
第十步加入攻击采集对话等动作

这样最稳。

不要一口气全做,否则出问题的时候很难排查。

十九、最小可用版本

如果你现在只是想先跑起来,最小版本只需要:

Player / CharacterBody2D
├── AnimatedSprite2D
└── CollisionShape2D

脚本只需要:

extends CharacterBody2D

@export var move_speed: float = 100.0

@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D

func _physics_process(delta: float) -> void:
    var input_vector := Input.get_vector(
        "move_left",
        "move_right",
        "move_up",
        "move_down"
    )

    velocity = input_vector * move_speed
    move_and_slide()

    if input_vector != Vector2.ZERO:
        animated_sprite.play("walk_down")
    else:
        animated_sprite.play("idle_down")

这个版本虽然还没有四方向动画,但可以先确认:

角色能不能显示
角色能不能移动
碰撞有没有生效
动画能不能播放

确认没问题后,再升级到四方向动画。

二十、最终理解

通过角色精灵图制作角色,本质上是在做三件事:

第一把一张大图切成一帧一帧的小图
第二把这些帧组合成不同方向的动画
第三用脚本根据玩家输入播放对应动画并移动角色

在 Godot 里,对应关系是:

角色主体CharacterBody2D
角色显示AnimatedSprite2D
动画资源SpriteFrames
角色碰撞CollisionShape2D
移动逻辑player.gd
镜头跟随Camera2D
遮挡排序Y Sort

真正需要重点记住的是:

CharacterBody2D 负责移动和碰撞
AnimatedSprite2D 负责显示和动画
SpriteFrames 负责管理动画帧
CollisionShape2D 负责角色碰撞范围
角色原点最好放在脚底
会互相遮挡的对象要放在同一个 Y Sort 体系里

只要这套关系理解了,之后无论你换什么角色精灵图,本质流程都是一样的。

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
godot2026-07-27
Godot 4 常用 UI 节点详解
Godot 4 常用 UI 节点详解 在 Godot 4 中,UI 系统基于 Control(控件) 节点构建。所有 UI 节点都继承自 Control,形成一棵完整的 UI 树。与游戏引擎中常见的"Canvas + DOM"模式不同,Godot 的 UI 系统是声明式的——你在场景中搭好节点树,引擎自动完成布局计算。 一、布局系统:Container 家族 Container 是 Godot UI 的 骨架 。它决定了子节点的大小和位...
学习
godot2026-07-09
Godot 4 自动地形系统(AutoTileSet / Terrains)完全指南
前言 在 2D 游戏开发中,地形瓦片(tile)的拼接是一个绕不开的问题。想象一下:你有一片草地、一条河流、一段平台——如果每一块边缘、角落、过渡区域都要手动选择对应的瓦片图,工作量将是巨大的。 自动地形系统 就是为了解决这个问题而生的。 一、什么是自动地形(Autotiling)? 自动地形的核心思想很简单: 你只管画,引擎帮你选对瓦片 。 当你在 TileMap 上绘制地形时,引擎会自动检测每个瓦片的上下左右邻居,然后根据预设的规则...
学习
godot2026-06-25
Godot 中 zindex 和 ysort 的区别总结
在 Godot 2D 游戏开发中,角色、树木、怪物、地面、技能特效、UI 都需要正确的显示顺序。比如角色走到树前面时,角色应该挡住树;角色走到树后面时,树又应该挡住角色。 这种显示顺序主要和两个概念有关: 和 。 其中 用来手动控制图层顺序, 用来根据物体的 Y 坐标自动排序。 一句话理解 是手动分层。 是根据 Y 坐标自动排序。 简单来说: | 属性 | 作用 | 适合场景 | | | | | | | 数值越大,显示越靠前 | 地面、...
学习
godot2026-06-11
Tileset 资源图的标准和规范
一、什么是 Tileset 资源图 Tileset,中文通常叫“图块资源图”或“瓦片图”,是 2D 游戏中非常常见的一种地图资源组织方式。 简单来说,Tileset 就是把很多小图块按照固定尺寸排列在一张图片里。游戏引擎会按照固定的格子大小去切割这张图片,然后把每个小格子当成一个独立的地图块使用。 比如一个 32×32 像素的 Tileset 中,每一个 tile 都是 32×32 像素。地图编辑器或游戏引擎会按照 32×32 的网格,...
学习
godot2026-05-26
Godot 节点系统详细介绍
Godot 里最核心的东西不是“类”,也不是“组件”,而是 节点 Node 。 你可以把 Godot 的节点理解成: 在前端里,一个页面是由很多 DOM 元素组成的; 在 Godot 里,一个游戏场景是由很多 Node 节点组成的。 比如一个玩家角色,可能不是一个单独对象,而是这样的结构: 这里的 是根节点,下面挂着显示图片、播放动画、碰撞检测、摄像机、音效等子节点。 Godot 官方文档也把节点和场景放在一起讲:多个节点组成树状结构后...
学习
godot2026-05-19
第一部分 01:Godot 基础世界观
先建立一个总认知: Godot 做游戏的核心思路是:用一个个 Node 组成 Scene,再把 Scene 放进 SceneTree 运行。代码 Script 负责控制 Node,Resource 负责存数据,Signal 负责对象之间通信。 你可以先把 Godot 想成一个“可视化的前端工程”: | Godot | 前端类比 | 说明 | | | | | | Project | 一个前端项目仓库 | 整个游戏工程 | | Scene...
学习

评论

请登录后发表评论

去登录
加载评论中...

目录