通过《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
的配置
这样玩家的摄像机就可以跟玩家一起移动: