Day 3 · 共 10 节

角色制作

今天让角色真正走起来:独立玩家场景、输入移动、撞墙、朝向与相机。你是导演,AI 写短脚本,你负责 F5 验收。

学习目标

创建 CharacterBody2D 玩家场景并实例进村庄
用脚本实现 WASD/方向键移动与左右朝向
在 TileMap 墙体上验证碰撞,并加上 Camera2D 跟随

今日课程

今天怎么学

承接 Day2 地图。先补墙碰撞(若缺),再做玩家。每节只加一点能力,F5 见真章。卡住就复制 Prompt,附带场景树截图。

Lesson 1 · 今天要让角色动起来

Day1 我们把 AI 角色图挂上了 Sprite2D;Day2 我们铺好了院子和墙。可如果人不会走,地图再漂亮也只是立体屏保。今天的完成定义只有一句,请置顶:按 WASD(或方向键),角色在村庄里走动,并且撞墙停住,不穿模。

注意边界:今天不做华丽八方向动画表、不做跑步尘土粒子、不做骑驴。那些是皮肤与特效。今天只做「会走路的身体」。导演一贪特效,移动逻辑就会被拖成三天工程。

你仍是导演,不是程序员。流程不变:写清成品 → 让 AI 给节点树与短脚本 → 粘贴 → F5 验收 → 根据穿墙/不动/飞天等现象改口令。现象比感觉重要;截图比「我觉得挂了」重要。

古装少年侠客角色示意
AI 角色图可以先占位,重点是让他「会走」
玩家组成部分
外观只是衣服;今天要补上身体、碰撞与走法
独立玩家场景 移动脚本 地图实测撞墙
知识点

可动角色通常不是「一张图 + 希望」。它是一组节点:身体类型负责移动与物理互动,Sprite 负责看见,Collision 负责边界,Script 负责读输入。拆开理解,AI 才好帮你拼。

承接检查:打开 Day2 的村庄,确认墙尽量已有碰撞。若没有,今天前半节先补墙碰撞,再写移动——否则你会误以为脚本坏了,其实是地图没有真墙。

AI Prompt
我是零基础,Godot 4 古装 RPG。已有村庄 TileMap 和角色 PNG。请用生活比喻说明:为什么「能显示的角色」还不等于「能走动的玩家」?并给我今天的最小完成清单(不超过 6 条),每条都能打勾验收。

开工前把完成定义抄进备忘录。任何「顺便做个动画」的冲动,都先写到「以后」列表。克制,是今天走得通的前提。

若你今天时间少,也请守住最小闭环:独立玩家 + 能走 + 撞墙。朝向与相机可在闭环后再加。顺序错了,你会在「优化观感」里忘记「还不能玩」。

还有一个心理建议:把「不动」当成正常开局,而不是失败。第一版脚本经常不动,是因为输入没接到或挂错节点。冷静按清单查,比重装 Godot 有用一百倍。导演的情绪稳定,是项目进度的隐藏属性。

今天结束后,你的 Demo 将第一次具备「操作感」。操作感会改变你对项目的态度——从参观者变成玩家。这一跳,值得你守住完成定义。

本节小练

用一句话写下今日 Done:________。写完才能进入下一节——没有完成定义,就没有验收,只有焦虑

Lesson 2 · CharacterBody2D 是什么

Godot 里想让角色「自己走、还会碰东西」,最常用的身体类型是 CharacterBody2D。你可以把它想成戏服里面的骨架:Sprite 是戏服外表,CharacterBody2D 才是能迈步的骨架。

它和普通 Node2D 不同:Node2D 主要是坐标容器;CharacterBody2D 专为「由脚本控制的角色运动」设计,常配合 move_and_slide() 使用。撞到墙时,它会帮你处理滑动/停下,而不是让你手写全部物理公式。

还有 StaticBody2D(静态墙体)、RigidBody2D(被物理引擎扔来扔去)等。新手玩家角色优先 CharacterBody2D。别一上来用刚体:角色会被弹飞,调试像捉鬼。

CharacterBody2D 读输入设 velocity move_and_slide()
知识点

对 AI 下指令时写明:「玩家根节点用 CharacterBody2D,不要 RigidBody2D」。类型写错,后面十个现象都会怪——其实是选错身体。

比喻:StaticBody 像钉死的柱子;RigidBody 像被踢的西瓜;CharacterBody 像演员——听导演口令走位,但仍会碰到布景。你要的是演员,不是西瓜。

