
1. 先想清楚Cocos Creator 的 Hello World 到底在验证什么1.1 从 C 语言那行 printf 说起大一新生写下的第一个 C 语言程序往往是这样的引入头文件写一个 main 函数调用 printf 打印一行字然后 return 0。这段代码在语法上没有任何难度真正的价值在于它一次性验证了三件事——编译器装好了、链接器能找到标准库、运行环境能把可执行文件跑起来。只要屏幕上出现那行字从没有环境到环境可用这道坎就算迈过去了。Cocos Creator 的 Hello World 承担的职责其实一模一样只不过要验证的东西从一个编译器变成了一整套内容生产管线。编辑器能不能正常启动、场景能不能保存、资源能不能被正确引用、脚本能不能被编译和加载、预览窗口能不能渲染出画面这几件事任意一环出问题你在后面做真正的玩法时会一头雾水分不清是代码写错了还是环境没配好。所以我的习惯是任何一个新版本、新机器、新团队环境第一件事就是老老实实跑一遍 Hello World把这条链路先焊死。1.2 Hello World 在游戏引擎里要跨过的四道门槛从纯文本输出到引擎渲染中间隔着好几道普通人不太会注意的门槛这里先把它们点出来后面每章都会落到实处。第一道是场景与节点系统。游戏引擎里没有直接往屏幕上打一行字这种操作文字必须先成为一个节点挂上渲染组件再被放进一棵节点树最后由摄像机拍下来。你要搞清楚节点、组件、场景三者之间的从属关系否则就会出现我明明加了 Label屏幕上一片空白的经典问题。第二道是坐标系与适配。屏幕有多大、设计分辨率是多少、锚点在哪里、父节点的尺寸是多少这些参数共同决定了一个文字节点最终落在屏幕的哪个像素上。很多人第一次做出来文字飞到屏幕外八成就是这块没理顺。第三道是脚本与组件的绑定关系。引擎的脚本不是被调用的是被挂载的。你写的类必须能出现在属性检查器的添加组件列表里挂上去之后引擎才会按生命周期回调去驱动它这一点和写 C 语言时写个 main 就有人执行的直觉完全不同。第四道是构建与打包。开发时在浏览器里预览跑通不代表能出一个能装到手机上的 APK。原生构建涉及外部依赖、包名、ABI、签名等一堆参数这一步是新手掉队最多的地方也是最值得提前走一遍的地方。1.3 谁适合跟着这篇走如果你是完全没接触过引擎的编程新手这篇可以当成一次完整的开荒记录来看每个操作我都会说明它在干什么、为什么要这么干而不是丢一堆菜单路径让你照点。如果你是从其他引擎或者 Cocos 2.x 转过来的老手第 2 章之后的编辑器与工程结构差异、第 5 章的打包参数、第 6 章的踩坑表更值得你直接跳读。整篇的默认前提是 Cocos Creator 3.x 版本加 TypeScript 工作流2.x 的差异我会在必要的地方单独点出来因为两个大版本在这件事上的操作路径差别不小混着看容易晕。2. 开工前的环境与工程初始化2.1 Dashboard 与编辑器版本的选择Cocos Creator 的安装包里带的其实是一个 Dashboard项目与版本的统一入口加若干版本编辑器。Dashboard 负责管理你本机装了哪几个版本的编辑器、每个项目用哪个版本打开。这里有个很容易被忽视的细节项目一旦用某个版本的编辑器打开并保存过再换版本打开时会有升级提示升级动作几乎不可逆。所以我的做法是正式项目登记一个主版本号写进团队文档Dashboard 里也只留主版本加一个备用版本避免自己下意识点错。版本选择上新手不要追最新的大版本。选一个官方文档覆盖完整、社区资料多的稳定小版本比如 3.8 系列里的最新补丁版。原因很实际新手遇到的问题九成是别人已经踩过的资料越多你越容易搜到答案而大版本刚发布时插件生态、教程、第三方库的适配往往滞后你会在一些莫名其妙的地方卡住还找不到人问。还有一个常被忽略的操作安装路径不要带中文和空格。原生构建阶段会调用外部命令行工具路径里有空格会让某些脚本参数解析出错报错信息还特别隐晦。Windows 用户尤其注意默认装在C:\Program Files下就带空格了直接装到D:\Cocos\这类干净路径能省掉一堆麻烦。2.2 新建项目时模板怎么挑新建项目面板会给出几个模板常见的有空白的 3D 工程、空白的 2D 工程以及一些带示例内容的工程。做 Hello World 这件事我建议直接选空白 2D 工程理由有三点。一是 2D 模板默认给你的场景结构更贴近界面上放一行字这种需求节点树更干净你不需要先把 3D 模板里的默认光源、相机参数理解一遍。二是空白模板没有预置的示例脚本和资源你每加一个文件都是自己加的出问题时排查范围小。三是带示例的工程虽然看着热闹但它会引入大量你暂时不需要的概念比如预制体、物理系统、动画状态机新手很容易被带偏花两小时研究示例代码而不是搞明白自己的 Hello World。项目名字建议用英文加下划线比如hello_world。项目路径同样不要有中文和空格。这个建议听起来像老生常谈但它在后面构建原生工程时会真的咬你一口某些构建工具的中间产物路径拼接对非 ASCII 字符支持不好报的错跟你写的中文项目名毫无关联你要排查很久才能想到是路径的问题。2.3 工程目录逐层拆解新建完成后先别急着打开场景把工程根目录浏览一遍。理解这些目录各自的职责能让你在后面遇到改了没生效构建报错时更快定位。目录/文件作用能否手动改是否该提交到版本库assets所有资源与脚本的源文件编辑器里看到的资源管理器就是它可以但建议在编辑器内操作必须提交settings项目级配置比如设计分辨率、物理、构建相关的基础设置谨慎最好通过项目设置面板改必须提交library编辑器导入资源后生成的缓存体积大不要动不提交可删可重建temp临时文件不要动不提交local本机相关的编辑器状态比如面板布局不要动不提交build构建产物输出目录可以看不建议手改不提交profiles构建配置等本机档案一般不手改视团队约定这里有一条我用血泪换来的经验遇到编辑器行为异常、资源显示不对、脚本改了不生效这类玄学问题第一步永远是关掉编辑器删掉 library 和 temp重新打开工程让它重建缓存。这两个目录是纯缓存删了不会有任何损失重建一次通常几分钟但能解决掉大半的诡异问题。我见过有人为了一个Label 不显示的问题重装了两遍编辑器最后发现是资源缓存坏了。另外assets目录下的资源引用关系是有唯一标识的直接在文件管理器里拖动或重命名资源文件会让引用断掉编辑器里会出现一堆命名冲突或者丢失引用。所有资源的移动、重命名、删除都老老实实在编辑器的资源管理器面板里做让编辑器同步更新元数据。这条规矩越早养成越好等工程里几百个资源的时候再改习惯代价就是一片红色的报错。3. 不用写一行代码先让屏幕出现自己的文字3.1 场景、节点树与 Canvas 的坐标系打开默认场景你会看到层级管理器里已经有一个场景根节点下面通常挂着一个 Canvas 节点和一个摄像机节点。先建立三个概念。场景是一份可保存的关卡描述文件它记录了这个场景里有哪些节点、每个节点挂了什么组件、组件的参数是什么。节点是场景里的一个位置容器本身不渲染任何东西它的价值在于提供坐标、旋转、缩放以及作为子节点的父级。组件才是真正干活的渲染、动画、脚本逻辑都以组件形式挂在节点上。真正决定文字画在哪里的是 Canvas 下的坐标系。Canvas 节点上带一个 UITransform 组件它定义了这块 UI 画布的尺寸而这个尺寸来自项目设置里的设计分辨率。比如设计分辨率设置成 960x640那么画布范围内节点坐标就落在这个区间里。关键点在于节点的位置是相对于父节点锚点的偏移而不是屏幕绝对坐标。你把一个 Label 节点拖进 Canvas它的位置坐标(0, 0)表示与父节点锚点重合也就是画面中心而不是左上角。这也是新手第一次做的时候最常见的困惑来源明明把位置设成(0, 0)以为会出现在左上角结果文字漂在正中间。搞明白相对父节点这五个字后面所有 UI 布局问题都会好理解很多。3.2 Label 组件的参数逐个说清楚在 Canvas 上右键新建一个节点给它添加 Label 组件然后修改 string 属性你就能在场景编辑器里看到文字了。但要让它在运行时表现正常有几个参数必须理解。参数含义新手的常见误区String要显示的文字内容直接输入多行文本不换行以为会自动折行Font Size字号单位是像素以为它是相对大小其实和设计分辨率绑定Line Height行高多行文本行距挤在一起时忘记调它Overflow溢出处理策略决定文字超出节点尺寸时怎么办默认策略下改了尺寸文字也不换行Horizontal / Vertical Align文字在节点内的对齐方式与锚点混淆两个都调最后不知道谁在起作用Color文字颜色颜色本身没问题但透明度为 0 导致看不见Cache Mode文字纹理的缓存方式频繁改内容时没意识到有重绘开销Overflow 这个参数值得单独说。它大致有几种策略不处理、自动换行后裁剪、自动换行后撑高节点、整体缩放到合适尺寸。很多人写了一段长文本发现文字跑到节点外面去了第一反应是去调节点尺寸结果没用因为当前的 Overflow 策略是不处理溢出。这时候把策略改成按宽度换行或者改成自动缩小问题立刻解决。先看 Overflow再看尺寸最后才看锚点这个排查顺序能帮你少走很多弯路。另外中文字体这块有个坑必须提前说引擎默认使用的字体字形覆盖范围有限显示英文数字没问题但换到中文时可能显示成方块或者干脆空白。正确做法是在 Label 组件的字体属性上指定一个带中文字形资源的字体文件或者把它设成使用系统字体。我在浏览器预览里测试中文正常、打包到真机就变方块就是因为预览时的字体回退走的是系统字体而运行时环境不一样。只要是中文项目字体一定要单独确认一遍别等出包才发现。3.3 分辨率适配与 Widget 的用法文字放上去之后第二个要面对的问题是不同尺寸的屏幕上它跑到哪里去了Canvas 节点上有一个适配相关的配置通常可以选择按高度适配、按宽度适配或者两者都适配。按高度适配适合竖屏为主的界面按宽度适配适合横屏。选错方向的直接后果是在你的开发机上看着正好换一台长宽比不同的手机界面元素就被裁掉或者挤在一起。对于我要把一行字固定在屏幕正中间这种需求最省事的做法是给节点加一个 Widget 组件。Widget 的直觉是把节点对齐到父节点的某条边你可以选择水平居中和垂直居中勾选之后节点位置会随着父节点尺寸变化自动重算不需要你写任何代码。这比手算坐标可靠得多尤其是在适配多种机型时。实测下来新手第一个 Hello World 想达到的效果通常是无论什么屏幕文字都在中间且完整可见那么组合方案就是Canvas 的适配策略选一个与你项目主方向一致的Label 的 Overflow 选择自动换行并按宽度撑高节点上挂 Widget 做居中。这三步做完你在绝大多数设备上看到的效果都是一致的。4. 加一段 TypeScript让 Hello World 动起来4.1 组件的生命周期回调执行顺序光显示一行静态文字其实还没碰到脚本系统。真正让 Hello World 有意义的一步是写一个脚本组件让它在运行时改文字内容、打印日志。这一步会验证脚本编译链路是通的价值比显示那行字本身大得多。Cocos Creator 3.x 的生命周期回调常用的有这几个执行顺序也要记清楚onLoad节点被激活时调用一次适合做初始化、取引用。此时节点还没开始渲染父节点的 onLoad 可能还没执行完不要在这里依赖兄弟节点的状态。onEnable组件每次被启用时调用节点被反复启用/禁用时会多次触发。start在当前帧第一次更新前调用一次适合做需要其他节点已完成初始化的逻辑。update(dt)每帧调用dt是距离上一帧的秒数适合做逐帧逻辑。lateUpdate(dt)在 update 之后、渲染前调用适合做跟随类逻辑比如相机跟人。onDisable/onDestroy禁用与销毁时调用用来清理定时器、事件监听。新手最容易犯的错是在 onLoad 里依赖其他节点的初始化结果。因为节点树的 onLoad 执行顺序是从上到下按层级来的你在子节点的 onLoad 里访问一个还没执行 onLoad 的兄弟节点拿到的引用可能是空的然后报一个看不懂的空指针。稳妥做法是取引用放 onLoad用引用干活放 start。4.2 property 把编辑器里的资源接到脚本上3.x 里让编辑器面板暴露一个属性给你的脚本靠的是装饰器。写法大概是引入引擎模块然后用ccclass给类注册一个名字用property标注你要暴露的字段。import { _decorator, Component, Label } from cc; const { ccclass, property } _decorator; ccclass(HelloWorld) export class HelloWorld extends Component { property(Label) label: Label null; private elapsed: number 0; start() { if (this.label) { this.label.string Hello World from Cocos Creator; } } update(dt: number) { this.elapsed dt; if (this.elapsed 1) { this.elapsed 0; console.log(已经运行了 1 秒); } } }这里有几个细节值得展开。第一property(Label)里的类型参数决定了属性检查器里显示什么类型的槽位写Label你就能把场景里的 Label 节点直接拖进去而不是在代码里写查找节点的路径。能用拖拽绑定的就不要用字符串路径去查找因为路径一旦改名就会静默失效而拖拽绑定在资源被删时编辑器会直接报错问题暴露得更早。第二类名建议和脚本文件名保持一致。编辑器在添加组件、序列化数据时都会用到类名两者对不上时会出现组件加不上去重新打开场景后组件丢了这类问题。这条规则在 3.x 里依然值得遵守别去试探边界。第三property标注的字段在编辑器里改了值会覆盖代码里的默认值。这是有意设计的但新手常被它坑到代码里把默认值从 1 改成 2运行结果还是 1因为编辑器已经把这个属性序列化到场景文件里了。改默认值之前先确认场景里没有覆盖它或者在属性检查器里点一下重置。4.3 脚本挂载不上的几种典型情形写完脚本回到编辑器右键节点添加组件如果列表里找不到你的脚本按这个顺序查脚本有没有编译错误。看控制台任何一处类型错误都会导致整个脚本无法注册。类名和文件名是否一致不一致时编辑器可能识别不到。ccclass装饰器的名字有没有重复同名会冲突后注册的覆盖前面的。脚本文件是不是放在了 assets 目录之外目录外的文件不会被纳入资源系统。扩展名是否正确.ts和.js的处理方式不同。挂载成功之后还有一步验证在属性检查器里确认那个 Label 槽位确实被赋值了。忘了拖拽赋值是最高频的低级错误代码写得再对label是 null运行时什么都不会发生控制台还未必有报错——因为你写了判空保护。4.4 预览与调试的基本姿势跑预览有两种常用方式浏览器预览和编辑器内预览。日常改 UI 参数、调位置看效果用编辑器内预览最快查逻辑、看网络请求、打断点用浏览器预览配合开发者工具更合适。日志打印方面console.log会输出到控制台面板。日志里带上上下文信息比如把节点名、关键数值拼进去而不是只打印一个进来了。真机上排查问题时你往往拿不到断点只能靠日志所以从第一天就用好日志习惯收益是长期的。浏览器预览还有一个好处是可以用性能面板看帧率和绘制调用次数。哪怕只是一个 Hello World你也可以顺手看一眼一个 Label 消耗几个绘制调用、有没有异常的帧率波动。这不是小题大做而是让你从一开始就对我这个场景大概什么开销有感觉将来节点数量上来时才不会失控。5. 打包成 APK从构建设置到真机跑起来5.1 构建原生工程的前置依赖这一步是 Hello World 之旅里最像配环境的部分因为它确实要装一堆外部的开发工具Android SDK、NDK、以及 JDK。三者的角色分别是SDK 提供平台库和构建工具NDK 提供编译原生代码所需的工具链JDK 提供构建系统本身运行需要的 Java 环境。这里有几个容易出问题的点。版本要互相匹配——不同版本的编辑器对 NDK、JDK 版本有各自的要求装错了通常会报一些和实际原因毫无关系的错误比如找不到某个编译器、某个中间文件格式不对。稳妥做法是去查你所使用版本的官方环境搭建文档按文档推荐的版本号装不要图省事用系统里已有的旧版本。路径依然不能带中文和空格并且记得在编辑器的偏好设置里把这三个路径都手动指定一遍。有些安装包会自动写环境变量有些不会指定路径比依赖环境变量更可靠。装完之后建议先做个无关的小验证在命令行里执行一次构建工具的版本查询命令能打印出版本号说明路径和环境变量没问题。这比在编辑器里构建失败后再去猜要高效得多。5.2 构建面板的关键参数逐项说明构建面板里的参数看着多真正影响出包成败和运行效果的主要是下面这些。参数说明建议平台选择 Android 出 APK按目标设备选包名应用的唯一标识形如反向域名上线后不可随意更改先规划好目标 API 级别允许运行的最低系统版本别设得过低兼容成本高屏幕方向竖屏、横屏、自动与设计分辨率适配策略保持一致ABI 架构生成哪些 CPU 架构的库至少保留主流架构全选会显著增大包体渲染后端图形接口选项保守选择兼容性更好的那个脚本加密是否对脚本做处理调试阶段关掉方便看堆栈MD5 缓存资源名带哈希便于增量更新首次调试可关压缩纹理等资源压缩选项有明确需求再开包名这件事我要多说一句。它看起来只是构建时填的一个字符串但它是应用在系统里的唯一身份一旦发布再改就相当于换了个应用用户数据和评价都带不过去。所以哪怕是练手的 Hello World也养成用规范反向域名的习惯比如com.yourname.helloworld这样别用默认值一路点下去。ABI 架构的选择也很实际。每多选一个架构包里就多一份原生库包体增长非常明显。初期调试只保留当前测试机对应的架构就够了等要发版再按用户设备分布决定保留哪些。5.3 生成物目录与 Android Studio 里的操作构建完成后产物会输出到build目录下平台对应的子目录里。这个目录里既有可以直接安装的包也有一个完整的原生工程目录后者可以用 Android Studio 打开做进一步定制——比如改应用图标、改启动画面、加平台相关的配置。编辑器里通常还会提供编译和运行两个操作编译负责把原生工程编译出安装包运行负责把它装到你连接的测试设备上并启动。第一次跑建议按构建、编译、运行的顺序一步步来不要跳步因为每一步失败的原因完全不同构建失败多半是资源配置问题编译失败多半是外部依赖和版本问题运行失败多半是签名或设备连接问题。分步走能让你一眼看出是哪一类。如果要在 Android Studio 里手动打包注意签名配置。调试版本可以用默认调试签名正式发布必须用你自己的签名文件并且这个文件要妥善保存——丢了就没法给已有的应用发更新。这是很多个人开发者吃过的大亏。5.4 真机白屏黑屏的排查链路应用装上去了一点开是白屏或者黑屏这是新手最慌的时刻。别急按下面这条链路走基本能覆盖八成情况。第一步看日志。通过命令行工具抓设备日志过滤应用包名相关的输出重点找报错和资源加载失败的记录。很多白屏其实是启动脚本抛了个异常日志里写得清清楚楚。第二步确认是不是资源没打进去。构建时如果有资源被排除或者某个资源引用了但没被纳入启动阶段会卡在加载。日志里通常有找不到某个资源标识的记录。第三步确认渲染后端与设备兼容。换一个渲染后端重新构建试试这是排查图形相关白屏最快的二分法。第四步确认方向与分辨率。屏幕方向配置和实际设备方向不一致时可能出现界面渲染在了可视区域之外看着像白屏其实是画面跑到别处去了。这种情况在 Hello World 阶段特别常见。第五步确认包体完整。传输过程损坏、安装不完整的概率不高但不是零重新构建安装一次能排除掉这类干扰。我自己的经验是能在浏览器预览里跑通的东西打包出问题九成在环境配置和资源引用上而不是逻辑代码。所以排查时优先怀疑配置别一上来就改代码。6. 新手第一次做 Hello World 最容易踩的坑把上面散落的经验集中成一张表方便你对照自查。现象最可能的原因处理方式Label 完全看不见节点不在 Canvas 下、颜色透明度为零、位置在可视区域外依次检查父节点、颜色、坐标文字位置和预期不符混淆了相对父节点的坐标与屏幕绝对坐标用 Widget 做对齐别手算中文显示成方块字体资源不含中文字形指定支持中文的字体或系统字体长文本不换行Overflow 策略不是换行类改 Overflow再调节点尺寸脚本在添加组件列表里找不到编译报错、类名与文件名不一致、类名重复看控制台统一命名脚本挂上了但不执行属性槽位没赋值、组件被禁用、节点未激活检查属性检查器与节点状态改了代码没生效缓存问题、编辑器未重新编译删除缓存目录重开工程构建原生工程报错SDK/NDK/JDK 版本不匹配或路径含空格按官方文档版本重装换纯净路径真机白屏启动脚本异常、资源缺失、渲染后端不兼容先抓日志再二分排查安装包体积异常大ABI 架构全选、调试资源未裁剪按需精简架构与资源这张表里的每一条我都在不同项目里真实遇到过。它们有一个共同特征现象和原因之间的距离很远靠猜基本猜不中。所以遇到问题时的正确姿势是先缩小范围——把问题定位到环境、配置、代码三类中的哪一类再往下查。分类对了接下来只是时间问题。7. 从这个小工程开始的工程习惯7.1 目录与命名规范Hello World 虽然小但它是一个绝佳的时机去建立目录规范。我的建议是在 assets 下按功能而非按资源类型分目录脚本、场景、图片、预制体各自有归属但当项目变大时按功能切分的目录更抗腐化因为你找东西时的思维是这个功能相关的文件在哪而不是所有图片在哪。命名上脚本用大驼峰或者下划线分隔保持统一场景用清晰的中文或英文描述性名字资源名避免用new、copy、111这类无语义的名字。这条听起来像强迫症但等到你需要在一百个资源里定位一个问题时你会感谢当初的自己。7.2 版本控制里哪些目录不该提交前面表格里已经列过这里再强调一次实践方式准备一个忽略规则文件把缓存目录、构建产物、本机配置目录都排除掉。判断标准很简单——如果一个目录删掉之后工程重新打开能自动重建那它就不该进版本库。这样做的直接好处是仓库体积小、克隆快、冲突少。反过来如果把缓存目录也提交了多人协作时每个人机器上的缓存内容不同每次合并都是一堆无意义的冲突真正重要的代码改动反而被淹没在噪音里。我在早期项目里吃过这个亏一个仓库因为误提交了缓存目录体积涨到几百兆后来清理花了很久。7.3 把这次的验证结果记录下来最后一条建议可能是我这篇文章里最想强调的把这次 Hello World 跑通用的所有参数都记下来。编辑器版本号、外部工具的版本号、构建面板的关键参数、包名规则、真机测试的机型。写在一个简单的文本文件里放在工程根目录下或者团队文档里。原因很简单半年后你换了台电脑或者带了个新人进来所有参数都要重问一遍。而这份记录能让你在半小时内把环境搭回来而不是再花一天去踩一遍已经踩过的坑。我自己每个新项目开荒时都会留这么一份文件它是我从 Hello World 这个阶段带走的最有价值的东西比那行字本身值钱得多。