通过《Cocos 2.x-Hello World 飞机大战游戏》的简单实践,算是入门了Cocos游戏开发,查看了官方手册3.8的入门游戏,了解了一些游戏的概念,通过2.4来实现这个小游戏,这里记录一下实践过程。
1. 环境配置
编辑器版本V2.4.11,设计分辨率960x640,固定高度:
官方手册文档地址:
https://docs.cocos.com/creator/manual/zh/getting-started/first-game-2d/
2. 创建主角
在Canvas创建一个空节点Player作为主角节点,并在Player节点下面创建一个精灵节点(渲染节点Sprite,单色)作为玩家的身体部分,取名Body,将Body的Position.y设置成40,大小也调整为40x40,并调整其颜色为红色。
即Player可能有多个部分组成,如:
身体:Body(渲染节点Sprite)
昵称:Label
血条:自定义UI
创建Typescript脚本组件(JumpPlayer)并挂在Player节点中。
3. 创建地图
跟创建Player的Body一样,在Canvas下面创建一个单色Sprite节点,并制作成预制体:
如图:红色代表玩家,白色代表地图
4. 让主角动起来
这里利用鼠标单击让主角跳起来,当鼠标单击左键时,跳一步,当鼠标单击右键时,跳两步。
新增JumpPlayerController脚本组件,并挂在Canvas上面,实现鼠标单击的监听:
import JumpPlayer from "./JumpPlayer"; const { ccclass, property } = cc._decorator; @ccclass export default class JumpPlayerController extends cc.Component { @property(cc.Node) player: cc.Node = null; playerComponent: JumpPlayer = null; onLoad() { this.playerComponent = this.player.getComponent(JumpPlayer); } start() { this.node.on( cc.Node.EventType.MOUSE_UP, (e: cc.Event.EventMouse) => { if (e.getButton() == 0) { this.playerComponent.jump(1); } else if (e.getButton() == 2) { this.playerComponent.jump(2); } }, this ); } }
这里的player是一个cc.Node,挂载的是Player节点,用于控制Player节点的移动,具体的移动代码实现如下:
const { ccclass, property } = cc._decorator; const BLOCK_SIZE = 40; @ccclass export default class JumpPlayer extends cc.Component { jumping: boolean = false; step: number = 1; // 移动时长 duration: number = 0.1; speed: number = 0; // 移动了多久 jumpTime: number = 0; // 位置 current: cc.Vec2 = new cc.Vec2(); temp: cc.Vec2 = new cc.Vec2(); dist: cc.Vec2 = new cc.Vec2(); // onLoad () {} start() {} update(deltaTime) { if (this.jumping) { this.jumpTime += deltaTime; if (this.jumpTime > this.duration) { this.node.setPosition(this.dist); this.jumping = false; } else { this.node.setPosition(this.current); this.temp.x = this.speed * deltaTime; cc.Vec2.add(this.current, this.current, this.temp); this.node.setPosition(this.current); } } } // P_1 = P_0 + v*t jump(step: number) { if (this.jumping) { return; } this.jumping = true; this.step = step; // 计算速度 const distance = this.step * BLOCK_SIZE; this.speed = distance / this.duration; this.jumpTime = 0; this.node.getPosition(this.current); cc.Vec2.add(this.dist, this.current, new cc.Vec2(distance, 0)); } }
这里的位置计算使用的是向量,简单理解为有方向的距离(可以参考野生程序君的解释),代码逻辑参考Cocos3.8的官方手册实例代码,最终的移动效果:
5. 制作动画
给Player的Body节点新增一个动画组件(Animation),并在assets/jump/animation中创建AnimationClip资源挂载在Animaction组件的Clip字段上。
在动画编辑器中,添加position属性,选中Body设置position.y=40(可能需要改变一下数值才能生成帧),然后将动画帧拖到0.10的地方,将Body的position.y设置成120,继续将动画帧拖动到0.20的地方,将Body的position.y重新设置成40,这样点击播放按钮就可以看到动画了:
用同样的方法制作step2,移动两步的动画帧(间隔设置成0.2,即0,0.2,0.4)
调整Player脚本,计算动画时长调整移动时长,使得动画播放更加平滑:
// 需要将Body拖到该属性上 @property(cc.Animation) bodyAnimation: cc.Animation = null; // P_1 = P_0 + v*t jump(step: number) { if (this.jumping) { return; } this.jumping = true; this.step = step; const clip = `step${step}`; this.duration = this.bodyAnimation.getAnimationState(clip).duration; // 计算速度 const distance = this.step * BLOCK_SIZE; this.speed = distance / this.duration; this.jumpTime = 0; this.node.getPosition(this.current); cc.Vec2.add(this.dist, this.current, new cc.Vec2(distance, 0)); this.bodyAnimation.play(clip); }
动画相关的API文档:
https://docs.cocos.com/creator/2.4/api/zh/classes/Animation.html
6. 游戏管理器
关于Manager,官方文档是这样说的:
一般情况为了保存游戏的数据,我们需要创建一些类来辅助这类工作。
创建一个GameManager节点,并创建对应的JumpGameManager脚本组件挂载在它上面,用于生成地图块:
const { ccclass, property } = cc._decorator; import { BLOCK_SIZE } from "./JumpPlayer"; enum Block { NONE, STONE, } @ccclass export default class JumpGameManager extends cc.Component { // Box预制体 @property(cc.Prefab) box: cc.Prefab = null; distance: number = 50; blockArray: Block[] = []; // onLoad () {} start() { this.renderBlock(); } // update (dt) {} renderBlock() { this.node.removeAllChildren(); this.blockArray = []; // 第一个必须是STONE this.blockArray.push(Block.STONE); for (let i = 1; i < this.distance; i++) { if (this.blockArray[i - 1] == Block.NONE) { // 不能出现连续的坑 this.blockArray.push(Block.STONE); } else { // 随机生成0或1,0=NONE、1=STONE this.blockArray.push(Math.floor(Math.random() * 2)); } } for (let i = 0; i < this.blockArray.length; i++) { const block = this.spawnBlock(this.blockArray[i]); if (block) { this.node.addChild(block); block.setPosition(i * BLOCK_SIZE, 0); } } } spawnBlock(block: Block) { if (this.box && block == Block.STONE) { return cc.instantiate(this.box); } return null; } }
地图生成效果:
7. 相机和卷轴
2.x的Canvas跟3.x稍有不同,这里的做法跟3.x的案例不太一样,2.4的摄像机文档地址:
https://docs.cocos.com/creator/2.4/manual/zh/render/camera.html
使用两个摄像机、也就是给玩家添加一个特写摄像机,并且取消主摄像机的Align with screen
的配置
这样玩家的摄像机就可以跟玩家一起移动:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)