cocos基础工程
This commit is contained in:
@@ -0,0 +1,385 @@
|
||||
/**
|
||||
* 输入管理器实现
|
||||
* 处理鼠标和触摸输入,转换为游戏事件
|
||||
*/
|
||||
|
||||
import { Camera, Component, EventMouse, EventTouch, Vec2, Vec3, _decorator } from 'cc';
|
||||
import { EventBus } from '../Core/EventBus';
|
||||
import { Vector2 } from '../Core/GameData';
|
||||
import {
|
||||
BaseInputEvent,
|
||||
InputButton,
|
||||
InputCallback,
|
||||
InputConfig,
|
||||
InputEventType,
|
||||
InputState,
|
||||
MouseInputEvent,
|
||||
TouchInputEvent
|
||||
} from './InputTypes';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass
|
||||
export class InputManager extends Component {
|
||||
|
||||
@property({ tooltip: '启用鼠标输入' })
|
||||
enableMouse: boolean = true;
|
||||
|
||||
@property({ tooltip: '启用触摸输入' })
|
||||
enableTouch: boolean = true;
|
||||
|
||||
@property({ tooltip: '双击时间间隔(ms)' })
|
||||
doubleClickTime: number = 300;
|
||||
|
||||
@property({ tooltip: '长按时间(ms)' })
|
||||
longPressTime: number = 500;
|
||||
|
||||
@property({ tooltip: '拖拽阈值(像素)' })
|
||||
dragThreshold: number = 10;
|
||||
|
||||
private eventBus: EventBus;
|
||||
private camera: Camera | null = null;
|
||||
private inputState: InputState;
|
||||
private config: InputConfig;
|
||||
private callbacks: Map<InputEventType, InputCallback[]> = new Map();
|
||||
|
||||
/**
|
||||
* 组件初始化
|
||||
*/
|
||||
onLoad(): void {
|
||||
this.eventBus = EventBus.getInstance();
|
||||
this.initializeInputState();
|
||||
this.initializeConfig();
|
||||
this.setupInputEvents();
|
||||
|
||||
console.log('InputManager initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化输入状态
|
||||
*/
|
||||
private initializeInputState(): void {
|
||||
this.inputState = {
|
||||
isMouseDown: false,
|
||||
isTouchActive: false,
|
||||
lastClickTime: 0,
|
||||
lastClickPosition: { x: 0, y: 0 },
|
||||
isDragging: false,
|
||||
dragStartPosition: { x: 0, y: 0 },
|
||||
activeTouches: new Map()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化配置
|
||||
*/
|
||||
private initializeConfig(): void {
|
||||
this.config = {
|
||||
enableMouse: this.enableMouse,
|
||||
enableTouch: this.enableTouch,
|
||||
doubleClickTime: this.doubleClickTime,
|
||||
longPressTime: this.longPressTime,
|
||||
dragThreshold: this.dragThreshold
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置相机引用
|
||||
*/
|
||||
setCamera(camera: Camera): void {
|
||||
this.camera = camera;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置事件回调
|
||||
*/
|
||||
on<T extends BaseInputEvent>(eventType: InputEventType, callback: InputCallback<T>): void {
|
||||
if (!this.callbacks.has(eventType)) {
|
||||
this.callbacks.set(eventType, []);
|
||||
}
|
||||
this.callbacks.get(eventType)!.push(callback as InputCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除事件回调
|
||||
*/
|
||||
off<T extends BaseInputEvent>(eventType: InputEventType, callback: InputCallback<T>): void {
|
||||
const callbacks = this.callbacks.get(eventType);
|
||||
if (callbacks) {
|
||||
const index = callbacks.indexOf(callback as InputCallback);
|
||||
if (index > -1) {
|
||||
callbacks.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置输入事件监听
|
||||
*/
|
||||
private setupInputEvents(): void {
|
||||
if (this.config.enableMouse) {
|
||||
this.node.on('mousedown', this.onMouseDown, this);
|
||||
this.node.on('mouseup', this.onMouseUp, this);
|
||||
this.node.on('mousemove', this.onMouseMove, this);
|
||||
}
|
||||
|
||||
if (this.config.enableTouch) {
|
||||
this.node.on('touchstart', this.onTouchStart, this);
|
||||
this.node.on('touchend', this.onTouchEnd, this);
|
||||
this.node.on('touchmove', this.onTouchMove, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标按下事件
|
||||
*/
|
||||
private onMouseDown(event: EventMouse): void {
|
||||
const position = this.screenToWorldPosition(event.getUILocation());
|
||||
const inputEvent: MouseInputEvent = {
|
||||
type: InputEventType.MOUSE_DOWN,
|
||||
position,
|
||||
screenPosition: { x: event.getUILocation().x, y: event.getUILocation().y },
|
||||
timestamp: Date.now(),
|
||||
button: event.getButton() as InputButton,
|
||||
ctrlKey: false, // Cocos Creator 3.x 中需要通过其他方式获取
|
||||
shiftKey: false,
|
||||
altKey: false
|
||||
};
|
||||
|
||||
this.inputState.isMouseDown = true;
|
||||
this.inputState.dragStartPosition = position;
|
||||
|
||||
// 检测双击
|
||||
const timeSinceLastClick = inputEvent.timestamp - this.inputState.lastClickTime;
|
||||
if (timeSinceLastClick < this.config.doubleClickTime) {
|
||||
const distance = this.calculateDistance(position, this.inputState.lastClickPosition);
|
||||
if (distance < this.config.dragThreshold) {
|
||||
this.emitDoubleClickEvent(inputEvent);
|
||||
}
|
||||
}
|
||||
|
||||
this.inputState.lastClickTime = inputEvent.timestamp;
|
||||
this.inputState.lastClickPosition = position;
|
||||
|
||||
this.emitEvent(inputEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标释放事件
|
||||
*/
|
||||
private onMouseUp(event: EventMouse): void {
|
||||
const position = this.screenToWorldPosition(event.getUILocation());
|
||||
const inputEvent: MouseInputEvent = {
|
||||
type: InputEventType.MOUSE_UP,
|
||||
position,
|
||||
screenPosition: { x: event.getUILocation().x, y: event.getUILocation().y },
|
||||
timestamp: Date.now(),
|
||||
button: event.getButton() as InputButton,
|
||||
ctrlKey: false,
|
||||
shiftKey: false,
|
||||
altKey: false
|
||||
};
|
||||
|
||||
this.inputState.isMouseDown = false;
|
||||
this.inputState.isDragging = false;
|
||||
|
||||
this.emitEvent(inputEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标移动事件
|
||||
*/
|
||||
private onMouseMove(event: EventMouse): void {
|
||||
const position = this.screenToWorldPosition(event.getUILocation());
|
||||
const inputEvent: MouseInputEvent = {
|
||||
type: InputEventType.MOUSE_MOVE,
|
||||
position,
|
||||
screenPosition: { x: event.getUILocation().x, y: event.getUILocation().y },
|
||||
timestamp: Date.now(),
|
||||
button: event.getButton() as InputButton,
|
||||
ctrlKey: false,
|
||||
shiftKey: false,
|
||||
altKey: false
|
||||
};
|
||||
|
||||
// 检测拖拽开始
|
||||
if (this.inputState.isMouseDown && !this.inputState.isDragging) {
|
||||
const distance = this.calculateDistance(position, this.inputState.dragStartPosition);
|
||||
if (distance > this.config.dragThreshold) {
|
||||
this.inputState.isDragging = true;
|
||||
this.emitDragStartEvent(inputEvent);
|
||||
}
|
||||
}
|
||||
|
||||
this.emitEvent(inputEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 触摸开始事件
|
||||
*/
|
||||
private onTouchStart(event: EventTouch): void {
|
||||
const touches = event.getAllTouches();
|
||||
|
||||
for (const touch of touches) {
|
||||
const position = this.screenToWorldPosition(touch.getUILocation());
|
||||
const touchEvent: TouchInputEvent = {
|
||||
type: InputEventType.TOUCH_START,
|
||||
position,
|
||||
screenPosition: { x: touch.getUILocation().x, y: touch.getUILocation().y },
|
||||
timestamp: Date.now(),
|
||||
touchId: touch.getID(),
|
||||
force: undefined // Cocos Creator 3.x 中 getForce 方法可能不可用
|
||||
};
|
||||
|
||||
this.inputState.activeTouches.set(touch.getID(), touchEvent);
|
||||
this.inputState.isTouchActive = true;
|
||||
|
||||
this.emitEvent(touchEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触摸结束事件
|
||||
*/
|
||||
private onTouchEnd(event: EventTouch): void {
|
||||
const touches = event.getAllTouches();
|
||||
|
||||
for (const touch of touches) {
|
||||
const position = this.screenToWorldPosition(touch.getUILocation());
|
||||
const touchEvent: TouchInputEvent = {
|
||||
type: InputEventType.TOUCH_END,
|
||||
position,
|
||||
screenPosition: { x: touch.getUILocation().x, y: touch.getUILocation().y },
|
||||
timestamp: Date.now(),
|
||||
touchId: touch.getID(),
|
||||
force: undefined // Cocos Creator 3.x 中 getForce 方法可能不可用
|
||||
};
|
||||
|
||||
this.inputState.activeTouches.delete(touch.getID());
|
||||
if (this.inputState.activeTouches.size === 0) {
|
||||
this.inputState.isTouchActive = false;
|
||||
}
|
||||
|
||||
this.emitEvent(touchEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触摸移动事件
|
||||
*/
|
||||
private onTouchMove(event: EventTouch): void {
|
||||
const touches = event.getAllTouches();
|
||||
|
||||
for (const touch of touches) {
|
||||
const position = this.screenToWorldPosition(touch.getUILocation());
|
||||
const touchEvent: TouchInputEvent = {
|
||||
type: InputEventType.TOUCH_MOVE,
|
||||
position,
|
||||
screenPosition: { x: touch.getUILocation().x, y: touch.getUILocation().y },
|
||||
timestamp: Date.now(),
|
||||
touchId: touch.getID(),
|
||||
force: undefined // Cocos Creator 3.x 中 getForce 方法可能不可用
|
||||
};
|
||||
|
||||
this.emitEvent(touchEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 屏幕坐标转世界坐标
|
||||
*/
|
||||
private screenToWorldPosition(screenPos: Vec2): Vector2 {
|
||||
if (!this.camera) {
|
||||
// 如果没有相机,使用简单的坐标转换
|
||||
return {
|
||||
x: (screenPos.x - 400) / 100, // 假设屏幕中心为 (400, 300),缩放 100倍
|
||||
y: (300 - screenPos.y) / 100
|
||||
};
|
||||
}
|
||||
|
||||
// 使用相机进行坐标转换 - 转换为 Vec3
|
||||
const screenPos3 = new Vec3(screenPos.x, screenPos.y, 0);
|
||||
const worldPos = this.camera.screenToWorld(screenPos3);
|
||||
return {
|
||||
x: worldPos.x / 100, // 转换为物理世界坐标
|
||||
y: worldPos.y / 100
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两点距离
|
||||
*/
|
||||
private calculateDistance(pos1: Vector2, pos2: Vector2): number {
|
||||
const dx = pos1.x - pos2.x;
|
||||
const dy = pos1.y - pos2.y;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发射事件
|
||||
*/
|
||||
private emitEvent(event: BaseInputEvent): void {
|
||||
const callbacks = this.callbacks.get(event.type);
|
||||
if (callbacks) {
|
||||
callbacks.forEach(callback => {
|
||||
try {
|
||||
callback(event);
|
||||
} catch (error) {
|
||||
console.error(`Error in input callback for ${event.type}:`, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 同时通过事件总线发射
|
||||
this.eventBus.emit(event.type, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发射双击事件
|
||||
*/
|
||||
private emitDoubleClickEvent(event: MouseInputEvent): void {
|
||||
this.eventBus.emit('double_click', event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发射拖拽开始事件
|
||||
*/
|
||||
private emitDragStartEvent(event: MouseInputEvent): void {
|
||||
this.eventBus.emit('drag_start', event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前输入状态
|
||||
*/
|
||||
getInputState(): InputState {
|
||||
return { ...this.inputState };
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取事件总线
|
||||
*/
|
||||
getEventBus(): EventBus {
|
||||
return this.eventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理资源
|
||||
*/
|
||||
onDestroy(): void {
|
||||
// 移除事件监听
|
||||
this.node.off('mousedown', this.onMouseDown, this);
|
||||
this.node.off('mouseup', this.onMouseUp, this);
|
||||
this.node.off('mousemove', this.onMouseMove, this);
|
||||
this.node.off('touchstart', this.onTouchStart, this);
|
||||
this.node.off('touchend', this.onTouchEnd, this);
|
||||
this.node.off('touchmove', this.onTouchMove, this);
|
||||
|
||||
// 清理回调
|
||||
this.callbacks.clear();
|
||||
|
||||
// 清理事件总线
|
||||
this.eventBus.clear();
|
||||
|
||||
console.log('InputManager destroyed');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user