第 44 章 UI 框架与工程化:把界面和逻辑解耦

第 35 章那张全景图里,模块八”UI 与工具链 / 工程化”被打成”全缺”——原文写的是”UI 框架 0、编辑器扩展 0、CI/CD 0,工程化全缺。主程很大一块工夫花在’让团队跑得动、出得了包’“。今天这一章,就把这块也补上一截。

你可能心想:“UI 不就是拖几个按钮吗,我第 18 章 Canvas/Image/Text/Button 都见过了,还要单开一章?” 我得先泼盆冷水:第 18 章你看到的是”组件长啥样”,那是零件;今天你要学的是”怎么用这些零件搭出一套不糊、不乱、改得动的界面系统”,以及更关键的——“主程怎么让一帮人协作、稳定地把包出出来”。界面组件谁都能拖,但一个二十个界面、上百个按钮的项目,如果没框架、没工程化,三个月后就是一锅粥,谁都不敢动谁的代码。

我照样走老路:现象 → 现实问题 → 工程师方案 → 落进 Unity 成了什么。你写 Go 的后端经验,这章能用的地方比你想的多——UI 解耦像前后端分离,编辑器工具像你写的内部运维脚本,CI 出包就像你那条 Go 构建流水线。我们一层层来。


44.1 为什么要懂 UI 框架:游戏一半交互在”界面”里

先纠正一个常见错觉:很多人觉得”游戏是 3D 世界,UI 只是边角”。错了。你细数一个策略游戏(就是你那个塔防/大富翁)里的交互——主菜单、登录框、选关界面、商店、血条、金币显示、技能栏、暂停面板、结算页、排行榜、弹窗公告……一半以上的”玩家操作”发生在 2D 界面上,不是在 3D 世界里。一个塔防,你点”建塔”是点 UI 按钮,不是钻进 3D 里去摆;你看自己剩多少血是看 UI 血条,不是凑近角色看它脸色。

现实问题:如果界面和游戏逻辑”焊死”在一起——按钮的点击事件里直接写了一堆”扣金币、生成塔、播特效”的代码,界面一多(20 个面板),逻辑就散落得到处都是。策划想改”点建塔后先弹个确认框”,你得去扒按钮代码;美术想换个布局,一动就怕把逻辑弄挂。界面和逻辑耦合,是项目变烂的第一推手。

工程师的方案:用一套 UI 框架,把”界面长啥样(显示)“和”数据怎么变(逻辑)“分开。Unity 内置的 UI 系统叫 UGUI(你第 18.11 节见过的 Canvas + Image/Text/Button/Slider 那一套就是它),它本身是”零件库”;我们要在上面建立”框架层”——界面怎么组织、怎么打开关闭、显示怎么跟着数据走。这是本章 44.2–44.3 的主线。

连回第 18 章:18.11 节说”游戏里所有 2D 界面都是 UI 组件,和 3D 世界的渲染是两套体系”。今天在它之上加”框架思维”——零件你会了,现在学怎么组装不散架。

举个你会立刻懂的事故:没有框架时,策划要让”商店里点购买后先弹个二次确认框”。你翻开那个购买按钮的代码,发现里面硬写着”扣金币、扣库存、生成道具、播特效、关商店”一整条——逻辑和界面焊死。为了加确认框,你得先把这坨拆开、把”真正扣”挪到确认之后,稍不留神”生成道具”在确认前就跑了,玩家没确认白拿东西。一个看似简单的需求,因为耦合变成高危手术。解耦后,按钮只发”我想购买”的信号,确认框是独立面板,扣钱是逻辑层的事——加确认框只是”在信号和扣钱之间插一步”,零风险。这和你后端”在 Controller 里直接写 SQL” vs “Controller 调 Service、Service 落库”的差别,一模一样:分层不是为了好看,是为了”改一处不炸别处”。

