万镜之下 2026-02-21 12:47 采纳率: 6.3%
浏览 19

unity的开发时候遇到的问题

1模块化开发是什么,搜索之后有的人的模块有接口,也有没有的,很矛盾。
2比如做个玩家类,里面有各种子系统,这叫外观模式,还是桥接,或者就时设计原则的组合大于继承
3使用状态模式时,不同状态有不同的方法,。就是说一个玩家类,然后有个状态类有个玩家类字段(状态模式),这个方法是在状态类里面还是在玩家类或其子系统里面。玩家子系统之间又是如何通信
4做个移动,高级工程师是如何开发的,是否牵扯到分层架构,模块化开发吗
5问题请您以专业工程师方向回答(因为我连第一步做什么都不知道,怕找不到专业工程师方向

  • 写回答

4条回答 默认 最新

  • Seal^_^ 优质创作者: 云计算技术领域 2026-02-22 12:34
    关注

    你提的这几个问题非常精准,正好卡在从“能写代码”到“会设计代码”的成长节点上。很多开发者走到这里都会感到迷茫,不是因为能力不够,而是因为从“实现功能”到“设计架构”之间,缺了一套系统的思考方式。

    下面我以专业工程师的视角,逐一拆解你的问题。


    1. 模块化开发:为什么有的有接口,有的没有?

    核心答案:接口是手段,解耦是目的。

    模块化开发的核心是“高内聚,低耦合”。你在搜索时看到的矛盾现象,其实是开发阶段不同导致的:

    • 有接口的模块:这是面向接口编程的体现。模块A只依赖模块B的接口,不依赖具体实现。这样你可以随时替换实现类(比如把本地存储模块换成云端存储模块),而不用改调用方的代码。
    • 没有接口的模块:可能因为:
      • 这个模块是内部工具类,确定不会被替换
      • 项目初期快速原型,还没来得及抽象
      • 模块之间已经直接依赖具体类(紧耦合,不推荐)

    专业工程师的做法:核心业务模块强制定义接口。UI模块依赖战斗模块的接口而不是具体类,这样即使战斗模块内部重写,UI也不需要动。

    2. 玩家类包含各种子系统:外观模式?桥接模式?组合大于继承?

    核心答案:这是“外观模式”的典型应用,背后是“组合优于继承”的设计原则。

    我们来区分一下这几个概念:

    概念定义在你的场景中是否适用
    外观模式为子系统的一组接口提供一个统一的、更易用的高层接口✅ 适用Player类就是那个“外观”,你把移动、战斗、动画这些子系统封装在内部,外部只需要调用Player.Move()Player.Attack(),不用关心内部有多少子系统在协作
    桥接模式将抽象部分与实现部分分离,让它们可以独立变化❌ 不适用。桥接是为了解决“多个维度变化”的问题(比如手机既有不同品牌,又有不同功能软件)
    组合优于继承设计原则,不是具体模式。指优先使用对象组合(Has-A)而非类继承(Is-A)来达到复用和扩展的目的✅ 指导思想。你的玩家类“包含”各种子系统,正是这一原则的体现

    结论:你的设计既符合外观模式(提供一个简化接口),也遵循了组合优于继承(用组合代替庞大的继承树)。

    3. 状态模式:方法放哪里?子系统间如何通信?

    3.1 方法的位置

    核心答案:与状态变化强相关的方法放在状态类里;与玩家核心属性相关的方法放在玩家类里。

    看这个标准结构:

    // 状态接口
    public interface IPlayerState {
        void Enter(Player player);      // 进入状态时执行
        void Update(Player player);     // 每帧更新
        void Exit(Player player);       // 退出状态时执行
        void HandleInput(Player player, InputType input); // 处理输入(如果需要)
    }
    
    // 具体状态类 - 移动状态
    public class MoveState : IPlayerState {
        public void Enter(Player player) {
            // 播放移动动画
            player.animator.Play("Move");
        }
        
        public void Update(Player player) {
            // 处理移动逻辑(调用移动子系统)
            player.movementSystem.Move(player.inputSystem.GetDirection());
            
            // 检测状态切换
            if (player.inputSystem.GetButton("Jump")) {
                player.stateMachine.ChangeState(new JumpState());
            }
        }
        
        public void Exit(Player player) {
            // 清理工作
        }
    }
    
    // 玩家类(上下文)
    public class Player : MonoBehaviour {
        public MovementSystem movementSystem;
        public InputSystem inputSystem;
        public AnimationSystem animator;
        public StateMachine stateMachine;
        
        private void Update() {
            stateMachine.Update(this);
        }
    }
    

    分配原则

    • 状态类里:与当前状态强相关的行为逻辑(如移动状态下怎么移动、跳跃状态下怎么跳跃)
    • 玩家类/子系统里核心能力(如移动系统提供Move()方法、动画系统提供Play()方法)
    • 状态机里状态切换逻辑

    3.2 子系统间如何通信

    核心答案:通过“事件中心”或“依赖注入”解耦,尽量避免直接引用。

    几种常见的解耦方式:

    通信方式实现适用场景
    直接引用移动系统直接调用动画系统简单项目,确定不变的依赖
    事件/消息系统移动系统抛出OnPlayerMoved事件,动画系统监听并播放动画解耦效果好,一个事件可以被多个系统响应
    服务定位器全局的ServiceLocator.Get<AnimationSystem>()方便,但隐藏了依赖关系(反模式争议)
    依赖注入在构造函数或初始化时传入依赖单元测试友好,依赖关系明确

    专业建议:在Unity中,可以创建一个事件总线(EventBus) 或使用UnityEvent来实现解耦通信。

    // 简单的事件中心示例
    public static class EventBus {
        public static System.Action<Vector3> OnPlayerMoved;
        
        public static void PlayerMoved(Vector3 position) {
            OnPlayerMoved?.Invoke(position);
        }
    }
    
    // 移动系统里触发
    EventBus.PlayerMoved(transform.position);
    
    // 动画系统里监听
    void OnEnable() => EventBus.OnPlayerMoved += UpdateAnimation;
    void OnDisable() => EventBus.OnPlayerMoved -= UpdateAnimation;
    

    4. 移动功能:高级工程师怎么开发?

    核心答案:分层架构 + 模块化 + 数据驱动 + 可测试性设计。

    高级工程师开发一个移动功能,不会只写一个Move()方法完事,而是会这样组织:

    4.1 分层架构

    典型的Unity项目分层:

    📦 表现层 (View/Presentation)
     ┣ 📜 PlayerAnimator.cs      // 动画表现
     ┗ 📜 PlayerInputHandler.cs   // 输入处理(键盘/手柄/触屏)
     
    📦 逻辑层 (Logic/Controller)  
     ┣ 📜 MovementController.cs   // 移动逻辑(状态机调用)
     ┗ 📜 PlayerStateMachine.cs   // 状态管理
     
    📦 数据层 (Model/Data)
     ┣ 📜 MovementSettingsSO.cs   // 移动参数(速度、加速度等)用ScriptableObject配置
     ┗ 📜 PlayerStats.cs          // 玩家属性
     
    📦 核心层 (Core/Framework)
      ┗ 📜 PhysicsHelper.cs       // 物理相关工具
    

    4.2 具体实现步骤(高级工程师的思考顺序)

    1. 定义数据模型:用ScriptableObject创建移动配置,让策划可以直接调参,不用改代码
    2. 实现核心逻辑:在MovementController中实现物理移动,不依赖任何输入具体实现
    3. 接入输入系统InputHandler只负责把输入转换成方向数据,传给Controller
    4. 连接动画:用事件或观察者模式,让移动状态变化时自动触发动画
    5. 单元测试:把移动逻辑写成不依赖MonoBehaviour的纯C#类,方便编写单元测试

    4.3 模块化体现在哪?

    • 移动模块可以被任何角色复用(敌人、NPC也可以挂同样的移动脚本)
    • 输入模块可以无缝替换(PC用键盘、手机用摇杆、主机用手柄,互不影响)
    • 配置模块让数据和逻辑分离

    5. 专业工程师方向:从第一步开始,我该做什么?

    你最后这句话特别重要:“我连第一步做什么都不知道,怕找不到专业工程师方向”。这说明你有强烈的成长意愿,只是缺一张路线图。下面我给你画出来:

    第一阶段:打地基(你现在可能就在这里)

    • ✅ 熟练掌握C#语法、Unity API
    • ✅ 能独立实现功能(比如你提到的玩家移动、状态切换)
    • 目标实现功能不卡壳

    第二阶段:学设计(你正在进入的阶段)

    • 📚 系统学习设计模式:不要零散搜索,建议看《设计模式:可复用面向对象软件的基础》或《游戏编程模式》
    • 📚 学习架构原则:SOLID原则、组合优于继承、高内聚低耦合
    • 🛠️ 实践:把以前写过的功能用设计模式重构一遍
    • 目标知道“为什么这么写”

    第三阶段:搭框架(专业工程师的日常)

    • 🏗️ 搭建项目框架:建立自己的通用工具库、基础模块
    • 🏗️ 引入成熟框架:学习使用Zenject(依赖注入)、UniRx(响应式编程)、DOTween(动画)等
    • 🏗️ 考虑可测试性:写代码时就想着“这个逻辑能不能脱离Unity进行单元测试”
    • 目标设计可扩展、易维护的系统

    第四阶段:带团队(资深工程师/主程)

    • 👥 制定规范:代码规范、模块划分规范、版本管理规范
    • 👥 技术选型:根据项目需求选择合适的技术方案
    • 👥 培养新人:把你的设计思想传递下去
    • 目标把控整个项目的技术方向

    你的“第一步”行动清单

    1. 本周:把你现在的玩家类重构一下,用上状态模式外观模式(把子系统封装好)
    2. 本月:买本《设计模式》或《游戏编程模式》,每天看一个模式,并在小项目中实践
    3. 本季度:尝试用MVC/MVP模式重写一个你之前做过的UI功能
    4. 长期:参与开源项目或自己从头搭一个小游戏的完整框架

    你现在的困惑,正是从“码农”走向“工程师”的必经之路。迷茫是因为你在突破舒适区。你提的这几个问题都非常有水平,说明你已经具备了工程师的思考潜力。

    如果还有具体问题(比如某个模式在Unity里怎么写),随时再问。我们一起把这条路走通。

    评论

报告相同问题?

问题事件

  • 创建了问题 2月21日