前言:
- 我是根据b站上的视频进行学习,并且总结写下笔记,然后做此分享。笔记非常详细以至于你可以通过查看文章进行快速学习并且制作出游戏出来。当然视频学习的链接我也放在下面了:
- 视频学习:www.bilibili.com/video/BV1Nd…
- 音频/美术资源包下载: pan.baidu.com/s/1mY05SbG3…
完成目标:
重构角色架构,实现“角色基类 + 状态驱动移动”,让玩家与敌人共用逻辑,结构更清晰。
一、创建角色基类
- 新建
base_character.gd - 继承 2D 物理角色类
- 添加
class_name方便继承 - 把玩家和敌人共有的代码移动到这里
效果:
公共功能统一管理,避免重复代码。
二、让玩家继承基类
- 修改玩家脚本继承
base_character - 删除重复代码
- 修正报错
- 把输入逻辑移到
_unhandled_input()
原因:
敌人不需要输入逻辑,所以输入代码只属于玩家。
三、状态访问角色
在 State.gd 中:
- 添加变量
character
在 state_machine.gd 的 _ready() 中:
- 遍历所有状态
- 给每个状态赋值
character
效果:
状态可以操作角色(比如访问 velocity)。
四、在状态中重写函数
在 Idle 和 Run 状态中:
- 重写
UpdatePhysics() - 使用
super()先调用父类方法 - 再写自己的逻辑
原因:
保证父类中的基础逻辑不会丢失。
五、实现状态驱动移动
Idle 状态
- 如果检测到有输入 → 切换到 Run
Run 状态
- 添加速度、加速度常量
- 把玩家脚本中的移动代码移到这里
- 通过
character.velocity操作角色 - 如果输入为 0 → 切回 Idle
最终效果
现在系统结构是:
- BaseCharacter → 处理公共逻辑
- Player → 处理输入
- StateMachine → 管理状态
- Idle / Run → 控制行为逻辑
角色移动不再写在玩家脚本里,
而是由“状态”决定。
架构正式升级为:
可扩展、可复用、清晰分层的角色系统。
实现过程:
- 玩家和敌人的角色控制脚本有很多共通之处,所以我们可以做一个基础的类去进行复用 ,我们将在基础角色类中处理大部分功能,然后玩家脚本和敌人脚本将继承这个基类。
- 首先我们右键点击脚本文件夹新建一个脚本 ,因为玩家和敌人都是2d物物体,所以我们继承的类也是就是2d物理物体,然后重命名为base_character.gd
- 接着创建类名,让别人可以进行继承,这个类名将被玩家脚本和敌人脚本进行继承使用
- 接着我们去玩家脚本移动一些代码到这里来成为公共的代码,笔者这里那个按ctrl进行拖动的2d动画精灵节点那行代码之前文章没放,这里要注意一下,按照图片中的来就对了
- 然后我们回到玩家脚本中进行修改一下代码,将打叉都删除掉,另外2行红色的直接注释掉
- 然后更好什么继承的基类,继承那个基础的角色类
- 然后敌人是不需要进行输入操作的,所以我们在玩家脚本中,将输入操作构建一个新的函数来进行实现_unhandled_input,当引擎检测到有输入未被其他任何地方处理时,就会调用这个函数。让我们把输入方向相关的代码从物理处理函数移到未处理输入函数中,以及删掉之前的那个函数,并且在目前的事件参数前加一个下划线
- 然后我们打开空闲状态的脚本,让我们重写状态类中的物理更新函数,我们去状态脚本那里把物理更新原始函数函数复制过来。大多数情况下当我们重写自己的函数时,我们需要先调用原始函数,因为很可能原始函数中还有其他操作。如果我们不先调用原始函数,那么原始函数中的那些操作就无法生效
- 这里我们可以通过一个名为super的属性来调用原始更新物理函数,Super代表这个脚本所继承的状态类
- 另外我们的更新函数也需要拿出来,所以也是同样的
- 然后我们去状态脚本那里添加一个变量来帮助我们进行获取角色,让我们转到状态脚本,声明一个名为character的变量
- 然后我们转到状态机脚本,为所有状态脚本进行初始化这个character的变量。我们在ready函数中的for in循环中完成这个操作
- 然后我们回到这个空闲状态脚本中,来进行更新物理函数,根据是否有输入来判断是否进行切换状态,这里进入奔跑状态
- 然后我们到奔跑状态的脚本中进行编写内容,首先我们需要速度和加速度常量,我们去玩家脚本中将其剪切出来,粘贴到这个奔跑状态中‘
- 然后我们来更新物理函数,另外就是重复上一个状态的操作也是需要进行调用原始函数里面的操作
- 然后我们到玩家脚本中,将移动的代码进行剪切到这个奔跑状态中来
- 然后我们会发现变红了,这个是因为velocity是玩家节点的一个属性,所以我们要在character变量上调用它
- 然后我们还需要能从奔跑状态切换回空闲状态,判断角色的输入方向是否为0,为0就是没有输入就是变为空闲状态