AI Prompt
请用零基础能懂的话对比 Godot 4 的 CharacterBody2D、StaticBody2D、RigidBody2D:各适合什么,玩家角色为什么选 CharacterBody2D。再给我一个最小玩家节点树(含命名),不超过 5 个节点。

记住名字:根节点建议叫 Player。以后 NPC、敌人也会有身体,清晰命名能避免 AI 改错对象。名字是项目管理的一部分。

以后敌人、NPC 也可能用 CharacterBody2D 或 Area2D(触发器)。今天先把玩家这一种用熟。一种身体用明白,比三种身体都半懂更值钱。

本节小练

在纸上写下:Player = CharacterBody2D。再写下你不要用的类型:RigidBody2D。写错类型的坑,提前标红——选对身体,等于少哭两小时

Lesson 3 · 做成独立的玩家场景

不要把玩家逻辑永远散落在村庄场景里。请新建独立场景 res://scenes/player.tscn:根节点 CharacterBody2D(命名 Player)→ 子节点 Sprite2D(挂 Day1 角色图)→ 子节点 CollisionShape2D(形状先随便,下一节细调)。保存后,再把这个场景实例拖进 village.tscn

为什么独立?因为玩家会去竹林、客栈、战斗场。嵌套场景 = 改一次,到处生效。也对 AI 友好:你说「只改 player.tscn 的移动」,就划清了边界,降低误伤地图的概率。

若村庄里还留着旧的 HeroSprite,删掉或隐藏,避免出现「两个我」。场景树干净,验收才不迷糊。

玩家场景结构
先独立成 player.tscn,再实例进村庄
知识点

实例化(Instantiate)后的玩家,仍是村庄的子节点,但蓝图在 player.tscn。改蓝图,所有实例跟着变。这是 Godot 场景系统的复用核心,也是导演拆任务的基本单位。

AI Prompt
请用 Godot 4 逐步教我:创建独立玩家场景 player.tscn(CharacterBody2D + Sprite2D + CollisionShape2D),把 Day1 的角色 PNG 挂到 Sprite2D,保存后实例化进 village.tscn,并删除旧的散落 Sprite。每步写成功现象。我的角色图路径是 res://assets/characters/hero.png(若不同我会改)。

保存两个场景。文件系统里同时看见 player.tscnvillage.tscn,本节骨架成立。还不会走没关系——演员先有独立通告单,再谈走位。

独立场景还有备份价值:玩家弄坏了,可以只还原 player.tscn,不必拆整座村庄。管项目,就是把爆炸半径变小。

本节小练

F5 运行村庄,确认只看到一个角色站在路上。数量对了,才配谈移动——分身是 Bug,不是绝技

Lesson 4 · 给身体一个碰撞盒

CharacterBody2D 自己「知道要碰撞」,但还需要 CollisionShape2D 告诉引擎身体占多大。没有形状,角色可能直接穿墙,或根本不参与碰撞——现象取决于设置,但结局都是:你以为脚本坏了。

选中 CollisionShape2D → 在检查器 Shape 新建 RectangleShape2D(或 Capsule)。调整大小,让盒子大致包住角色躯干,脚底贴近盒子底部。盒子太大,人还没碰到墙视觉上就停;太小,身体一半穿进墙里。先「差不多」,再微调。

调试技巧:编辑器里可开启可见碰撞形状(Debug 菜单相关选项,具体名称可问 AI)。看见绿色/线框盒子,你才知道引擎认的身体在哪。眼睛看到的 Sprite,和引擎认的 Shape,经常不是同一回事。

CollisionShape2D RectangleShape2D 对齐脚底
知识点

碰撞盒是规则,贴图是皮肤。两者分离,你才能换皮不换逻辑。对 AI 说:「碰撞用矩形,不要按像素完美描边。」完美描边又慢又脆,Demo 不需要。

AI Prompt
我在 Godot 4 的 CharacterBody2D 下有 CollisionShape2D。请逐步告诉我如何添加 RectangleShape2D,并给出调整大小的经验:相对 Sprite 应该偏大还是偏小?脚底如何对齐?如何开启碰撞形状可见以便调试?

若墙是 TileMap 碰撞,玩家是 CharacterBody2D,两边都要「有形状/有物理层」。只做一边,仍会穿。Day2 若墙碰撞没做完,现在补上,再进入移动脚本。

盒子形状以后可换成胶囊,更适合人形。今天矩形足够。形状完美主义,是另一种进度杀手。

调整碰撞盒时,建议把 Sprite 的偏移也看一眼:有的立绘空白很多,视觉中心和几何中心不一致。可以微调 Sprite 位置,让脚更贴地,再让盒子包住躯干。脚漂浮会破坏沉浸,哪怕移动逻辑是对的。