反问:你写 Go 后端时,绝不会把”渲染 HTML”和”业务计算”写在一个函数里(你用 MVC/分层)。那游戏里”点按钮扣金币”如果按钮事件里直接 gold -= 100 还顺手 Instantiate(tower),和后端哪种坏味道一样?这问通到 44.3 的解耦。


44.2 UGUI 结构:画布、矩形变换、锚点,以及为什么”锚点”是命脉

第 18 章你扫过组件,这里把它们串成”结构”,并讲清一个新手必栽的坑——锚点(Anchor)。

Canvas(画布):所有 UI 的”舞台”。 你第 18.11 节见过。它是 UI 的根容器,所有按钮、文字、血条都挂在它下面。Canvas 有个关键参数 Render Mode(渲染模式):Screen Space - Overlay(画在屏幕最上层,不管 3D 世界)、Screen Space - Camera(跟着某台摄像机,可做”血条贴在 3D 角色头上”的混合 UI)、World Space(UI 本身就是 3D 世界里的物体,比如游戏内的告示牌)。连回第 7 章摄像机——UI 最终也得”被某台摄像机/某层渲染”才能被看到,只是 UI 通常用自己的那套屏幕坐标,不进 3D 深度。

RectTransform:UI 专用的”Transform”。 普通 3D 物体用 Transform(位置/旋转/缩放,第 2/17 章)。但 UI 元素活在”屏幕矩形”里,所以它用的是 RectTransform——除了位置旋转缩放,还多了 anchoredPosition(相对锚点的偏移)、sizeDelta(尺寸)、anchorMin/anchorMax(锚点范围)、pivot(自身旋转中心,元素绕哪点缩放/旋转,比如血条从左端增长就把 pivot 设在左)。你可以把它理解成”专门伺候矩形界面的增强版 Transform”。

锚点(Anchor)——为什么说它是命脉? 这是新手最容易翻车的概念,我多讲几句。手机/平板的屏幕分辨率千奇百怪(iPhone 的 19.5:9、平板的 4:3、安卓一堆比例)。如果你的按钮”死定位”在”距左边 100 像素、距顶 50 像素”,换台更窄的手机,按钮可能跑到屏幕外面或被挤变形。锚点就是”告诉 UI 元素:你相对于父级矩形的哪条边对齐”。 比如你把按钮的锚点设成”右下角”,那无论屏幕多宽多高,它永远贴着右下角、跟着变;设成”横向拉伸”,它就在父级宽度变化时自动拉宽。类比你写前端 CSS 的 flex/百分比布局——锚点就是 UI 的”响应式布局开关”。不做锚点适配,你的游戏在 A 手机漂亮、在 B 手机一塌糊涂,这是上线必踩的坑。

Image / Text / Button / ScrollRect:四类主力零件。

  • Image:显示一张图(图标、底框、血条底)。参数 Sprite(用哪张图)、Color(染色)、fillAmount(配合血条,控制”填满多少”,0–1)。
  • Text(新版 TextMeshPro 更清晰):显示文字。参数 text(内容)、fontSize、color。
  • Button:可点按钮。它身上挂着 OnClick 事件列表(点它触发哪些函数),这是 44.3 解耦的关键接口。还有 Transition(点下去高亮/变色的反馈,关乎”手感”)。
  • ScrollRect:滚动列表(背包、排行榜、聊天)。内容多时滚动显示,省得全堆屏上。

落进引擎成了什么:UGUI 给你一套”屏幕空间里的零件 + 矩形变换 + 锚点系统”。你第 18.11 节说”UI 和 3D 渲染是两套体系”——具体说就是:3D 走网格+摄像机投影(第 4/7 章),UI 走 Canvas + RectTransform 这套屏幕矩形体系,互不干扰。

