evidently-input
Version:
TypeScript powered for easily handling input in your games.
166 lines • 7.48 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var MouseButtons;
(function (MouseButtons) {
MouseButtons[MouseButtons["Left"] = 0] = "Left";
MouseButtons[MouseButtons["Middle"] = 1] = "Middle";
MouseButtons[MouseButtons["Right"] = 2] = "Right";
})(MouseButtons = exports.MouseButtons || (exports.MouseButtons = {}));
/**
* Handles the mouse events and provdes an API for interacting with it easily. The simplest way to use it is:
*
* 1. Create a new instance of `MouseInput`.
* 2. Call `registerListeners()` passing the `document`.
* 3. Set `inputContainer` to the canvas element created by PIXI.
* 4. Call `update` **at the end** of every update frame of your game.
* 5. Use the functions of this library in your code.
*
* ### Different mouse positions
*
* * `screen` is the position of the mouse in the whole screen.
* * `page` is the position of the mouse inside the loaded webpage.
* * `local` is the position of the mouse relative to the `inputContainer` if defined, or to the element passed to `registerListeners`.
* * `scaled` is the position of the mouse inside the game, which is `local` modified by `scaleProperties`. It is mostly useful in games
* that scale up when their workspace is enlarged, as opposed to games that just reorganize their content and allow seeing more
* space inside.
*
* In order to get the proper values for `local` it is recommended to set `inputContainer` to the canvas element used to render the game.
*
* ### Scaled mouse position
*
* In order to get the proper values for `scaled` you need to keep the `scaleProperties` in sync with the modifications you do to the rendering of the game.
* For example, a typical game imitating 8-bit aesthetics would likely have its own internal resolution and then would scale that up, maybe pixel-perfect
* or maybe not. For example: a game in resolution `320x240` scaled up proportionally to resolution `1920x1080`:
*
* * It would scale `4.5` times, to `1440x1080.`
* * It would be horizontally centered, so offset in `X` by `240px` ( `(1920 - 1440) / 2` )
* * So the `scaleProperties` would be `{scaleX: 4.5, scaleY: 4.5, offsetX: 240, offsetY: 0}
*
* With these values scaledX/Y will return the proper position of the mouse in the stage.
*
* ### How does it work:
*
* See [[KeyboardInput]] for details.
*
* ### Understanding mouse button states
*
* Down, pressed and released for the mouse buttons work exactly the same as the keys in [[KeyboardInput]], please refer to its documentation.
*/
class MouseInput {
constructor() {
this.isMouseDown = (button) => this._mouseButtonsDown.indexOf(button) !== -1 || this.isMousePressed(button);
this.isMousePressed = (button) => this._mouseButtonsPressed.indexOf(button) !== -1;
this.isMouseReleased = (button) => this._mouseButtonsReleased.indexOf(button) !== -1;
/**
* Updates the internal state, should be called at the end of each frame.
*/
this.update = () => {
this._mouseButtonsReleased.length = 0;
this._mouseButtonsPressed.length = 0;
};
/**
* Resets the internal state of this class to what it is during creation - nothing pressed, released or held down, positions reset.
* This won't affect `scaleProperties` and `inputContainer`.
*/
this.flush = () => {
this._mouseButtonsDown.length = 0;
this._mouseButtonsPressed.length = 0;
this._mouseButtonsReleased.length = 0;
this._pageX = 0;
this._pageY = 0;
this._localX = 0;
this._localY = 0;
this._screenX = 0;
this._screenY = 0;
};
/**
* Handles a mouse event updating the internal status. This will be called automatically if you register the listeners
* via `registerListeners`. If you have listeners being registered somewhere else entirely and would like to keep it
* that way, you can manually call this method passing the MouseEvent/PointerEvent.
*
* @param {MouseEvent | PointerEvent} event
*/
this.handleEvent = (event) => {
var _a, _b;
this._pageX = (_a = event.pageX, (_a !== null && _a !== void 0 ? _a : event.clientX));
this._pageY = (_b = event.pageY, (_b !== null && _b !== void 0 ? _b : event.clientY));
this._screenX = event.screenX;
this._screenY = event.screenY;
this._localX = this.inputContainer ? event.pageX - this.inputContainer.offsetLeft : event.clientX;
this._localY = this.inputContainer ? event.pageY - this.inputContainer.offsetTop : event.clientY;
if (event.type === 'mouseup' || event.type === 'pointerup') {
this._mouseButtonsDown = this._mouseButtonsDown.filter(button => button !== event.button);
this._mouseButtonsReleased.push(event.button);
}
else if (event.type === 'mousedown' || event.type === 'pointerup') {
this._mouseButtonsDown.push(event.button);
this._mouseButtonsPressed.push(event.button);
}
};
this.handleContextMenuEvent = (event) => {
event.preventDefault();
return false;
};
this._pageX = 0;
this._pageY = 0;
this._localX = 0;
this._localY = 0;
this._mouseButtonsDown = [];
this._mouseButtonsReleased = [];
this._mouseButtonsPressed = [];
this.scaleProperties = {
scaleX: 1,
scaleY: 1,
offsetX: 0,
offsetY: 0,
};
}
get pageX() {
return this._pageX;
}
get pageY() {
return this._pageY;
}
get localX() {
return this._localX;
}
get localY() {
return this._localY;
}
get screenX() {
return this._screenX;
}
get screenY() {
return this._screenY;
}
get scaledX() {
return this.localX / this.scaleProperties.scaleX - this.scaleProperties.offsetX;
}
get scaledY() {
return this.localY / this.scaleProperties.scaleY - this.scaleProperties.offsetY;
}
get isAnyMouseDown() {
return this.isAnyMousePressed || this._mouseButtonsDown.length > 0;
}
get isAnyMousePressed() {
return this._mouseButtonsPressed.length > 0;
}
get isAnyMouseReleased() {
return this._mouseButtonsReleased.length > 0;
}
/**
* Registers the `mousemove`, `mosedown` and `mouseup` listeners on the passed element so that the class
* can handle the input.
* This also registers an event that blocks right mouse button context menu from appearing.
*
* @param {GlobalEventHandlers} element To avoid issues with focus it's best to pass `document` here
*/
registerListeners(element) {
element.addEventListener("mousedown", this.handleEvent);
element.addEventListener("mouseup", this.handleEvent);
element.addEventListener("mousemove", this.handleEvent);
element.addEventListener('contextmenu', this.handleContextMenuEvent);
}
}
exports.MouseInput = MouseInput;
//# sourceMappingURL=MouseInput.js.map