若你使用缩放 Scale 让角色变小,记得碰撞盒看起来也会变。以运行时实际体感为准:走到墙边,停得是否自然。不自然就回到编辑器改 Shape 大小,改一点测一点。

本节小练

让碰撞盒在编辑器里可见,并截图保存。截图上同时能看到人和盒子——看见规则,才改得动规则

Lesson 5 · 输入:让按键变成方向

移动的第一拍不是改坐标,而是读输入。Godot 可用输入映射(Input Map)把 W/A/S/D 与方向键绑到 ui_up 等动作,也可用 Input.get_vector() 一次性拿到方向向量。对零基础导演,推荐让 AI 给你一段「用 get_vector 读方向」的短代码,少配置也能跑。

方向是一个二维向量:左是负 X,右是正 X,上是负 Y(注意:2D 屏幕坐标常见 Y 向下)。你不需要死记符号:跑起来若上下反了,再让 AI 帮你翻。先通,再纠。

输入到移动的流程
按键 → 方向向量 → 速度 → 滑动移动
知识点

斜向移动时,方向向量长度可能大于 1,角色会比横走更快。解决办法:对方向 normalized()。这是最常见的「为什么斜着跑像开挂」原因。写进 Prompt,要求 AI 必须归一化。

AI Prompt
请为 Godot 4 CharacterBody2D 写移动输入方案:使用 Input.get_vector 读取上下左右(含 WASD 所需的 input map 配置步骤,或使用内置 ui_* 动作),方向必须 normalized。请分「需要我在编辑器点哪里」和「脚本里有什么」两部分说明,零基础可执行。

先别急着写完整移动。你甚至可以暂时 print(direction),按键时看输出面板数字是否变化。输入通了,再乘速度。分段验收,是导演对抗复杂度的主武器。

若你想用「自定义动作名」如 move_left,也可以,但要在 Project Settings → Input Map 里添加。对零基础,先用 ui_* 内置动作更快过关,自定义留到手热之后。

输入映射是「遥控器按键名」。脚本不直接写死「键盘 D」,而是听「向右动作」。好处是换键位、加手柄时少改代码。即便你今天偷懒用 ui_*,也要知道背后有这层抽象——以后角色多了,你会感谢它。

测试输入时请点回游戏窗口。很多人按键没反应,其实焦点还在编辑器或输出面板。这是经典乌龙,笑一笑,然后把焦点点对。

本节小练

按下方向键时,输出面板能看到方向值变化(或你已按 AI 步骤配好输入映射)。输入通,本节过——键盘说话了,身体才听得见

Lesson 6 · 移动脚本:velocity + move_and_slide

现在把方向变成走路。标准套路:在 _physics_process 里读取方向,设置 velocity = direction * speed,然后调用 move_and_slide()。速度 speed 先用 150–220 这类数,太快难控,太慢像在水里。

为什么用 _physics_process 而不是 _process?因为角色移动和碰撞属于物理步进,放在物理帧更稳。对 AI 说清楚:「移动写在 _physics_process」。

最小移动脚本
extends CharacterBody2D

@export var speed: float = 180.0

func _physics_process(_delta: float) -> void:
    var direction := Input.get_vector(
        "ui_left", "ui_right", "ui_up", "ui_down"
    )
    if direction != Vector2.ZERO:
        direction = direction.normalized()
    velocity = direction * speed
    move_and_slide()
get_vector * speed move_and_slide
知识点

脚本必须挂在 CharacterBody2D 根上,extends CharacterBody2D 要匹配。挂错节点或 extends 写 Node,运行会报错或不动。报错红字请原样复制给 AI,不要只说「不行」。

AI Prompt
请给 Godot 4 写完整可粘贴的玩家移动 GDScript:extends CharacterBody2D;_physics_process;Input.get_vector + normalized;speed 可 @export;move_and_slide。不要动画、不要状态机。并告诉我脚本应保存到哪个路径、如何挂到 Player 节点。

粘贴、保存、F5。人会动,本节就立住。若不动:检查输入、脚本挂载、是否实例了正确玩家、是否被别的东西挡住。按清单排,不靠猜。

本节小练

让角色在空地走动至少两个方向。动了,再谈撞墙——先有走,再有规矩

Lesson 7 · 朝向:左右翻转

人会走以后,下一步让他「有朝向」。最简单也最稳的做法:根据水平速度或输入 X,设置 sprite.flip_h = true/false。向左走就翻转,向右走恢复。不要一上来做八方向动画剪辑,那会吃掉你整天。