Canvas Scaler:锚点是”单元素对齐”,Scaler 是”整块画布怎么缩放”。 光设锚点还不够。屏幕分辨率从 1280×720 到 2778×1284(旗舰手机),UI 整体放多大?Canvas Scaler 组件(挂在 Canvas 上)管这件事,三种模式里最常用的是 Scale With Screen Size:你设一个”参考分辨率”(比如 1920×1080),引擎按”当前屏幕 / 参考分辨率”的比例,整体缩放 UI。配合锚点,UI 既”整体跟着分辨率缩放”,又”单个元素贴对边角”。这就像你前端设 viewport + rem 基准,整页随屏缩放、内部用相对单位——同源思想。主程上线前必调这一项,否则不同手机 UI 大小参差。

布局组(Layout Group):让一堆元素自动排。 单个按钮用锚点;一整排按钮、一个网格背包、一个自适应列表,手动摆锚点会累死。Unity 给了三个”自动排布”组件:HorizontalLayoutGroup(横着排)、VerticalLayoutGroup(竖着排)、GridLayoutGroup(网格排,背包/商城标配)。你挂上它,往里塞子元素,它们自动等距排列、随父级尺寸变化重排。类比你前端 flexbox 的 flex-direction: row/column 和 grid——UGUI 的布局组就是游戏里的 flex/grid。学会它,做”商店一排商品""设置页一列开关”才不痛苦。锚点管”单体贴哪边”,布局组管”一群怎么排”,两者配合才是完整自适应。

反问:你前端写 CSS 时,fixed 定位和 flex 自适应布局的区别,是不是正好对应 UI 里”死定位 vs 用锚点/布局组自适应”?如果你把游戏所有按钮都写死像素坐标、不用 Scaler,上线到异形屏手机会怎样?这问让你记住锚点+Scaler 不是”可选项”,是”上线刚需”。


44.3 UI 与逻辑解耦:按钮只发”意图”,数据在别处

回到 44.1 那个坏味道。怎么解?两板斧:事件通信 + MVC/MVVM 思想。

第一板斧:Button.onClick 事件(连回第 17 章事件通信)。 第 17 章我讲过 Unity 的”事件/消息”通信思想——组件之间别硬引用,用事件通知。Button 天生带 OnClick:你在 Inspector 或代码里把一个函数挂上去,点按钮时它就被调用。关键是:按钮只负责”我被点了,发出一个信号”,至于点了之后干啥,交给外部逻辑。

using UnityEngine;
using UnityEngine.UI;
 
public class ShopUI : MonoBehaviour {
    public Button buildTowerBtn;   // 拖一个 Button 进来
    public Text goldText;          // 显示金币的文字
    private int gold = 500;        // 金币"数据",属于逻辑层,不在 UI 里算
 
    void Start() {
        // 按钮点击 -> 调用 OnBuildClicked(按钮只发信号,不关心具体怎么建)
        buildTowerBtn.onClick.AddListener(OnBuildClicked);
        RefreshGoldText();         // 初始刷新一次显示
    }
 
    void OnBuildClicked() {
        int cost = 100;
        if (gold >= cost) {
            gold -= cost;          // "逻辑"在这里:扣金币(真实项目这应走服务端权威,见第 19 章)
            RefreshGoldText();     // 数据变了 -> 通知 UI 重新显示
            // 真正建塔的逻辑可以发事件/调用别的系统,UI 不亲自 Instantiate 塔
        } else {
            // 钱不够:UI 只管显示"提示",不亲手处理建塔失败的业务
            Debug.Log("金币不足");
        }
    }
 
    void RefreshGoldText() {
        goldText.text = "金币:" + gold;   // UI 只做一件事:把数据画出来
    }
}

第二板斧:MVC / MVVM 思想。 这是你后端最熟的词(Model-View-Controller)。搬进游戏 UI:

  • Model(数据):金币数、血量、塔列表——游戏的”真相”,存在逻辑层(最好连回第 19 章服务端权威的那套)。
  • View(界面):Canvas 上的 Image/Text/Button,只负责”长啥样、显示啥”。
  • Controller / ViewModel(中介):把 Model 的变化同步给 View,把 View 的操作(点按钮)翻译成对 Model 的修改。

