Files
cocos-engine/pal/input/touch-manager.ts
alpha e5040dc3ee [3.4.1] Fix bug multi touch (#9917)
* 🐛 fix multi touch can not disable

* Update pal/input/touch-manager.ts

Co-authored-by: PP <chinese1236@qq.com>

* Update pal/input/touch-manager.ts

Co-authored-by: PP <chinese1236@qq.com>

Co-authored-by: PP <chinese1236@qq.com>
2022-01-06 18:22:32 +08:00

137 lines
4.4 KiB
TypeScript

import { macro } from '../../cocos/core/platform/macro';
import { Touch } from '../../cocos/input/types';
import { Vec2 } from '../../cocos/core/math/vec2';
const tempVec2 = new Vec2();
class TouchManager {
/**
* A map from touch ID to touch object.
*/
private _touchMap: Map<number, Touch>;
private readonly _maxTouches = 8;
constructor () {
this._touchMap = new Map();
}
/**
* The original touch object can't be modified, so we need to return the cloned touch object.
* @param touch
* @returns
*/
private _cloneTouch (touch: Touch): Touch {
const touchID = touch.getID();
touch.getStartLocation(tempVec2);
const clonedTouch = new Touch(tempVec2.x, tempVec2.y, touchID);
touch.getLocation(tempVec2);
clonedTouch.setPoint(tempVec2.x, tempVec2.y);
touch.getPreviousLocation(tempVec2);
clonedTouch.setPrevPoint(tempVec2);
return clonedTouch;
}
/**
* Create the touch object at the touch start event callback.
* we have some policy to create the touch object:
* - If the number of touches doesn't exceed the max count, we create a touch object.
* - If the number of touches exceeds the max count, we discard the timeout touch to create a new one.
* - If the number of touches exceeds the max count and there is no timeout touch, we can't create any touch object.
* @param touchID
* @param x
* @param y
* @returns
*/
private _createTouch (touchID: number, x: number, y: number): Touch | undefined {
if (this._touchMap.has(touchID)) {
console.log('Cannot create the same touch object.');
return undefined;
}
const checkResult = this._checkTouchMapSizeMoreThanMax(touchID);
if (checkResult) {
console.log('The touches is more than MAX_TOUCHES.'); // TODO: logID 2300
return undefined;
}
const touch = new Touch(x, y, touchID);
this._touchMap.set(touchID, touch);
this._updateTouch(touch, x, y);
return this._cloneTouch(touch);
}
/**
* Release the touch object at the touch end or touch cancel event callback.
* @param touchID
* @returns
*/
public releaseTouch (touchID: number) {
if (!this._touchMap.has(touchID)) {
return;
}
this._touchMap.delete(touchID);
}
/**
* Get touch object by touch ID.
* @param touchID
* @returns
*/
public getTouch (touchID: number, x: number, y: number): Touch | undefined {
let touch = this._touchMap.get(touchID);
if (!touch) {
touch = this._createTouch(touchID, x, y);
} else {
this._updateTouch(touch, x, y);
}
return touch ? this._cloneTouch(touch) : undefined;
}
/**
* Get all the current touches objects.
* @returns
*/
public getAllTouches (): Touch[] {
const touches: Touch[] = [];
this._touchMap.forEach((touch) => {
if (touch) {
const clonedTouch = this._cloneTouch(touch);
touches.push(clonedTouch);
}
});
return touches;
}
/**
* Update the location and previous location of current touch ID.
* @param touchID
* @param x The current location X
* @param y The current location Y
*/
private _updateTouch (touch: Touch, x: number, y: number) {
touch.getLocation(tempVec2);
touch.setPrevPoint(tempVec2);
touch.setPoint(x, y);
}
private _checkTouchMapSizeMoreThanMax (touchID: number) {
if (this._touchMap.has(touchID)) {
return false;
}
const maxSize = macro.ENABLE_MULTI_TOUCH ? this._maxTouches : 1;
if (this._touchMap.size < maxSize) {
return false;
}
// Handle when exceed the max number of touches
const now = performance.now();
this._touchMap.forEach((touch) => {
if (now - touch.lastModified > macro.TOUCH_TIMEOUT) {
console.log(`The touches is more than MAX_TOUCHES, release touch id ${touch.getID()}.`);
// TODO: need to handle touch cancel event when exceed the max number of touches ?
this.releaseTouch(touch.getID());
}
});
return maxSize >= this._touchMap.size;
}
}
export const touchManager = new TouchManager();