资讯动态

Cocos Creator跑酷源码拆解:对象池、状态机与物理碰撞实战

发布时间:2026/10/14 0:30:19 来源:尧图企业网站定制
简介面向 Cocos Creator 初中级开发者的熊猫跑酷完整项目源码基于 1.4 以上版本设计亲测可用适合用来学习跑酷游戏的核心玩法、场景构建与资源组织方式。整个压缩包共 256 个文件体积仅 3.46MB结构相当紧凑其中包含 102 个 JSON 配置、22 个 Prefab 预制体、21 个 JavaScript 脚本、19 个 PNG 贴图以及 map、plist、anim、fire 等特殊类型文件分别对应关卡地图、序列帧动画、角色动作和游戏场景配置能较完整地还原熊猫跑酷项目的开发脉络。目前已有 3274 人学习或下载属于关注度较高的源码范例。通过阅读源码可以了解场景文件如何串联各模块、角色控制脚本如何控制移动与跳跃、动画文件如何实现奔跑和二段跳等动作还附带演示视频和说明文档便于对照运行效果快速上手。对于准备用 Cocos Creator 制作跑酷或动作类游戏的开发者这套源码提供了可直接参考与改写的实战基础。1. 拿到的这份跑酷源码先别急着预览拆过不少 Cocos Creator 跑酷项目源码一个很一致的现象是压缩包里脚本、场景、资源都在但八成的人第一次预览都跑不出一个完整的游戏循环。不是代码有深坑而是版本匹配、资源路径和脚本挂载三件事没对齐。这份源码适合两类人一类是打算快速复刻一套跑酷 Demo、做作品集或课程设计的新手另一类是想研究对象池和状态机写法的在职开发。下文从核心循环讲到二次开发全程按实际拆过的流程走参数给到能改的位置踩坑记录也一并列出。2. 跑酷游戏的核心循环角色控制、障碍生成与滚动背景2.1 玩家控制脚本跳跃、二段跳与触感反馈先拆最核心的 PlayerController。Cocos Creator 里角色控制本质是状态切换加碰撞体配合跑酷游戏物理成分不高真正重要的是状态机和碰撞体尺寸。源码里通常会有三个碰撞体节点身体、脚底、头顶分别负责侧面碰撞、落地检测和顶碰判定。这三个必须随角色一起移动缺一个都会出现穿模或跳跃失灵。// PlayerController.js —— 核心角色控制 import { _decorator, Component, Vec3, input, Input, EventKeyboard, KeyCode, RigidBody2D, Collider2D, Contact2DType } from cc; const { ccclass, property } _decorator; ccclass(PlayerController) export class PlayerController extends Component { property jumpForce 600; // 跳跃力度 property maxFallSpeed 800; // 最大下落速度防穿模 property jumpTimes 2; // 允许二段跳 private rigidBody: RigidBody2D; private collider: Collider2D; private curJumpTimes 0; onLoad() { this.rigidBody this.getComponent(RigidBody2D); this.collider this.getComponent(Collider2D); input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this); this.collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); } onKeyDown(e: EventKeyboard) { if (e.keyCode KeyCode.SPACE) { this.tryJump(); } } tryJump() { if (this.curJumpTimes this.jumpTimes) { this.rigidBody.linearVelocity new Vec3(0, this.jumpForce, 0); this.curJumpTimes; } } onBeginContact(self, other) { if (other.group this.node.parent.getComponent(GameManager).groundGroup) { this.curJumpTimes 0; } } }代码里用 linearVelocity 直接覆盖垂直速度实现跳跃而不是调 applyForce原因很简单跑酷跳跃要的是固定高度力的累加会把角色弹得时高时低对关卡设计是灾难。jumpForce 从 600 开始调地图密度大就降到 500跳过一根普通高的柱子大概需要 600 到 650。maxFallSpeed 是防穿模的关键不设上限的话角色从高台落下来单帧位移可能超过碰撞体厚度直接掉出地板网格。collider 的 Contact 回调里通过 group 判断接触对象是不是地面这个 group 要在物理系统中预定义跑酷项目里通常把地面、障碍、道具各分一组。如果用的是 2D 项目记得在项目设置里把物理引擎改为 Box2DCocos Creator 默认 2D 物理才是开启状态否则这两个回调根本不会触发。2.2 障碍物生成器对象池设计与预制体管理跑酷游戏里障碍物生成是最容易把帧率拖下来的一块。如果每生成一个障碍就 instantiate 一次跑上 30 秒后场景里可能堆积上百个节点DrawCall 直线上升。稳妥的做法是对象池预创建一批障碍节点随用随取、不用即还。源码里一般会有一个 ObstaclePool 挂在地图管理器下。// ObstacleSpawner.js —— 障碍物生成器与对象池 import { _decorator, Component, Prefab, instantiate, Node, Vec3 } from cc; const { ccclass, property } _decorator; ccclass(ObstacleSpawner) export class ObstacleSpawner extends Component { property({ type: Prefab }) obstaclePrefab: Prefab null; property poolSize 12; property spawnInterval 1.8; // 秒 property minSpawnX 1200; // 出生点 X private pool: Node[] []; private timer 0; onLoad() { this.initPool(); } initPool() { for (let i 0; i this.poolSize; i) { const node instantiate(this.obstaclePrefab); node.active false; this.node.addChild(node); this.pool.push(node); } } update(dt: number) { this.timer dt; if (this.timer this.spawnInterval) { this.timer 0; this.spawnObstacle(); } } spawnObstacle() { const node this.pool.find(n !n.active); if (node) { node.setPosition(new Vec3(this.minSpawnX, 0, 0)); node.active true; } } recycle(node: Node) { node.active false; } }这段代码的要点在 poolSize 和 spawnInterval 的配合。poolSize 设 12对应的是玩家从起点跑到第一个障碍物之间所有存活节点数量的上限。spawnInterval 设 1.8 秒切的是生成密度想调难度直接把值改小但要同时检查 poolSize 够不够不然运行一段时间后池子取空会静默不生成障碍表现就是某一段路突然变平了。障碍物移动一般由单独脚本监听全局速度字段拆源码时留意这个速度是由 GameManager 单例下发还是每个障碍自己维护。推荐前者后者容易在暂停和恢复时出现跳变。2.3 背景与地板滚动无缝循环与视差补偿跑酷的地板滚动原理很简单玩家横向坐标固定地板和背景以固定速度向左移动视觉上像是角色在向前跑。坑在两处贴图接缝和视差层速度。地板贴图宽度通常做 1024 或 2048移动时按贴图宽度取余否则接缝处会闪线。// BackgroundScroller.js —— 无缝滚动与视差 import { _decorator, Component, Vec3 } from cc; const { ccclass, property } _decorator; ccclass(BackgroundScroller) export class BackgroundScroller extends Component { property scrollSpeed -300; property loopWidth 2048; // 贴图循环宽度 private startX 0; onLoad() { this.startX this.node.position.x; } update(dt: number) { const x this.node.position.x this.scrollSpeed * dt; const offset Math.abs((x - this.startX) % this.loopWidth); this.node.setPosition(this.startX - offset, this.node.position.y, 0); } }视差是跑酷质感的大头做法是给不同深度的背景节点挂同一个脚本给不同 scrollSpeed速度越小视觉上越远。比如远景山体给 -80中景建筑给 -150近景地面给 -300三层叠加转起来才有纵深。有个细节值得注意地板节点的循环宽度必须精确等于贴图原始宽度的整数倍如果美术给的贴图是 2047 像素硬按 2048 取模每循环一次就多出 1 像素跑 50 个循环后接缝能看出一整条亮线。3. 把源码跑通版本匹配、场景检查与参数校准3.1 导入之前先做版本核对打开 Cocos Dashboard先看项目对应的 Creator 版本跑酷源码最容易踩的就是 3.x 和 2.x 之间的 API 大改。代码里用import { _decorator } from cc是 3.x 写法2.x 是cc.Class那套老接口混在一起编译必挂。拿到源码先翻 project.json 里的 creator 版本字段或者看目录下有没有 ui3 相关的项目文件再决定用哪个版本的编辑器打开。常见做法是找与源码标注版本相同或次新的 Creator 稳定版。比如源码写的是 3.6就用 3.6 或 3.7 打开不建议跨大版本。2.4 的源码升到 3.8 要改的 API 太多不是一份新手资源该承担的工作量。项目打开后先别着急预览按顺序做三件事看构建面板的物理系统、看资源管理器里脚本是否报错、看场景里是否有红色缺失组件。任何一项异常都优先处理急着重开只会把问题堆到运行时。3.2 场景检查清单跑酷 Demo 跑不起来的五个检查点第一Canvas 和 Camera 的视口关系。跑酷通常是竖屏Canvas 设计分辨率设为 750x1334 或 720x1280Camera 的 Projection 要选 Ortho正交Size 设成高度的一半左右否则画面会被拉伸。第二碰撞体尺寸与实际图像的比例。源码里角色的 Box Collider 如果和精灵图不贴合地面上一个微小的台阶都会导致碰撞体提前触发死亡逻辑。选中角色节点把碰撞体的 Offset 调到角色脚底往上 1 到 2 像素处。第三脚本挂载的时机。检查 GameManager 节点是否在场景加载时处于激活状态。很多源码把它挂在启动场景的根节点下但有些分支版本挂在了某个动态加载的预制体上场景一结束它就随预制体销毁整个游戏逻辑链断掉。第四物理分组设置。进入项目设置的物理分组确认地面、玩家、障碍物三个分组都定义了且玩家与地面组的碰撞矩阵是勾选状态否则 onBeginContact 永远不触发角色会一直保持可跳状态表现就是跳不起来。第五图层顺序。跑酷游戏里地板必须排在背景之上、角色之下这个顺序错了视觉上就是角色钻进地里。用节点树的层级拖拽调整即可不用改代码。3.3 首跑参数校准表第一次预览可能跑起来了但手感不对劲这时候不急着改数值先建立一个三参数感知跳跃力度、障碍生成间隔、地板滚动速度。三者互相牵连例如地板速度 -300、跳跃力度 600 时刚好能越过一个高度 120 的障碍把地板速度改到 -450同样的跳跃力度会显得滞空时间不足这时要把 jumpForce 提到 750 到 800。参数校准建议每次只改一个变量记录改前改后的通过率。通过率就是连续跑十次能跳过的障碍数占比。不要一次调三个出问题无法定位根源。下面给一组常用起点值参数起点值作用jumpForce600跳跃高度spawnInterval1.8s障碍生成间隔scrollSpeed-300地板滚动速度paybackTime0.8s死亡后复活延迟4. 跑酷源码避坑记录五个翻车现场与解决过程4.1 编辑器阶段打不开、缺场景与白屏现象导入源码后编辑器能打开但预览直接白屏或者资源管理器里一堆红色脚本报错。原因多数是版本不匹配也可能场景文件缺失。很多跑酷项目源码是多人协作产物目录里混入了原生打包的 Android 工程文件纯编辑器打开时没有可运行场景。解决先检查 assets 目录下有没有 .scene 文件没有就新建一个空场景把 Player 预制体和 Ground 预制体拖进去重新组装。脚本报错先看 Console把报错行号定位到具体脚本通常是把 2.x 的老接口写进了 3.x 工程。Web 构建白屏的另一个常见原因是某个预制体引用了不存在的贴图加载流程静默失败打开浏览器 Network 面板看哪个资源 404。4.2 运行时阶段二段跳失控与物理回调失灵现象角色在第一次落地前可以无限跳跃看起来像二段跳没有次数限制或者 Android 真机物理回调正常iOS 上却不触发。原因二段跳失控是因为 curJumpTimes 的复位逻辑写在 update 里检测 y 轴速度这在物理引擎里不可靠角色在上升阶段和滞空阶段 y 速度都在变化一次跳跃会触发多次复位。iOS 物理回流失灵则是因为大碰撞体移出相机视野后被物理引擎休眠。解决二段跳的复位逻辑全部放到 onBeginContact 里同时判断碰撞组只在地面分组接触时才复位。iOS 的休眠问题有两种解法一是在项目设置里调大物理唤醒距离二是把碰撞体设为 Sensor 模式传感器不受休眠影响但在回调里要自己做分组判定。跑酷这种逻辑简单的游戏建议直接切 Sensor省心。4.3 适配阶段真机黑边与屏幕比例不对现象真机预览时画面两侧有黑边或者角色被拉成瘦长条。原因Canvas 的适配策略没配对。只勾了 Fit Height竖屏游戏宽度就会跟随屏幕比例被裁切导致黑边。解决在 Canvas 的 Widget 组件下把 Fit Width、Fit Height 都勾上设计分辨率改成 750x1334View 节点锚点居中。如果项目用了 Camera 编辑器预览还要确认 Camera 的 Size 与设计分辨率匹配正交相机和 2D 场景里这两者不统一是黑边主因。5. 二次开发实战给跑酷源码加一个磁铁道具5.1 道具预制体与触发检测只调参数可能不过瘾给源码加一个属于自己的玩法是很多人拿到源码后的第一个动作。道具是最容易实现的切入口因为不涉及地形和物理变更只需要一个碰撞触发和一个状态翻转。下面以磁铁道具为例吃到后自动吸附周围金币。// MagnetItem.js —— 磁铁道具脚本 import { _decorator, Component, Collider2D, Contact2DType, Node } from cc; const { ccclass, property } _decorator; ccclass(MagnetItem) export class MagnetItem extends Component { property magnetDuration 5; // 持续秒数 private player: Node null; onLoad() { const collider this.getComponent(Collider2D); collider.on(Contact2DType.BEGIN_CONTACT, this.onTouch, this); } onTouch(self, other) { if (!this.player) { this.player other.node; this.node.active false; GameManager.instance.activateMagnet(this.player, this.magnetDuration); } } }触发检测的核心是注册 BEGIN_CONTACT 回调。道具的碰撞体建议比视觉尺寸小四分之一玩起来手感才对。很多跑酷源码里道具和金币的碰撞体都比图小一号玩家跑过去会被“吸”进判定范围而不是必须精准踩上去这个细节对跑酷的节奏感影响很大。新建预制体时在资源管理器里右键创建 prefab把一张磁铁 PNG 拖进去添加 Collider2D 和这个脚本再把预制体拖到 ObstacleSpawner 的生成列表里。注意生成列表的引用数组需要手动在编辑器里拖拽不能靠脚本自动填充除非源码里本来就实现了加载逻辑。5.2 磁铁效果的改造点磁铁效果本质上是玩家身上多了一个状态每帧对场景内金币做距离判断小于吸附半径就飞向玩家。// MagnetController.js —— 吸附金币逻辑 import { _decorator, Component, Vec3, Node } from cc; const { ccclass, property } _decorator; ccclass(MagnetController) export class MagnetController extends Component { property magnetRadius 150; property magnetPower 500; private coins: Node[] []; update(dt: number) { this.coins.forEach(coin { const off this.node.position.subtract(coin.position); if (off.length() this.magnetRadius) { const dir off.normalize(); coin.position coin.position.add(dir.multiplyScalar(this.magnetPower * dt)); } }); } }magnetRadius 控制在 150 到 200 比较合适超过 300 就变成全屏吸钱跑酷的路线选择和走位策略会失效。magnetPower 表示每帧位移量500 对应每秒 500 像素在 750x1334 的设计分辨率下刚好能保证 1 秒内把半径内的金币全部吸完。这两个值需要配合使用半径大但功率小金币会在空中转圈体验差半径小但功率大金币方向转向太突兀也会显得生硬。金币的回收机制要在吸附之前跑通。金币碰撞玩家后立即回收到对象池否则吸附结束后那一批金币会留在原地成为视觉垃圾。这一点在预览阶段很难发现跑一分钟左右就会明显感觉得到节点数量持续增加。另外磁铁效果持续期间要在 UI 上显示倒计时源码里如果没有现成的状态条可以创建一张 Sprite按比例修改 scale 模拟进度不用上第三方 UI 插件。6. 验证你的改动从帧率到真机手感6.1 快速验证清单改完参数、加完道具下一步别急着说“跑通就行”。先在编辑器里打开 Profiler 面板看 DrawCall 和节点数。跑酷 Demo 的基准是角色加 10 个存活障碍加 3 层背景DrawCall 应压在 40 以下超过 60 就要怀疑对象池失效了。节点数也是一个好指标正常跑一分钟场景内节点数应该保持平稳如果持续上涨一定是哪个对象没回收到池子里。帧率是跑酷游戏的及格线用 Profiler 的 Physics 一栏看物理耗时超过 5 毫秒就说明碰撞体数量太多或带了不必要的 Joint。相机跟随也值得检查。Cocos Creator 的 Camera 不默认跟随玩家很多跑酷源码自己写了 follow 脚本。如果用了 LateUpdate 但没有用调度器帧率波动时画面会卡顿在真机上更明显。发布前用真机跑一遍浏览器模拟器永远测不出贴图内存压力和碎片化物理回调的差异。6.2 手感记录的注脚最后说一个自己养成的习惯每改一个参数或加一个脚本就在代码块里加一行日期和预期值注释例如“2024-05-08 跳力 600 改 680二段跳手感偏硬待验证”。跑酷手感是很主观的东西参考数值只是起点后续微调必须建立在记录的基础上不然三天后再改就忘了当初为什么是 680 而不是 650。从那以后我每次拆源码、调参数都会强制走一遍注释记录的流程改动可回溯沟通成本低不少。这份跑酷源码我已经按上面的方式完整跑通并加装了一个道具希望你也能在自己的项目里少走几步弯路祝顺利。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