落进上面那段代码:gold 是 Model,goldText 是 View,OnBuildClicked + RefreshGoldText 是轻量 Controller。铁律:View 不反向算业务逻辑。 按钮点了 → 改 Model → Model 变了 → 刷新 View。单向数据流,干净。你后端”Controller 调 Service 改数据库,再返回数据给模板渲染”——一模一样。MVVM 只是再把”View 自动绑定 Model”做得更自动(WPF/前端 Vue 那套),思想同源。

为什么非解耦不可(主程视角):一个二十界面项目,解耦后——美术改布局,只动 View 的 RectTransform/锚点,不动逻辑;策划加个”确认弹窗”,只在 Controller 插一步,不动显示;程序修”扣金币算错”,只改 Model 那行,不碰 UI。三拨人互不踩脚。反过来耦合的项目:改个按钮位置可能顺手把”建塔”弄没了,谁都不敢动。你写 Go 深受”分层”之恩,游戏 UI 同理。

连回第 17 章:事件通信那套(组件间用事件而非硬引用)正是解耦的底层机制——Button 发 onClick、别的系统订阅,大家通过”事件总线”对话,不互相 new 对方。第 17.4 节的”事件/消息”通信,在这里是 UI 解耦的骨架。

界面栈(UI Manager):二十个面板怎么不打架。 上面讲”单个界面内”的解耦。但真实游戏有几十个面板:主菜单、设置、商店、暂停、结算、弹窗……它们要”打开/关闭/互斥/叠加”。如果哪里需要弹窗就 Instantiate 一个、用完就 Destroy,代码会散得到处都是,还容易”弹窗叠弹窗关不掉”。工程师的解法是做一个 UIManager(界面管理器):所有界面预制体(Prefab)登记在一张表里,用 Open("Shop") / Close("Shop") 统一开关;它内部维护一个”栈”——后开的盖在上层,关掉回到下层(就像你浏览器前进后退的页面栈,或你后端”中间件调用栈”)。伪代码思路:

public class UIManager {
    Dictionary<string, GameObject> panels = new Dictionary<string, GameObject>();
    Stack<string> openStack = new Stack<string>();   // 打开顺序栈,管"返回"去哪
 
    public void Open(string name) {
        // 从 Resources/Addressables 加载预制体(连 43.4 / 39 章资源管理),挂到 Canvas 下
        GameObject go = Object.Instantiate(panelPrefab[name], canvas);
        panels[name] = go;
        openStack.Push(name);
    }
    public void Close(string name) {
        Object.Destroy(panels[name]);
        panels[name] = null;
        // 栈顶弹出,逻辑上"回到上一个界面"
    }
}

为什么主程要它:它把”界面生命周期”收口到一个地方,配合 MVC,整套 UI 才成”框架”而非”一堆散面板”。第 35 章模块八写的”UI 框架(UGUI / 数据驱动 UI / 界面栈)“——这 UIManager + 栈 正是”界面栈”那半句的具体落地。你后端”路由表 + 中间件栈”管理请求生命周期,和这管理界面生命周期,是一个脑子。

反问:上面代码里 gold -= cost 写在客户端。如果这是联网塔防,这行该留客户端还是移回服务端(第 19 章)?UI 解耦和”服务端权威”是两个独立维度吗,还是后者约束前者”哪些数据 UI 能自己改”?想通这点,你 43.5 和本章就接上了。


44.4 编辑器扩展:主程的”内部工具”日常

讲完界面,跳到主程另一块高频活——编辑器扩展(Editor Extension)。这词你可能陌生,但对应你后端的”内部运维脚本/管理后台”,你一定熟。

现象:项目里一堆重复劳动——批量给 200 个资源改个设置、一键把配置表导成二进制、做个”关卡编辑器”让策划拖拖拽拽摆怪物路线、一个按钮打出当前场景所有异常物体。这些如果让程序/策划手动点,又慢又错。

