Cocos Creator 2.4.10 2D人物3D地面透视移动方案

📅 发布时间:2026/10/15 21:04:36
Cocos Creator 2.4.10 2D人物3D地面透视移动方案
简介这份资源面向使用 Cocos Creator 2.4.10 进行游戏开发的初学者与进阶开发者聚焦 2D 人物与 3D 背景混合场景的搭建解决人物移动控制与透视视角设置这两类常见需求。压缩包共 33 个文件约 313KB包含 4 个 ts 脚本、4 张 png 贴图、1 个 atlas 图集、6 个 json 配置、1 个 fire 场景文件及配套 meta 等脚本负责移动逻辑与输入监听贴图与图集用于 2D 人物表现场景与配置文件则承载 3D 背景、摄像机参数与项目设置。已有 464 人学习下载说明该示例在同类教程中具备一定参考价值。读者可据此理解 2D 精灵与 3D 模型在同一场景中的组织方式掌握通过节点属性更新位置、监听键盘或触摸输入实现人物移动并调整透视摄像机的位置、方向与视角角度营造空间纵深感同时参考项目目录结构快速复现与二次开发。1. 2D 人物踩在 3D 地面上这套 Cocos Creator 2.4.10 方案到底解决了什么如果你做过 2.5D 项目大概率遇到过这个尴尬人物是 2D 序列帧或 Spine背景却想用 3D 场景做透视纵深结果人物和地面的透视关系怎么调都别扭——人物像贴纸一样浮在画面上走到远处不会变小走到近处又穿不进地面。这套基于 Cocos Creator 2.4.10 的资源核心就是解决「2D 人物 3D 背景 透视视角移动」这个组合场景。它适合正在做横版卷轴、斜 45 度俯视、或者伪 3D 跑酷类项目的开发者尤其是那些不想上全 3D 角色美术成本高、骨骼动画麻烦但又需要真实透视纵深的团队。2.4.x 这条线至今仍有大量线上项目在维护这套方案的价值在于不升级引擎版本也能把 2D 和 3D 的坐标系打通。2. 坐标系对齐2D 人物怎么在 3D 世界里站住脚2.1 为什么不能直接把 Sprite 丢进 3D 场景Cocos Creator 2.4.10 的渲染架构里2D 和 3D 走的是两套节点体系。cc.Sprite 挂在 Canvas 下用的是 UI 坐标系原点在屏幕中心单位是像素而 3D 模型挂在场景根节点下用的是世界坐标系单位是米。你直接把一个 Sprite 节点拖到 3D 摄像机视野里它会跟着 Canvas 走不会跟着 3D 空间走。常见做法是给 2D 人物单独建一个节点挂上 cc.Sprite但把这个节点从 Canvas 下移出来放到场景根节点下然后手动同步它的世界坐标。这样 2D 人物就能被 3D 摄像机拍到同时保留 Sprite 的渲染方式。具体操作分三步// 第一步把人物节点从 Canvas 下移出挂到场景根节点 // 在编辑器里操作选中 personNode拖到 Scene 根节点下 // 确保 personNode 的 position 是相对于场景原点的世界坐标 // 第二步人物节点上挂一个自定义脚本每帧同步逻辑坐标到世界坐标 cc.Class({ extends: cc.Component, properties: { // 逻辑坐标用二维平面表示人物在地面上的位置 logicPos: cc.v2(0, 0), // 地面在 3D 世界里的 Y 轴高度 groundY: 0, // 像素到米的换算比例根据项目实际调整 pixelToMeter: 0.01, }, update(dt) { // 把逻辑坐标映射到 3D 世界坐标 // X 轴直接对应Z 轴对应逻辑 Y 轴俯视视角 var worldX this.logicPos.x * this.pixelToMeter; var worldZ this.logicPos.y * this.pixelToMeter; this.node.setPosition(worldX, this.groundY, worldZ); }, });这段代码的逻辑是人物的「逻辑位置」用一个二维向量表示相当于在地面平面上的投影。每帧根据换算比例把逻辑坐标映射到 3D 世界的 XZ 平面Y 轴固定在 groundY 上。pixelToMeter 这个参数需要根据你的 3D 场景比例来调一般先设 0.01然后看人物移动速度和场景尺寸是否匹配再微调。2.2 透视摄像机的参数怎么设才不穿帮3D 摄像机用透视模式Perspective时FOV 和摄像机角度直接决定人物在不同位置的缩放感。如果 FOV 太大人物走到画面边缘会拉伸变形FOV 太小透视感又不够看起来像正交。我一般会这样设参数推荐值说明FOV3545小于 30 透视感弱大于 50 边缘畸变明显摄像机角度X 轴 3045 度俯视角度决定看到地面的比例远裁面根据场景深度设太小会裁掉远处背景近裁面0.10.3太大会导致近处人物被裁摄像机角度这块有个血泪经验X 轴角度不要超过 50 度否则地面在画面里占比太大人物看起来像趴在地上。30 到 40 度之间是比较舒服的斜俯视。2.3 人物缩放与透视的联动透视摄像机下人物离摄像机越远在画面上越小。但 2D Sprite 默认不会自动缩放需要手动根据距离算缩放系数。// 根据人物到摄像机的距离动态调整 Sprite 缩放 updateSpriteScale() { var camPos this.cameraNode.getPosition(); var personPos this.node.getPosition(); // 计算人物到摄像机的水平距离 var dist cc.v2(personPos.x - camPos.x, personPos.z - camPos.z).mag(); // 基准距离即人物在画面中原始大小对应的距离 var baseDist 10; // 缩放系数 基准距离 / 当前距离 var scale baseDist / dist; // 限制缩放范围避免过大或过小 scale cc.misc.clampf(scale, 0.5, 2.0); this.node.scale scale; }这里 baseDist 需要根据你的场景实际尺寸来定。调的时候先把人物放在画面中间看 Sprite 原始大小是否合适然后反推 baseDist。clampf 的限制范围也要根据项目调太小会导致远处人物看不清太大会导致近处人物占满屏幕。3. 人物移动与输入映射从屏幕点击到 3D 地面坐标3.1 屏幕坐标转 3D 地面坐标的射线检测玩家点击屏幕时你拿到的是屏幕坐标。要把这个坐标转成 3D 地面上的人物目标位置需要用射线检测。// 屏幕点击转 3D 地面坐标 onTouchEnd(event) { var touchPos event.getLocation(); // 从摄像机发射射线 var ray new cc.geom.Ray(); this.cameraNode.getComponent(cc.Camera).screenPointToRay( touchPos.x, touchPos.y, ray ); // 与地面平面求交地面 Y groundY var groundPlane new cc.geom.Plane( cc.v3(0, 1, 0), // 法线朝上 -this.groundY // 平面方程常数项 ); var distance cc.geom.intersect.rayPlane(ray, groundPlane); if (distance ! null) { var hitPoint ray.getPoint(distance); // hitPoint 就是点击位置在地面上的 3D 坐标 this.moveTo(hitPoint); } }screenPointToRay 把屏幕坐标转成一条从摄像机出发的射线rayPlane 求射线与地面的交点。注意平面方程的参数法线 (0,1,0) 表示水平面常数项是 -groundY因为平面方程是 n·p d 0代入 p.y groundY 得 d -groundY。3.2 移动插值与朝向翻转拿到目标点后人物需要平滑移动过去而不是瞬移。同时根据移动方向翻转 Sprite 的 scaleX 来实现朝向变化。// 平滑移动到目标点 moveTo(targetPos) { this.targetPos targetPos; this.isMoving true; // 根据目标位置在人物左侧还是右侧决定朝向 var dir targetPos.x - this.node.x; if (Math.abs(dir) 0.01) { this.node.scaleX dir 0 ? Math.abs(this.node.scaleX) : -Math.abs(this.node.scaleX); } }, update(dt) { if (this.isMoving this.targetPos) { var curPos this.node.getPosition(); // 计算到目标点的方向 var dir cc.v3( this.targetPos.x - curPos.x, 0, this.targetPos.z - curPos.z ); var dist dir.mag(); if (dist 0.05) { // 到达目标点 this.node.setPosition(this.targetPos); this.isMoving false; this.playIdle(); } else { // 按速度移动 dir.normalize(); var moveStep this.speed * dt; var newPos cc.v3( curPos.x dir.x * moveStep, curPos.y, curPos.z dir.z * moveStep ); this.node.setPosition(newPos); this.playRun(); } } }speed 参数控制移动速度单位是米/秒。这个值要和 pixelToMeter 配合调如果 pixelToMeter 是 0.01speed 设 3 到 5 比较合适。朝向翻转用 scaleX 的正负来实现注意要先取绝对值再乘符号避免多次翻转后 scaleX 累积异常。3.3 移动边界与地面碰撞人物不能走出地面范围需要加边界限制。常见做法是在逻辑坐标层面做 clamp而不是在 3D 坐标层面。// 逻辑坐标边界限制 clampLogicPos(pos) { return cc.v2( cc.misc.clampf(pos.x, this.minX, this.maxX), cc.misc.clampf(pos.y, this.minY, this.maxY) ); }minX、maxX、minY、maxY 根据你的地面尺寸和 pixelToMeter 反推。比如地面在 3D 世界里是 20 米 × 20 米pixelToMeter 是 0.01那逻辑坐标范围就是 -1000 到 1000。这个边界值建议做成可配置的方便在编辑器里调。4. 避坑与排查2D/3D 混合渲染的五个翻车现场4.1 人物被 3D 模型遮挡层级错乱现象人物走到某些 3D 物体后面时应该被遮挡但实际上人物永远显示在最前面或者反过来被莫名其妙遮住。原因2D Sprite 和 3D 模型的渲染排序不在同一个体系里。Cocos Creator 2.4.x 中3D 模型走的是不透明队列2D Sprite 走的是透明队列两者的深度测试规则不同。解决给 3D 场景中需要遮挡人物的物体单独设置渲染层级或者用深度写入的方式处理。简单做法是把人物 Sprite 的材质改成带深度测试的版本在自定义材质里开启 depthTest。如果项目对遮挡要求不高也可以把人物节点的 zPosition 手动设一个很小的偏移让它始终在 3D 物体前面。4.2 人物移动时抖动或跳帧现象人物在移动过程中位置不平滑有肉眼可见的抖动。原因update 里同时做了坐标同步和移动插值两套逻辑互相干扰。或者 pixelToMeter 设得太大导致每帧移动步长超过一个像素。解决把坐标同步和移动逻辑分开移动逻辑只更新 logicPos坐标同步只负责把 logicPos 映射到世界坐标。pixelToMeter 建议不要超过 0.02否则每帧移动距离太大看起来会跳。4.3 点击位置偏移人物走到错误的地方现象点击屏幕某个位置人物却走到旁边去了。原因射线检测用的摄像机不对或者屏幕坐标没有做适配处理。Cocos Creator 2.4.x 里event.getLocation() 返回的是设计分辨率下的坐标如果你的 Canvas 做了适配缩放需要先转换。解决确认 screenPointToRay 用的是主摄像机并且触摸坐标经过 cc.view 的适配转换。可以在 onTouchEnd 里先打印 touchPos 和射线起点看是否匹配。4.4 人物缩放后碰撞检测失效现象人物在远处缩得很小但点击它时判定区域还是原始大小。原因碰撞检测用的是节点原始尺寸没有考虑 scale 的影响。解决如果用的是 cc.Node 的点击事件需要在缩放后同步更新节点的 contentSize 或者碰撞体尺寸。更稳妥的做法是用逻辑坐标做距离判定而不是依赖节点的物理碰撞。4.5 3D 背景在低端机上帧率骤降现象加了 3D 背景后低端安卓机帧率从 60 掉到 20 多。原因3D 场景的面数太多或者用了实时光照和阴影。解决3D 背景尽量用烘焙光照关掉实时阴影。如果背景是静态的可以考虑烘焙成序列帧或者用简单的面片代替。2.4.10 对 3D 的支持本身就不是强项背景模型面数控制在 5000 面以内比较安全。5. 进阶技巧用逻辑坐标层做一套可复用的 2.5D 移动框架上面讲的都是单个人物的处理。实际项目里你可能会有多个 NPC、多个可点击物体每个都单独写一套坐标同步逻辑会很乱。我一般会抽一个「逻辑坐标层」出来所有 2D 元素都注册到这个层里统一做坐标映射和排序。// 逻辑坐标管理器 cc.Class({ extends: cc.Component, properties: { pixelToMeter: 0.01, groundY: 0, }, // 注册一个 2D 节点到逻辑坐标层 register(node, logicPos) { if (!this._nodes) this._nodes []; this._nodes.push({ node: node, logicPos: logicPos }); }, // 每帧统一同步所有注册节点的世界坐标 update(dt) { if (!this._nodes) return; for (var i 0; i this._nodes.length; i) { var item this._nodes[i]; var worldX item.logicPos.x * this.pixelToMeter; var worldZ item.logicPos.y * this.pixelToMeter; item.node.setPosition(worldX, this.groundY, worldZ); } // 按逻辑 Y 坐标排序Y 越小越靠前渲染层级越高 this._nodes.sort(function(a, b) { return b.logicPos.y - a.logicPos.y; }); for (var j 0; j this._nodes.length; j) { this._nodes[j].node.zIndex j; } }, });这套框架的好处是所有 2D 元素的坐标同步和渲染排序都在一个地方管新增 NPC 只需要 register 一下不用改移动逻辑。排序规则是按逻辑 Y 坐标降序Y 越小表示越靠近摄像机zIndex 越高这样人物走到 NPC 前面时能正确遮挡。验证方法很简单放两个人物一个在前一个在后让前面的人物走到后面人物的上方逻辑 Y 更大看渲染层级是否自动切换。如果切换正确说明排序逻辑没问题。从那以后我每次做 2.5D 项目都会先把逻辑坐标层搭好再往上堆人物和交互。这套东西不复杂但能省掉后面大量的层级调试时间。希望帮到你。本文还有配套的精品资源点击获取