游戏逻辑模块
This commit is contained in:
207
client/assets/scripts/App/Game/PlayerController.ts
Normal file
207
client/assets/scripts/App/Game/PlayerController.ts
Normal file
@@ -0,0 +1,207 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user