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); } } } }