现实问题:Unity 编辑器默认只给你通用功能。但你的项目有专属流程(比如”塔防关卡用 Excel 配怪,要导进 Unity”)。没有工具,团队每天重复机械操作,主程被叫去干杂活。

工程师的方案:Unity 允许你写”只在编辑器里跑、不进游戏包”的 C# 代码,扩展编辑器。两个主力:

  • MenuItem:在编辑器顶部菜单加一个自定义项,点了跑一段你的代码。比如:
using UnityEditor;
using UnityEngine;
 
public class MyTools {
    [MenuItem("工具/批量处理/把所有材质设为不透明")]
    static void MakeAllOpaque() {
        // 遍历项目里所有材质,批量改属性——省下人工点几百次
        foreach (var guid in AssetDatabase.FindAssets("t:Material")) {
            string path = AssetDatabase.GUIDToAssetPath(guid);
            Material m = AssetDatabase.LoadAssetAtPath<Material>(path);
            m.SetFloat("_Mode", 0);  // 示意:设成不透明
            EditorUtility.SetDirty(m);
        }
        AssetDatabase.SaveAssets();
        Debug.Log("批量处理完成");
    }
}
  • EditorWindow:做一个独立的自定义窗口(比如一个”关卡编辑器”面板),里面放按钮、输入框、拖拽区,让策划可视化地配关卡。本质是”给团队写一个内部小软件”,和你在后端给运营写个 web 管理后台一个脑子。

它解决什么:主程的价值一半在”写游戏”,一半在”让团队跑得动”——工具就是后者。你 Go 里给同事写个 CLI / 管理后台提效,游戏里就是写编辑器扩展。第 35 章模块八说”编辑器扩展 0”是缺,今天补上认知:主程不是只写玩法,是写’让团队高效产出’的杠杆。

反问:你后端给运营做的”配置后台”,和这里给策划做的”关卡编辑器窗口”,本质是不是同一个东西——都是”把重复操作变成一键/可视化”?你那套经验直接能用,只是语言从 Go 换成 C#、平台从 web 换成 Unity 编辑器。


44.5 工程化与 CI:能稳定出包,才是主程的基本功

最后一节,也是模块八最被低估的一块——工程化(Engineeringization)。说人话:项目怎么组织、资源怎么管、怎么自动构建出包、怎么多平台发。

项目结构规范。 你写 Go 讲究目录分层(cmd/ internal/ pkg/),游戏工程也该有约定:脚本放 Scripts/、按系统分子目录(战斗/UI/网络)、资源放 Assets/ 下分类(Prefabs/Scripts/Configs/Scenes)、第三方插件隔离。没规范,三人协作三天就互相覆盖文件、找不到东西。你后端的”代码规范 + 目录约定”素养,直接平移。

Addressables 管理资源(连回第 39/43.4)。 第 43.4 节提过 Addressables 是资源热更的正规军。工程化上它还有一层意义:它让”资源不再散落、按需加载、可远程更新”,是大项目资源管理的标准做法。你把资源打组、定地址、按需拉取,包体小、更新灵活——这正是”资源管理”工程化的核心。若你读过第 39 章,这里就是它的落地;没读记住”Addressables = 资源的规范化地址管理 + 热更能力”即可。

构建流水线 / CI(连回你 Go 后端的 CI 经验)。 这是你最该有熟悉感的一段。你写 Go,CI(持续集成,Continuous Integration)你熟——git push 触发 GitHub Actions / GitLab CI,自动 go build、跑测试、出二进制、部署。游戏工程化一模一样,只是产物从”服务端二进制”变成”游戏安装包(APK/IPA/EXE)”:

  • 你提交代码 → CI 拉起 Unity(用命令行 -batchmode -quit 无界面构建)→ 自动编译 → 跑一遍冒烟测试 → 打出 Android APK / iOS IPA / PC EXE → 传到分发平台或内部测试渠道。
  • 好处:没人手动点”Build”出错;每次提交都有可装包;测试同学随时拿最新包测;出事能追溯哪次提交引入的。

