Files
rougelike-demo/client/assets/scripts/App/Game/PlayerController.ts
2025-12-14 23:35:08 +08:00

208 lines
6.2 KiB
TypeScript

import { _decorator, Component, Node, EventKeyboard, KeyCode, Input, input, Vec3 } from 'cc';
import { NetManager } from '../../Framework/Net/NetManager';
import { ReqMove, ResMove } from '../../Shared/protocols/PtlMove';
import { PlayerInfo } from '../../Shared/protocols/PtlLogin';
import { RoleController } from '../../CC/RoleController';
const { ccclass } = _decorator;
/**
* PlayerController 本地玩家控制器
* 负责处理本地玩家的输入、移动和动画
*/
@ccclass('PlayerController')
export class PlayerController extends Component {
/** 玩家信息 */
private playerInfo: PlayerInfo = null;
/** 角色控制器(控制动画) */
private roleController: RoleController = null;
/** 移动速度 */
private moveSpeed: number = 5;
/** 当前移动方向 */
private moveDirection: Vec3 = new Vec3(0, 0, 0);
/** 按键状态 */
private keyStates: Map<KeyCode, boolean> = new Map();
/** 是否正在移动 */
private isMoving: boolean = false;
/** 上次发送移动请求的位置 */
private lastSentPosition: Vec3 = new Vec3();
/** 移动阈值(超过这个距离才发送移动请求) */
private moveSendThreshold: number = 0.5;
/**
* 初始化玩家控制器
*/
public init(playerInfo: PlayerInfo): void {
this.playerInfo = playerInfo;
this.lastSentPosition.set(playerInfo.position.x, 0, playerInfo.position.y);
// 获取 RoleController 组件
this.roleController = this.node.getComponentInChildren(RoleController);
if (!this.roleController) {
console.warn('[PlayerController] 未找到 RoleController 组件');
} else {
// 初始播放待机动画
this.roleController.PlayAnimation('idle', true);
}
console.log('[PlayerController] 初始化完成:', playerInfo.name);
}
protected onEnable(): void {
// 注册键盘事件
input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
input.on(Input.EventType.KEY_UP, this.onKeyUp, this);
}
protected onDisable(): void {
// 取消注册键盘事件
input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
input.off(Input.EventType.KEY_UP, this.onKeyUp, this);
}
/**
* 键盘按下事件
*/
private onKeyDown(event: EventKeyboard): void {
this.keyStates.set(event.keyCode, true);
}
/**
* 键盘抬起事件
*/
private onKeyUp(event: EventKeyboard): void {
this.keyStates.set(event.keyCode, false);
}
protected update(dt: number): void {
// 计算移动方向
this.updateMoveDirection();
// 如果有移动方向,移动角色
if (this.moveDirection.lengthSqr() > 0) {
this.move(dt);
} else {
// 没有移动,播放待机动画
if (this.isMoving) {
this.isMoving = false;
if (this.roleController) {
this.roleController.PlayAnimation('idle', true);
}
}
}
}
/**
* 更新移动方向
*/
private updateMoveDirection(): void {
this.moveDirection.set(0, 0, 0);
// W - 向前
if (this.keyStates.get(KeyCode.KEY_W)) {
this.moveDirection.z -= 1;
}
// S - 向后
if (this.keyStates.get(KeyCode.KEY_S)) {
this.moveDirection.z += 1;
}
// A - 向左
if (this.keyStates.get(KeyCode.KEY_A)) {
this.moveDirection.x -= 1;
}
// D - 向右
if (this.keyStates.get(KeyCode.KEY_D)) {
this.moveDirection.x += 1;
}
// 归一化移动方向
if (this.moveDirection.lengthSqr() > 0) {
this.moveDirection.normalize();
}
}
/**
* 移动角色
*/
private move(dt: number): void {
// 计算移动增量
const moveOffset = this.moveDirection.clone().multiplyScalar(this.moveSpeed * dt);
// 更新节点位置
const currentPos = this.node.position.clone();
currentPos.add(moveOffset);
this.node.setPosition(currentPos);
// 更新朝向(让角色面向移动方向)
if (this.moveDirection.lengthSqr() > 0) {
const targetAngle = Math.atan2(this.moveDirection.x, -this.moveDirection.z) * (180 / Math.PI);
this.node.setRotationFromEuler(0, targetAngle, 0);
}
// 播放移动动画
if (!this.isMoving) {
this.isMoving = true;
if (this.roleController) {
this.roleController.PlayAnimation('move', true);
}
}
// 检查是否需要发送移动请求
this.checkSendMoveRequest(currentPos);
}
/**
* 检查是否需要发送移动请求
*/
private checkSendMoveRequest(currentPos: Vec3): void {
const distance = Vec3.distance(currentPos, this.lastSentPosition);
// 如果移动距离超过阈值,发送移动请求
if (distance >= this.moveSendThreshold) {
this.sendMoveRequest(currentPos.x, currentPos.z);
this.lastSentPosition.set(currentPos);
}
}
/**
* 发送移动请求到服务器
*/
private async sendMoveRequest(x: number, z: number): Promise<void> {
try {
const netManager = NetManager.getInstance();
const result = await netManager.callApi<ReqMove, ResMove>('Move', {
x: x,
y: z
});
if (!result) {
console.error('[PlayerController] 移动请求失败');
return;
}
// 服务器可能会修正位置,使用服务器返回的位置
if (result.position) {
const serverPos = result.position;
this.node.setPosition(serverPos.x, 0, serverPos.y);
this.lastSentPosition.set(serverPos.x, 0, serverPos.y);
}
} catch (error) {
console.error('[PlayerController] 发送移动请求异常:', error);
}
}
/**
* 获取玩家信息
*/
public getPlayerInfo(): PlayerInfo {
return this.playerInfo;
}
}