Files
cocos/assets/scripts/controller/RideLink.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

158 lines
5.6 KiB
TypeScript
Raw 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 { Vec3 } from 'cc';
import { GridType } from '../core/Define';
import { GameManager } from '../manager/GameManager';
import { forEachLevelEntityNode } from '../level/TileLayout';
import { entityWorldPositionForRole, worldToMoverCellForRole } from '../level/EntitySpawnPlacement';
import { PlayerController } from './PlayerController';
import { VehicleController } from './VehicleController';
/** 按逻辑格查找载具gridTypes + 当前 committedCell */
export function findVehicleAtCell(cell: Vec3): VehicleController | null {
const gm = GameManager.instance;
if (!gm) return null;
const fromGrid = gm.getGameObjectAtCell(cell)?.getComponent(VehicleController);
if (fromGrid) return fromGrid;
const level = gm.curLevel;
if (!level) return null;
let found: VehicleController | null = null;
forEachLevelEntityNode(level, (ch) => {
if (found || !ch.name.includes('Vehicle')) return;
const vc = ch.getComponent(VehicleController);
if (!vc || !vehicleMatchesCell(vc, cell)) return;
found = vc;
});
return found;
}
/** 双向绑定玩家与载具,并确保 Ride 格注册 */
export function linkRidePair(player: PlayerController, vehicle: VehicleController, cell: Vec3) {
const gm = GameManager.instance;
if (!gm) return;
const config = gm.getCurLevel();
const theme = config?.theme ?? gm.uiStyle;
const deck = entityWorldPositionForRole(cell, config ?? undefined, theme, 'vehicle');
player.setRideVehicle(vehicle);
vehicle.setPlayer(player);
vehicle.setDirection(player.direction);
player.shareCommittedCell(cell);
vehicle.shareCommittedCell(cell);
vehicle.node.setPosition(deck);
gm.addObjAtCell(cell, GridType.Ride, vehicle.node);
player.setRideBaseFromVehicle(deck);
}
function playerLogicCell(player: PlayerController): Vec3 {
const committed = player.getCommittedCell();
if (committed) return committed.clone();
const gm = GameManager.instance!;
const config = gm.getCurLevel();
const theme = config?.theme ?? gm.uiStyle;
return worldToMoverCellForRole(
player.node.position,
config ?? undefined,
theme,
'player',
);
}
function vehicleLogicCell(vehicle: VehicleController): Vec3 | null {
const committed = vehicle.getCommittedCell();
if (committed) return committed.clone();
const spawn = vehicle.getSpawnCell() ?? vehicle.getCommittedCell();
if (spawn) return spawn.clone();
const gm = GameManager.instance;
if (!gm) return null;
const config = gm.getCurLevel();
const theme = config?.theme ?? gm.uiStyle;
return worldToMoverCellForRole(vehicle.node.position, config ?? undefined, theme, 'vehicle');
}
function vehicleMatchesCell(vehicle: VehicleController, cell: Vec3): boolean {
const vCell = vehicleLogicCell(vehicle);
return !!vCell && vCell.x === cell.x && vCell.y === cell.y;
}
/** 玩家与载具占同一逻辑格时绑定(不依赖 Ride 格是否已注册) */
export function tryLinkPlayerVehicle(player: PlayerController): boolean {
const gm = GameManager.instance;
const level = gm?.curLevel;
if (!level) return false;
const pCell = playerLogicCell(player);
if (!pCell) return false;
const existing = player.getRideVehicle();
if (existing) {
const vCell = vehicleLogicCell(existing);
if (!vCell || vCell.x !== pCell.x || vCell.y !== pCell.y) {
existing.setPlayer(null);
player.setRideVehicle(null);
return false;
}
linkRidePair(player, existing, pCell);
return true;
}
let linked = false;
forEachLevelEntityNode(level, (ch) => {
if (linked || !ch.name.includes('Vehicle')) return;
const vc = ch.getComponent(VehicleController);
if (!vc || !vehicleMatchesCell(vc, pCell)) return;
linkRidePair(player, vc, pCell);
linked = true;
});
if (linked) return true;
const rideVc = findVehicleAtCell(pCell);
if (rideVc) {
linkRidePair(player, rideVc, pCell);
return true;
}
return false;
}
/** 载具侧:同格玩家自动设为骑手 */
export function tryLinkVehicleRider(vehicle: VehicleController): boolean {
const gm = GameManager.instance;
const level = gm?.curLevel;
if (!level) return false;
const vCell = vehicleLogicCell(vehicle);
if (!vCell) return false;
const rider = vehicle.getPlayer();
if (rider) {
const pCell = playerLogicCell(rider);
if (pCell && pCell.x === vCell.x && pCell.y === vCell.y) {
linkRidePair(rider, vehicle, vCell);
return true;
}
}
let matched = false;
forEachLevelEntityNode(level, (ch) => {
if (matched || !ch.name.includes('Player')) return;
const pc = ch.getComponent(PlayerController);
if (!pc) return;
const pCell = playerLogicCell(pc);
if (!pCell || pCell.x !== vCell.x || pCell.y !== vCell.y) return;
linkRidePair(pc, vehicle, vCell);
matched = true;
});
return matched;
}
/** 移动中强制位置联动Unity OnMoving 语义) */
export function syncRidePositions(driver: 'player' | 'vehicle', player: PlayerController, vehicle: VehicleController) {
if (driver === 'player') {
const p = player.node.position;
vehicle.node.setPosition(p.x, p.y, p.z);
} else {
player.setRideBaseFromVehicle(vehicle.node.position);
}
}
export function resolveRideBind(player: PlayerController, cell: Vec3 | null): VehicleController | null {
if (!cell) return null;
return findVehicleAtCell(cell);
}