你 Go 的 CI 流水线经验,几乎一字不差地能用——只是构建命令换成 Unity 的批处理构建,测试从 go test 换成 Unity 的 EditMode/PlayMode 测试。第 35 章说”CI/CD 0”是缺,今天补:主程要会搭这条”提交即出包”的流水线,这是”能稳定交付”的命根。

具体长什么样(给你一个真实形态的印象)。 你 CI 脚本里,触发构建的那一行大概是这样(以命令示意,不是让你现在抄):

# 无界面启动 Unity,执行一个"出 Android 包"的静态方法,跑完自动退出
Unity -batchmode -quit -projectPath ./ -executeMethod BuildScript.BuildAndroid -logFile build.log

其中 BuildScript.BuildAndroid 是你写的一个编辑器脚本(和 44.4 的编辑器扩展同源,都用 UnityEditor 命名空间),里面调用 BuildPipeline.BuildPlayer(...) 打出 APK。CI 拿到产物传到分发后台,测试同学点链接下载。你看——“编辑器扩展(44.4)“和”CI 出包(44.5)“是同一套 UnityEditor 能力的两个出口:一个给人手动点,一个给机器自动跑。你 Go 里”运维 CLI”和”CI 调用同一段部署逻辑”,也是这个关系。所以工程化不是孤立的三件事,而是一条”用编辑器能力喂饱 CI”的链。