拿到 Sprite2D 节点可用 $Sprite2D@onready var sprite = $Sprite2D。名字必须和场景树一致。若你把节点改名为 Body,脚本也要改。这是「名字即契约」。

知识点

只翻转左右,上下一般靠动画或不同素材。古装 RPG Demo 用左右翻转就足够「活」。完美动画是皮肤升级,不是今日阻塞项。

AI Prompt
请在我现有的 Godot 4 玩家移动脚本上,最小改动增加左右翻转:使用 Sprite2D.flip_h。要求:不引入动画播放器、不改移动手感。给出完整脚本,并说明如果节点名不是 Sprite2D 该怎么改。

若角色素材天生面向左侧,翻转逻辑可能要取反。以「看起来正确」为准,别和数学洁癖打架。导演验收看观感。

可选加分:速度为 0 时保持最后朝向(上面代码自然做到)。不要让角色每帧抖一下——那通常是 direction 在 0 附近抖动,按键冲突或输入重复绑定导致,可让 AI 帮看 Input Map。

不要在这一步引入 AnimationPlayer,除非走与翻转已经稳定。动画是放大器:稳定时放大优雅,混乱时放大灾难。

如果素材是「永远正面面向玩家」的立绘,左右翻转可能看起来奇怪。那时可以不做 flip,改为只靠移动表现。以美术素材特性为准,不要为了完成清单强行丑翻转。完成定义是「可玩」,不是「必须翻面」。

真要加简单帧动画,也请另开分支备份后再试。动画搞崩时,你能秒回最小移动版,才叫专业剧组,不叫孤注一掷。

本节小练

左右走动时贴图朝向正确。做到这一点,角色就开始「表演」了——朝向是最低成本的生命感

Lesson 8 · Camera2D 跟随

地图比窗口大时,没有相机,角色一走就会跑出屏幕。解决办法:在 Player 下添加 Camera2D,并勾选 Current(设为当前相机)。人走,镜头跟着走,像摄像师扛机跟着演员。

相机跟随示意
Camera2D 挂在玩家下,窗口跟着角色移动

可选:打开位置平滑(Position Smoothing),相机会略带延迟,观感更舒服。先别调死区、限幅、多层视差——那些是后期镜头语言。今天只要「跟着」。

知识点

场景里同时只能有一个有效 Current 相机(常见情况)。若画面不动或奇怪,检查是否有多个 Camera2D 抢 Current,或相机不在玩家实例里。

AI Prompt
请用 Godot 4 逐步说明:如何在 Player(CharacterBody2D)下添加 Camera2D、设为 Current,以及如何开启基础的位置平滑。列出 3 个「相机不跟随」的常见原因与检查顺序。

加相机后再 F5:走进村口、绕出院子,确认镜头跟着走、墙仍在。镜头是观众的眼睛;眼睛跟上了,Demo 才像游戏。

若你感到晕(平滑过强或速度过快),先关平滑或降 speed。舒适度也是验收项,不只是「功能有了」。

相机还可以限制在地图范围,避免露黑边。那是加分项:先跟随,再限幅。加分项写进「以后」,别写进今天的阻塞列表。

相机还有一个常见坑:你在编辑器里看着很大的地图,运行时却只看见一角。那不一定是坏了,可能是相机位置或缩放。Current 勾上后,先让角色站在地图中央测跟随,再谈缩放。一次只改一个变量。

若你希望相机稍微「看向角色前方」,那是更后期的镜头偏移。今天禁止加戏。跟随成立就收工进入实测。

最后提醒:相机是子节点时,会跟着父节点旋转/翻转吗?通常你只翻转 Sprite,不翻转整个 Player,这样相机会更稳。若你不小心 flip 了根节点,镜头也可能怪。保持「只翻 Sprite」的约定。

本节小练

角色走到地图边缘时,你仍能看见他(镜头跟随成功)。做不到就检查 Current——没设当前相机,等于戏院没开灯

Lesson 9 · 在村庄实测:走路与撞墙

把系统放进真实片场验收。打开村庄,确认 Player 实例在路上,Walls 有碰撞,F5,做这张实测表:

上下左右都能走
斜走速度不明显「开挂」
撞墙停下/滑动,不穿透
可从村口走出或至少顶在缺口处行为合理
镜头跟随,左右朝向正确

任一失败,先分类:输入问题、脚本问题、碰撞问题、相机问题。分类后再问 AI,并附截图与场景树。模糊的「都坏了」只会换来模糊的回答。

