Includes core gameplay, 600 exported levels, visual assets, web bridge, and bootstrap scene. Co-authored-by: Cursor <cursoragent@cursor.com>
214 lines
7.1 KiB
TypeScript
214 lines
7.1 KiB
TypeScript
import { _decorator, Vec3 } from 'cc';
|
|
import { Direction, GameState, GridType, Skin } from '../core/Define';
|
|
import { EventManager, EventType } from '../core/EventManager';
|
|
import { JsBridge } from '../bridge/JsBridge';
|
|
import { GameManager } from '../manager/GameManager';
|
|
import { Movement } from '../gameplay/Movement';
|
|
import { VehicleController } from './VehicleController';
|
|
import { VisualAssets } from '../visual/VisualAssets';
|
|
|
|
const { ccclass } = _decorator;
|
|
|
|
export interface ExternalData {
|
|
position: { x: number; y: number; z: number };
|
|
gridType: number;
|
|
direction: string;
|
|
}
|
|
|
|
export interface ExternalDataList {
|
|
direction: number;
|
|
externalDatas: ExternalData[];
|
|
}
|
|
|
|
export interface ExternalResult {
|
|
isWin: boolean;
|
|
stepNum: number;
|
|
direction: number;
|
|
isInputEnd: boolean;
|
|
}
|
|
|
|
@ccclass('PlayerController')
|
|
export class PlayerController extends Movement {
|
|
coins = 0;
|
|
private vehicle: VehicleController | null = null;
|
|
private sendFinally = false;
|
|
|
|
onLoad() {
|
|
this.moverRole = 'player';
|
|
EventManager.register(EventType.LevelInit, this.onLevelInit);
|
|
EventManager.register(EventType.InputEnd, this.onInputEnd);
|
|
this.coins = 0;
|
|
}
|
|
|
|
onDestroy() {
|
|
EventManager.remove(EventType.LevelInit, this.onLevelInit);
|
|
EventManager.remove(EventType.InputEnd, this.onInputEnd);
|
|
}
|
|
|
|
start() {
|
|
super.start();
|
|
VisualAssets.applyPlayerSprite(this.node, this.direction);
|
|
if (this.node.name === 'Player' && GameManager.instance) {
|
|
this.callChangeSkin(GameManager.instance.playerSkin);
|
|
}
|
|
}
|
|
|
|
override setDirection(dir: Direction) {
|
|
super.setDirection(dir);
|
|
VisualAssets.applyPlayerSprite(this.node, dir);
|
|
}
|
|
|
|
private onLevelInit = () => {
|
|
this.checkRide();
|
|
};
|
|
|
|
private onInputEnd = () => {
|
|
this.externalCallResult(false);
|
|
};
|
|
|
|
protected onMoveNextSet(isJump: boolean) {
|
|
if (isJump && this.targetGridType === GridType.Jump) {
|
|
const p = this.node.worldPosition.clone();
|
|
p.y += 0.15;
|
|
this.targetPosition.set(p);
|
|
}
|
|
}
|
|
|
|
onMoving() {
|
|
if (this.targetGridType === GridType.None && this.vehicle && !Movement.callEach) {
|
|
this.vehicle.setPosition(this.node.worldPosition);
|
|
}
|
|
}
|
|
|
|
protected onMoveFail(isJump: boolean) {
|
|
this.externalCallResult(false);
|
|
const gm = GameManager.instance!;
|
|
if (gm.multMode) {
|
|
const other = gm.findNodeByName(this.node.name === 'Player' ? 'Enemy' : 'Player');
|
|
other?.getComponent(PlayerController)?.externalCallResult(true);
|
|
}
|
|
console.log(`${this.node.name} 无法移动`, isJump);
|
|
}
|
|
|
|
protected onMoveToTarget() {
|
|
if (this.curGrid === GridType.Ride) {
|
|
const obj = GameManager.instance!.getGameObject(this.node.worldPosition);
|
|
if (obj) {
|
|
this.vehicle = obj.getComponent(VehicleController);
|
|
this.vehicle?.setPlayer(this);
|
|
if (this.vehicle) this.vehicle.setDirection(this.direction);
|
|
}
|
|
} else if (this.curGrid !== GridType.None && this.vehicle) {
|
|
this.vehicle.setPlayer(null);
|
|
this.vehicle = null;
|
|
}
|
|
if (this.vehicle) {
|
|
this.vehicle.setPosition(this.node.worldPosition);
|
|
GameManager.instance!.removeObj(this.lastPosition);
|
|
GameManager.instance!.addObj(this.node.worldPosition, GridType.Ride, this.vehicle.node);
|
|
}
|
|
this.externalCall();
|
|
}
|
|
|
|
callChangeSkin(n: number) {
|
|
if (n < 0 || n > Skin.sanxing) return;
|
|
if (GameManager.instance) GameManager.instance.playerSkin = n as Skin;
|
|
}
|
|
|
|
callPlayerInfo() {
|
|
this.externalCall();
|
|
}
|
|
|
|
setName(name: string) {
|
|
this.vehicle?.setName(name);
|
|
}
|
|
|
|
getCoinsNum() {
|
|
JsBridge.call('coinsData', JSON.stringify({ coinsNum: this.coins, gameObjectName: this.node.name }));
|
|
}
|
|
|
|
addCoins() {
|
|
this.coins++;
|
|
}
|
|
|
|
setPosition(pos: Vec3) {
|
|
this.node.setPosition(pos);
|
|
}
|
|
|
|
/** 供 VehicleController 同步 */
|
|
syncFromVehicle(targetGridType: GridType, isJump: boolean) {
|
|
this.targetGridType = targetGridType;
|
|
this.onMoveNextSet(isJump);
|
|
}
|
|
|
|
syncMoveToTargetFromVehicle() {
|
|
this.onMoveToTarget();
|
|
}
|
|
|
|
externalCall() {
|
|
const gm = GameManager.instance!;
|
|
const list: ExternalDataList = { direction: this.direction, externalDatas: [] };
|
|
const self = gm.worldToCell(this.node.worldPosition);
|
|
list.externalDatas.push({
|
|
position: { x: self.x, y: self.y, z: 0 },
|
|
gridType: this.curGrid,
|
|
direction: 'self',
|
|
});
|
|
for (let d = Direction.North; d <= Direction.West; d++) {
|
|
const wp = gm.nextGridPosition(this.node.worldPosition, d);
|
|
const cell = gm.worldToCell(wp);
|
|
list.externalDatas.push({
|
|
position: { x: cell.x, y: cell.y, z: 0 },
|
|
gridType: gm.calculateNextGridType(this.node.worldPosition, d),
|
|
direction: gm.getRelativePosition(this.direction, d),
|
|
});
|
|
}
|
|
const json = JSON.stringify(list);
|
|
if (gm.multMode) JsBridge.call(`process${this.node.name}`, json);
|
|
else JsBridge.call('processData', json);
|
|
}
|
|
|
|
externalCallResult(isWin: boolean) {
|
|
const gm = GameManager.instance!;
|
|
if (isWin && (this.node.name === 'Player' || this.node.name === gm.multPlayerRole)) {
|
|
/* success audio */
|
|
} else if (!isWin && (this.node.name === 'Player' || this.node.name === gm.multPlayerRole)) {
|
|
/* fail audio */
|
|
}
|
|
let myStep = gm.stepNum;
|
|
if (gm.multMode) {
|
|
switch (gm.multPlayerRole) {
|
|
case 'PlayerA1': myStep = gm.stepA1Num; break;
|
|
case 'PlayerA2': myStep = gm.stepA2Num; break;
|
|
case 'PlayerA3': myStep = gm.stepA3Num; break;
|
|
case 'PlayerB1': myStep = gm.stepB1Num; break;
|
|
case 'PlayerB2': myStep = gm.stepB2Num; break;
|
|
case 'PlayerB3': myStep = gm.stepB3Num; break;
|
|
}
|
|
}
|
|
if ((this.node.name === 'Player' || this.node.name === gm.multPlayerRole) && !this.sendFinally) {
|
|
const payload: ExternalResult = {
|
|
isWin,
|
|
stepNum: myStep,
|
|
direction: this.direction,
|
|
isInputEnd: gm.isInputEnd,
|
|
};
|
|
JsBridge.call('externalResult', JSON.stringify(payload));
|
|
this.sendFinally = true;
|
|
}
|
|
if (gm.gameState !== GameState.Run) return;
|
|
gm.setGameState(isWin ? GameState.ResultWin : GameState.ResultFail);
|
|
}
|
|
|
|
private checkRide() {
|
|
if (this.curGrid === GridType.Ride) {
|
|
const obj = GameManager.instance!.getGameObject(this.node.worldPosition);
|
|
if (obj) {
|
|
this.vehicle = obj.getComponent(VehicleController);
|
|
this.vehicle?.setDirection(this.direction);
|
|
this.vehicle?.setPlayer(this);
|
|
}
|
|
}
|
|
}
|
|
}
|