多平台打包(PC/手机)。 同一个工程,要出 PC(Windows/Mac)、Android、iOS。各平台有差异:屏幕比例(锚点这时显灵,44.2)、输入方式(触屏 vs 键鼠)、权限(手机要申请存储/网络权限)、性能预算(手机 GPU 弱,画质要降)。工程化上要”一套代码、多平台配置切换”,用 Unity 的 BuildTarget 切换 + 平台宏(#if UNITY_ANDROID)。类比你后端”一套 Go 服务跑在 linux/跨架构”,平台差异靠编译标签和条件处理——同源。

UI 图集(Atlas)与 DrawCall:界面多了也会卡。 工程化不只管”出包”,还管”出了包跑得顺”。你第 34 章学过 DrawCall(一次”把一批几何体送给 GPU 画”的调用,太多就卡)。UI 也吃 DrawCall:每个 Image 默认一次绘制调用,几百个按钮/图标同屏,DrawCall 爆了手机直接掉帧。工程师的办法是图集(Atlas)——把一堆小图标拼进一张大图(SpriteAtlas),UI 用这张大图里的”一小块”,GPU 就能”一次调用画一堆”,DrawCall 骤降。这和你后端”把几百个小请求合并成批量接口、减少往返”是一个省资源的脑子。主程做工程化,要把”建立图集、控制同屏 DrawCall”写进规范,否则美术 happily 拖了五百个图标,手机当场卡死。第 35 章模块三”性能剖析”你若补了 Profiler,这里就能量化——UI 的 DrawCall 在 Frame Debugger 里一目了然。

连回你的 Go 后端:你那套”规范目录 + 自动化构建 + 多环境部署”的工程素养,是模块八最稀缺的视角。很多纯客户端出身的主程,工程化反而是弱项;而你,CI 是老本行。所以这一节对你不是学新东西,是把”出服务端二进制”换成”出游戏安装包”,流水线思维一模一样。

大实话:能”稳定出包”听起来不起眼,却是主程和” solo 写 demo 的人”的分水岭。demo 自己点 Build 能跑就行;产品要”每次提交都自动出可测包、出事能回滚、多平台同步”。这套能力,你 5 年 Go 的 CI/部署肌肉直接复用,是差异化王牌。


44.6 收尾:模块八补上了,全景图又亮一块

回到第 35 章。今天你补上了模块八的大半:UI 框架思想(44.1–44.3,解耦是核心)、编辑器扩展(44.4,主程的工具杠杆)、工程化与 CI(44.5,稳定出包是基本功)。连回第 18 章的 UI 零件、第 17 章的事件通信、第 19 章的服务端权威、第 39/43.4 的 Addressables,这一章把”界面”和”交付”两块缝进了你已有的地图。

至此,第 35 章标的两大缺口——模块四(本章 43 章填的本地存档/配置表/热更)和模块八(本章填的 UI/工程化)——你都不再是零。九大模块里,你从”图形强、联机概念有、客户端数据层与工程化为零”,变成了”客户端数据层与工程化也立住了”。剩下的硬骨头(四元数、主循环、动画物理)是别的章的事。

你 5 年 Go 后端,今天再次证明了它的杠杆力:配置中心思想(43.3)、服务端权威(43.5/44.3)、CI 流水线(44.5)、运维工具(44.4)——全是你的存量技能平移。游戏主程不是”从头学一切”,是”把旧本事接到新战场”。

【思考题】

  1. 为什么 UI 必须用锚点(Anchor)而不是写死像素坐标?如果所有按钮都”距左边 100 像素”,上线到一台更窄的手机(比如折叠屏半屏)会发生什么?
  2. UI 和逻辑耦合(按钮事件里直接写”扣金币 + 生成塔 + 播特效”)会有什么具体坑?用 MVC 思想,金币数据、血条文字、按钮点击回调分别属于哪一层?
  3. 编辑器扩展(MenuItem/EditorWindow)对主程团队意味着什么?它和你后端给运营写的”配置后台/运维脚本”本质是不是同一个东西?举一个塔防项目里你想要的”内部工具”。
  4. 你 Go 后端的 CI 流水线(push 触发自动 build + test + 部署),平移到 Unity 游戏项目,产物从什么变成了什么?为什么”能稳定自动出包”是主程的基本功而非可选项?

【参考答案】

  1. 锚点是 UI 的”响应式布局开关”:它定义元素相对父级哪条边对齐,屏幕比例变化时自动跟随,不溢出不变形。写死像素坐标(如距左 100)是”死定位”,窄屏上右边空间不够,按钮会被挤出屏幕外或重叠,A 手机漂亮、B 手机一塌糊涂——这正是上线必踩的适配坑。类比前端 CSS:死像素 = fixed 定位,锚点 = flex/百分比自适应。锚点不是可选项,是多分辨率上线的刚需。
  2. 耦合的坑:界面一多(20 面板),逻辑散落各处,美术改布局怕弄挂逻辑、策划加确认框得扒按钮代码、谁都不敢动。用 MVC:金币数等”真相”是 Model(逻辑层,联网时归服务端权威);血条文字/按钮是 View(只显示);按钮点击回调 + “改 Model 后刷新 View”是轻量 Controller。铁律:View 不反向算业务,单向数据流(点→改 Model→刷新 View),三方互不踩脚,和你后端 Controller-Service-模板分层同源。
  3. 编辑器扩展是”主程写杠杆让团队高效”——把重复机械操作变成一键/可视化。它和你后端给运营写的配置后台、运维 CLI 本质完全相同:都是”用代码替团队省手工、降出错”。塔防里我想要的内部工具举例:一个”关卡编辑器窗口(EditorWindow)“,让策划拖拽摆怪物出生点/路线/塔位,一键导出成配置表(连 43.3),不用手写 JSON;或”一键校验所有塔配置数值合法”的 MenuItem,脏数据(负数血量)提交前就拦下。
  4. 平移后,CI 产物从”服务端二进制(Go 可执行文件)“变成”游戏安装包(APK/IPA/EXE)“;触发、自动编译、跑测试、出产物、可追溯的思路一字不差,只是构建命令换成 Unity 批处理(-batchmode)。“稳定自动出包”是基本功:demo 自己点 Build 能跑就行,产品要”每次提交自动出可测包、出事能回滚、多平台同步”——手动点 Build 易错、不可追溯、测试拿不到最新包。能稳定交付,是主程和 solo 写 demo 者的分水岭,也是你 Go CI 肌肉直接复用的王牌。