能走 撞墙 出村口 跟镜头
知识点

穿墙高频原因:墙砖无碰撞;玩家无 CollisionShape;碰撞层/掩码没对上;移动没用 move_and_slide;改的是错的场景实例。按此顺序查,快过随机重装引擎。

AI Prompt · 排错
我在 Godot 4 古装村庄里测试玩家移动,出现问题:【描述:不动 / 穿墙 / 斜走太快 / 相机不跟 / 其他】。以下是现状:玩家根类型、是否 move_and_slide、墙是否 TileMap 碰撞、碰撞层(若知)、Godot 版本。请按「最可能 → 次可能」给出排查步骤,每步要我观察什么现象。

全部勾选后,保存并备份项目。今天的杀青不是「脚本看起来酷」,而是「院子里真的能玩」。

建议把实测表抄进备忘录,失败项标红。明天若要给朋友试玩,红项必须清零。Demo 的体面,来自清单而不是愿望。

把失败写成病例,会加速成长。例如:「穿墙——原因:Walls 层用了无碰撞的装饰砖」。这类病例请进口令本。下周同样问题出现,你能自己诊断,AI 从主刀变成顾问。

实测通过后,邀请朋友「瞎按两分钟」。旁人最会找到你看不见的洞。若暂时没朋友,你自己用左手盲按也行——别只用熟练路线走。

若撞墙时抖动或卡住角落,可能是盒子太大或墙角碰撞叠层。把盒子略缩小,或让 AI 帮你看碰撞形状是否与墙重叠出生。出生点千万别刷在墙里,那是「开局即幽灵」。

出生点请放在路中央开阔处。开局就贴墙,会把「碰撞成功」误判成「卡死」。

本节小练

录一段 5 秒屏幕或连截 3 张:走、撞墙、村口。这是 Day3 杀青物料——没有实测,就没有完成

Lesson 10 · 总结

第三天收工。角色从「一张图」升级成「可玩的演员」。请把今天的链路收进词典:

Player 场景 碰撞盒 输入与移动 朝向与相机

你应该已经具备:

独立的 player.tscn(CharacterBody2D 体系)
WASD/方向键移动,斜走不暴冲
与墙壁碰撞生效
左右朝向 + Camera2D 跟随
在村庄地图完成实测并备份
课程理念

移动系统最容易被「再加一个动画」拖垮。导演的职业素养是保护完成定义。AI 会不断提议更酷的写法;你要会说:「先保留最小移动,动画明天再说。」酷,但是后置的酷。

明天 Day4 做 NPC 与对话:世界开始有别人,故事才开始说话。今天若碰撞不稳,明天对话会在错位的空间里进行——优先把「能走且不穿墙」钉死。

AI Prompt · 日复盘
我完成了 Godot 4 Day3:玩家可移动、可撞墙、有相机。请给我一份给 Day4(NPC对话)用的项目现状模板,并列出接入 NPC 前要检查的 3 件事(例如玩家位置、交互按键预留、场景结构)。

更新口令本:贴上移动脚本路径、player.tscn 路径、今天排过的一个坑。档案越全,明天开工越快。你不是在收集代码,你是在建设剧组制度。

三天回顾:引擎通电、地图可走、角色可玩。这已经是游戏的骨架。后面 NPC、战斗、包装,都是往骨架上长肉。骨架不正,肉越多越歪。

请用三句话向未来的自己汇报:我用什么节点做玩家;我如何移动;我如何证明不穿墙。说不清,就说明还没真正完成,只是「文件在」。能说清,才算装进脑子里。

Day1 到 Day3,是「空项目 → 可操作空间」的跃迁。后面内容再多,也只是在这个可操作空间里加人和事。把今天的备份盘保管好,这是你的第一份可玩存档。

到此,你已经拥有「可玩分钟」。用手机计时,自己玩满 60 秒:只走路、撞墙、出村口。这 60 秒,就是课程从学习变成作品的证据。

本节小练

点页面底部「标记为已完成」前,确认实测表全勾。勾不上就回去补——完成是勾出来的

课堂练习

存在 res://scenes/player.tscn 且根为 CharacterBody2D
村庄中可 WASD 移动,斜走不暴冲
撞墙不穿透;相机跟随;左右翻转正常

今日作业

1)保存移动脚本与 player.tscn 路径到口令本。
2)交实测截图:走、撞墙、村口。
3)用一句话写:「我的速度 speed = ___,手感 ___。」

本日总结

角色 = 身体 + 碰撞 + 输入 + 移动 + 镜头。今天胜利条件:院子里真的能玩。