208 lines
6.2 KiB
TypeScript
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;
|
|
}
|
|
}
|