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>
This commit is contained in:
157
assets/scripts/controller/RideLink.ts
Normal file
157
assets/scripts/controller/RideLink.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user