2D example
PlayerController
import { _decorator, Component, EventMouse, Node, input, Input, Animation, log, Vec3 } from 'cc';
const { ccclass, property } = _decorator;
export const BLOCK_SIZE = 100;
@ccclass('PlayerController')
export class PlayerController extends Component {
@property(Animation)
BodyAnim: Animation = null;
private _startJump: boolean = false;
private _jumpStep: number = 0;
private _jumpTime: number = 0;
private _curJumpTime: number = 0;
private _curJumpSpeed: number = 0;
private _curPos: Vec3 = new Vec3();
private _deltaPos: Vec3 = new Vec3(0, 0, 0);
private _targetPos: Vec3 = new Vec3();
private _number: number = 0;
private _animationPlayed: boolean = false;
private _curMoveIndex: number = 0;
start() {
// input.on(Input.EventType.MOUSE_UP, this.onMouseUp, this);
}
setInputActive(active: boolean) {
if (active) {
input.on(Input.EventType.MOUSE_UP, this.onMouseUp, this);
} else {
input.off(Input.EventType.MOUSE_UP, this.onMouseUp, this);
}
}
onMouseUp(event: EventMouse) {
if (event.getButton() === 0) {
this.jumpByStep(1);
} else if (event.getButton() === 2) {
this.jumpByStep(2);
}
}
reset() {
this._curMoveIndex = 0;
this.node.getPosition(this._curPos);
this._targetPos.set(0, 0, 0);
}
onOnceJumpEnd() {
this.node.emit('JumpEnd', this._curMoveIndex);
}
jumpByStep(step: number) {
if (this._startJump) {
return;
}
this._startJump = true;
this._jumpStep = step;
this._curJumpTime = 0;
// 速度 = 距离 / 时间
this._curJumpSpeed = this._jumpStep * BLOCK_SIZE / this._jumpTime;
this.node.getPosition(this._curPos);
Vec3.add(this._targetPos, this._curPos, new Vec3(this._jumpStep * BLOCK_SIZE, 0, 0));
// 读取动画时间
const state = this.BodyAnim.getState('jump');
this._jumpTime = state.duration;
if (this.BodyAnim) {
if (step === 1 || step === 2) {
this.BodyAnim.play('jump');
}
}
this._curMoveIndex += step;
}
update(deltaTime: number) {
if (this._startJump) {
this._curJumpTime += deltaTime;
if (this._curJumpTime > this._jumpTime) {
this._startJump = false;
this.node.setPosition(this._targetPos);
this.onOnceJumpEnd();
} else {
this.node.getPosition(this._curPos);
// 位移 = 速度 * 时间间隔
// 最终位置 = 当前位置 + 平均速度 * 时间间隔
this._deltaPos.x = this._curJumpSpeed * deltaTime;
Vec3.add(this._curPos, this._curPos, this._deltaPos);
this.node.setPosition(this._curPos);
}
}
if (!this.BodyAnim.getState('walk').isPlaying && !this.BodyAnim.getState('jump').isPlaying) {
this.BodyAnim.play('walk');
}
}
}
GameManager
import { _decorator, CCInteger, Component, instantiate, Label, Node, Prefab, Vec3 } from 'cc';
import { BLOCK_SIZE, PlayerController } from './PlayerController';
const { ccclass, property } = _decorator;
enum BlockType {
BT_NONE,
BT_STONE,
};
enum GameState {
GS_INIT,
GS_PLAYING,
GS_END,
};
@ccclass('GameManager')
export class GameManager extends Component {
@property({ type: Prefab })
public boxPerfab: Prefab | null = null;
@property({ type: CCInteger })
private roadLength: number = 50;
private _road: BlockType[] = [];
@property({ type: Node })
public startMenu: Node | null = null; //开始的ui
@property({ type: PlayerController })
public playerCtrl: PlayerController | null = null; //角色控制器
@property({ type: Label })
public stepLabel: Label | null = null; //计步器
start() {
// 第一初始化要在 start 里面调用
this.setCurState(GameState.GS_INIT);
this.playerCtrl?.node.on('JumpEnd', this.onPlayerJumpEnd, this);
}
init() {
// init 时我们先显示 StartMenu、创建地图以及重设角色的为和状态并禁用角色输入。
if (this.startMenu) {
this.startMenu.active = true;
}
this.generateRoad();
if (this.playerCtrl) {
this.playerCtrl.setInputActive(false);
this.playerCtrl.node.setPosition(new Vec3(0, 100, 0));
this.playerCtrl.reset();
}
}
update(deltaTime: number) {
}
setCurState(value: GameState) {
switch (value) {
case GameState.GS_INIT:
this.init();
break;
case GameState.GS_PLAYING:
this.playing();
break;
case GameState.GS_END:
break;
}
}
onStartButtonClicked() {
this.setCurState(GameState.GS_PLAYING);
}
onPlayerJumpEnd(moveIndex: number) {
if (this.stepLabel) {
this.stepLabel.string = '' + (moveIndex >= this.roadLength ? this.roadLength : moveIndex);
}
this.checkResult(moveIndex);
}
playing() {
if (this.startMenu) {
this.startMenu.active = false;
}
if (this.stepLabel) {
this.stepLabel.string = '0';
}
//直接设置active会直接开始监听鼠标事件,做了一下延迟处理
setTimeout(() => {
if (this.playerCtrl) {
this.playerCtrl.setInputActive(true);
}
});
}
// 判定角色是否跳跃到坑或者跳完所有地块的方法
checkResult(moveIndex: number) {
if (moveIndex < this.roadLength) {
if (this._road[moveIndex] == BlockType.BT_NONE) {
// 跳到了空方块
this.setCurState(GameState.GS_INIT);
}
} else {
this.setCurState(GameState.GS_INIT);
}
}
generateRoad() {
this.node.removeAllChildren();
this._road = [];
this._road.push(BlockType.BT_STONE);
for (let i = 1; i < this.roadLength; i++) {
if (this._road[i - 1] === BlockType.BT_NONE) {
this._road.push(BlockType.BT_STONE);
} else {
// 从 [0, 2) 中随机取 1个数并向下取整,得到的结果是 0 或者 1
this._road.push(Math.floor(Math.random() * 2));
}
}
for (let j = 0; j < this.roadLength; j++) {
let block: Node | null = this.spawnBlockByType(this._road[j]);
if (block) {
this.node.addChild(block);
block.setPosition(j * BLOCK_SIZE, 0, 0);
}
}
}
spawnBlockByType(type: BlockType) {
if (!this.boxPerfab) {
return null;
}
let block: Node | null = null;
switch (type) {
case BlockType.BT_STONE:
// instantiate: 是 Cocos Creator 提供的克隆预制体的方法
block = instantiate(this.boxPerfab);
break;
}
return block;
}
}
参考 https://docs.cocos.com/creator/3.8/manual/zh/getting-started/first-game-2d/