Files
cocos/assets/scripts/controller/VehicleController.ts
刘宇飞 d393302388 Complete Cocos Creator port with level bundles, themes, and tooling.
Adds level prefabs, theme assets, audio, extensions, and deployment scripts for the Unity WebGL migration.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 15:30:58 +08:00

185 lines
5.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { _decorator, Vec3 } from 'cc';
import { Direction, GridType } from '../core/Define';
import { EventManager, EventType } from '../core/EventManager';
import { JsBridge } from '../bridge/JsBridge';
import { GameManager } from '../manager/GameManager';
import { scaledMoveSpeed, UNITY_VEHICLE_MOVE_SPEED } from '../core/GridConstants';
import { Movement } from '../gameplay/Movement';
import { PlayerController, ExternalDataList } from './PlayerController';
import { syncRidePositions } from './RideLink';
import { VisualAssets } from '../visual/VisualAssets';
const { ccclass } = _decorator;
/**
* 载具移动(对齐 Unity VehicleController
* - 仅能在空地移动None↔None、Ride→None
* - 有骑手时每帧同步玩家;落格更新 Ride 注册
*/
@ccclass('VehicleController')
export class VehicleController extends Movement {
private player: PlayerController | null = null;
onLoad() {
this.moverRole = 'vehicle';
this.moveSpeed = scaledMoveSpeed(UNITY_VEHICLE_MOVE_SPEED);
this.moveState = 0;
}
/** 不调用 super.start(),避免 component.start 晚于 LevelInit 绑定后再次用 spawn 方向刷贴图 */
start() {
this.syncCommittedCellFromPosition();
if (this.player) {
this.syncFacingFromRider();
}
this.setIcon();
}
setPlayer(p: PlayerController | null) {
this.player = p;
if (!p) return;
if (p.direction !== this.direction) {
super.setDirection(p.direction);
}
this.setIcon();
}
getPlayer(): PlayerController | null {
return this.player;
}
setPosition(pos: Vec3) {
this.node.setPosition(pos);
}
setName(_name: string) {
/* 可挂 Label */
}
override setDirection(dir: Direction) {
super.setDirection(dir);
this.setIcon();
if (Movement.callEach) return;
Movement.callEach = true;
this.player?.setDirection(dir);
Movement.callEach = false;
}
private entityVisualOptions() {
const gm = GameManager.instance;
const levelTheme = gm?.getCurLevel()?.theme?.trim();
return {
...(gm?.getEntityVisualOptions() ?? {}),
theme: levelTheme ?? gm?.uiStyle ?? 'default',
};
}
/** 载具四向贴图:有骑手时跟随骑手 direction转向时 setIcon 直接换图 */
private iconDirection(): Direction {
return this.player?.direction ?? this.direction;
}
setIcon() {
const dir = this.iconDirection();
if (this.player && dir !== this.direction) {
super.setDirection(dir);
}
VisualAssets.applyVehicleIconForDirection(
this.node,
dir,
this.entityVisualOptions(),
);
this.player?.syncRideMountVisual();
}
/** 骑乘时逻辑朝向与骑手保持一致Scratch 回传等) */
private syncFacingFromRider() {
if (!this.player || this.player.direction === this.direction) return;
super.setDirection(this.player.direction);
}
/** 主题 / 软重置后按当前逻辑朝向重刷贴图 */
refreshIcon() {
this.syncFacingFromRider();
this.setIcon();
}
override callJump() {
/* 载具不可跳跃 */
}
protected override syncRideAfterMoveStep() {
if (this.player) syncRidePositions('vehicle', this.player, this);
}
protected onMoveNextSet(isJump: boolean) {
if (Movement.callEach) return;
Movement.callEach = true;
if (this.player) {
this.player.setTargetGridType(this.targetGridType);
this.player.syncFromVehicle(this.targetGridType, isJump);
}
Movement.callEach = false;
}
protected onMoving() {
if (this.player) syncRidePositions('vehicle', this.player, this);
if (Movement.callEach) return;
Movement.callEach = true;
this.player?.onMoving();
Movement.callEach = false;
}
protected onMoveToTarget() {
this.commitLandingCell();
const gm = GameManager.instance!;
gm.removeObj(this.lastPosition);
if (this.committedCell) {
gm.addObjAtCell(this.committedCell, GridType.Ride, this.node);
} else {
gm.addObj(this.node.position, GridType.Ride, this.node);
}
if (!Movement.callEach && this.player) {
Movement.callEach = true;
this.player.setRideBaseFromVehicle(this.node.position);
if (this.committedCell) this.player.shareCommittedCell(this.committedCell);
this.player.syncMoveToTargetFromVehicle();
Movement.callEach = false;
}
if (this.step === 0) this.externalCall();
}
protected onMoveFail(_isJump: boolean) {
this.externalCall();
EventManager.dispatch(EventType.InputEnd, GameManager.instance!.gameState);
}
callVehicleInfo() {
this.externalCall();
}
externalCall() {
const gm = GameManager.instance!;
const list: ExternalDataList = { direction: this.direction, externalDatas: [] };
const sample = this.getGridSamplePosition();
const self = gm.worldToCell(sample);
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(sample, d);
const cell = gm.worldToCell(wp);
list.externalDatas.push({
position: { x: cell.x, y: cell.y, z: 0 },
gridType: gm.calculateNextGridType(sample, d),
direction: gm.getRelativePosition(this.direction, d),
});
}
JsBridge.call('processVehicleData', JSON.stringify(list));
}
}