Skip to content

Commit

Permalink
fix: forEach issue on set
Browse files Browse the repository at this point in the history
  • Loading branch information
doubleactii committed Dec 16, 2024
1 parent e63e0ad commit 6df6a54
Show file tree
Hide file tree
Showing 6 changed files with 1,857 additions and 2,057 deletions.
Binary file modified .DS_Store
Binary file not shown.
3,902 changes: 1,851 additions & 2,051 deletions docs/ast/source/gamepad.mjs.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/file/src/gamepad.mjs.html
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@
switch (pEvent) {
case 'connect':
this.connectHandler[pEvent] = pCallback;
this.unassignedControllers.values().forEach(pController => this.connectHandler[pEvent](pController));
this.unassignedControllers.forEach(pController => this.connectHandler[pEvent](pController));
this.unassignedControllers.clear();
break;

Expand Down
2 changes: 1 addition & 1 deletion docs/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -1587,7 +1587,7 @@
"__docId__": 98,
"kind": "file",
"name": "src/gamepad.mjs",
"content": "\nimport { Controller } from './controller.mjs';\nimport { Logger } from './vendor/logger.min.mjs';\n\n/**\n * A gamepadmanager to help with games / handling input from a controller\n * @class GamepadManagerSingleton\n * @license GamepadManager does not have a license at this time. For licensing contact the author\n * @author https://github.com/doubleactii\n * @todo Currently bluetooth gamepads when disconnecting (PS4 only) do no fire a disconnected event. Manually calling `this.gamepad.vibrationActuator.reset()` can force it to call a disconnect event, but \n * this is a messy way of checking each tick to see if the gamepad is still connected. It also will cancel ongoing vibrations. Find a fix. (This is a GamepadAPI issue/OS issue/not code wise issue)\n */\nclass GamepadManagerSingleton {\n\t/**\n\t * Object containing all connected controllers\n\t * \n\t * @type {Object}\n\t */\n\tcontrollers = {};\n\t/**\n\t * Object containing the callback for when a controller is connected\n\t * \n\t * @type {Object}\n\t */\n\tconnectHandler = {};\n\t/**\n\t * Controllers connected before an event listener caught them.\n\t * @type {Set<Controller> | null}\n\t */\n\tconnectedControllers = null;\n\t/**\n\t * Controllers connected before an event listener caught them.\n\t * @type {Set<Controller> | null}\n\t */\n\tunassignedControllers = null;\n\t/**\n\t * Object containing the callback for when a controller is disconnected\n\t * \n\t * @type {Object}\n\t */\n\tdisconnectHandler = {};\n\t/**\n\t * The version of the module.\n\t */\n\tversion = \"VERSION_REPLACE_ME\";\n\t/**\n\t * Creates the instance and assigns event handlers to gamepad events\n\t */\n\tconstructor() {\n\n /** The logger module this module uses to log errors / logs.\n * @private\n * @type {Object}\n */\n this.logger = new Logger();\n this.logger.registerType('Gamepad-Module', '#ff6600');\n\n\t\tthis.connectedControllers = new Set();\n\t\tthis.unassignedControllers = new Set();\n\n\t\t// Bind this class instance to the event handlers\n\t\tthis.handleGamepadConnected = this.handleGamepadConnected.bind(this);\n\t\tthis.handleGamepadDisconnected = this.handleGamepadDisconnected.bind(this);\n\t\tthis.pollGamepadState = this.pollGamepadState.bind(this);\n\n\t\t// Check for gamepad support\n\t\tif ('getGamepads' in navigator) {\n\t\t\twindow.addEventListener('gamepadconnected', this.handleGamepadConnected);\n\t\t\twindow.addEventListener('gamepaddisconnected', this.handleGamepadDisconnected);\n\t\t\trequestAnimationFrame(this.pollGamepadState);\n\t\t} else {\n\t\t\tthis.logger.prefix('Gamepad-Module').warn('Gamepad API not supported in this browser.');\n\t\t}\n\t}\n\t/**\n\t * Gets the angle between two points\n\t * \n\t * @param {Object} pStartPoint - The starting point\n\t * @param {Object} pEndPoint - The ending point\n\t * @returns {number} The angle between the starting point and the ending point\n\t */\n\tstatic getAngle(pStartPoint, pEndPoint) {\n\t\tconst y = pStartPoint.y - pEndPoint.y;\n\t\tconst x = pStartPoint.x - pEndPoint.x;\n\t\treturn -Math.atan2(y, x) - Math.PI;\n\t}\n\t/**\n\t * This gets the first controller connected. This controller is dominant\n\t * \n\t * @returns {Gamepad} The first controller connected\n\t */\n\tgetMainController() {\n\t\treturn this.controllers['0'];\n\t}\n\t/**\n\t * @returns {Array} An array of all connected controllers\n\t */\n\tgetControllers() {\n\t\treturn { ...this.controllers };\n\t}\n /**\n * Attaches a callback to the specified event.\n\t * \n * @param {Object} pEvent - The event to attach the callback to\n * @param {Function} pCallback - The function to be called when the event is triggered\n * @return {GamepadManagerSingleton} The GamepadManagerSingleton instance\n */\n\ton(pEvent, pCallback) {\n\t\tif (typeof(pEvent) === 'string') {\n\t\t\tif (typeof(pCallback) === 'function') {\n\t\t\t\tswitch (pEvent) {\n\t\t\t\t\tcase 'connect':\n\t\t\t\t\t\tthis.connectHandler[pEvent] = pCallback;\n\t\t\t\t\t\tthis.unassignedControllers.values().forEach(pController => this.connectHandler[pEvent](pController));\n\t\t\t\t\t\tthis.unassignedControllers.clear();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'disconnect':\n\t\t\t\t\t\tthis.disconnectHandler[pEvent] = pCallback;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthis.logger.prefix('Gamepad-Module').error(`The event \"${pEvent}\" is not supported.`);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.logger.prefix('Gamepad-Module').error(`The callback for event \"${pEvent}\" is not a function.`);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\t/**\n\t * Listener function for when a gamepad is connected\n\t * \n\t * @param {pGamepadEvent} pGamepadEvent - A gamepad event\n\t */\n\thandleGamepadConnected(pGamepadEvent) {\n\t\t// Create a controller from the gamepad that was connected\n\t\t// This controller only saves a snapshot of the data of when it was first created, but we update it based on new polled data\n\t\tconst controller = new Controller(pGamepadEvent.gamepad);\n\n\t\tthis.controllers[controller.index] = controller;\n\t\tthis.connectedControllers.add(controller);\n\t\t\n\t\tif (typeof(this.connectHandler.connect) === 'function') {\n\t\t\tthis.connectHandler.connect(controller);\n\t\t} else {\n\t\t\tthis.unassignedControllers.add(controller);\n\t\t}\n\t}\n\t/**\n\t * Listener function for when the gamepad is disconnected\n\t * \n\t * @param {pGamepadEvent} pGamepadEvent - A gamepad event\n\t */\n\thandleGamepadDisconnected(pGamepadEvent) {\n\t\t// Delete the controller when it's disconnected\n\t\t// Maybe add a option to save gamepad info for a short while, incase it disconnected due to battery? \n\t\t// When reconnected it can prompt an alert that says \"restore configuration for gamepad\". This will restore that configuration to the controller.\n\t\tconst index = pGamepadEvent.gamepad.index;\n\t\tconst controller = this.controllers[index];\n\n\t\tif (typeof(this.disconnectHandler.disconnect) === 'function') this.disconnectHandler.disconnect(controller);\n\n\t\tthis.connectedControllers.delete(controller);\n\t\tdelete this.controllers[index];\n\t}\n\t/**\n\t * Get the latest game state of the connected gamepads (Chrome only saves snapshots of the state, we have to keep polling to get updated states)\n\t */\n\tpollGamepadState() {\n\t\tconst gamepads = navigator.getGamepads();\n\t\tif (!gamepads) return;\n\t\t// Loop through all connected controllers and update their state\n\t\tfor (const gamepad of gamepads) {\n\t\t\t// Can be null if disconnected during the session\n\t\t\tif (gamepad) {\n\t\t\t\tfor (const controller in this.controllers) {\n\t\t\t\t\t// Make sure we are updating the correct controller with the right data from the gamepad at the same index\n\t\t\t\t\tif (gamepad.index === this.controllers[controller].gamepad.index) {\n\t\t\t\t\t\tthis.controllers[controller].updateState(gamepad);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trequestAnimationFrame(this.pollGamepadState);\n\t}\n}\n\n\nexport const GamepadManager = new GamepadManagerSingleton();\n",
"content": "\nimport { Controller } from './controller.mjs';\nimport { Logger } from './vendor/logger.min.mjs';\n\n/**\n * A gamepadmanager to help with games / handling input from a controller\n * @class GamepadManagerSingleton\n * @license GamepadManager does not have a license at this time. For licensing contact the author\n * @author https://github.com/doubleactii\n * @todo Currently bluetooth gamepads when disconnecting (PS4 only) do no fire a disconnected event. Manually calling `this.gamepad.vibrationActuator.reset()` can force it to call a disconnect event, but \n * this is a messy way of checking each tick to see if the gamepad is still connected. It also will cancel ongoing vibrations. Find a fix. (This is a GamepadAPI issue/OS issue/not code wise issue)\n */\nclass GamepadManagerSingleton {\n\t/**\n\t * Object containing all connected controllers\n\t * \n\t * @type {Object}\n\t */\n\tcontrollers = {};\n\t/**\n\t * Object containing the callback for when a controller is connected\n\t * \n\t * @type {Object}\n\t */\n\tconnectHandler = {};\n\t/**\n\t * Controllers connected before an event listener caught them.\n\t * @type {Set<Controller> | null}\n\t */\n\tconnectedControllers = null;\n\t/**\n\t * Controllers connected before an event listener caught them.\n\t * @type {Set<Controller> | null}\n\t */\n\tunassignedControllers = null;\n\t/**\n\t * Object containing the callback for when a controller is disconnected\n\t * \n\t * @type {Object}\n\t */\n\tdisconnectHandler = {};\n\t/**\n\t * The version of the module.\n\t */\n\tversion = \"VERSION_REPLACE_ME\";\n\t/**\n\t * Creates the instance and assigns event handlers to gamepad events\n\t */\n\tconstructor() {\n\n /** The logger module this module uses to log errors / logs.\n * @private\n * @type {Object}\n */\n this.logger = new Logger();\n this.logger.registerType('Gamepad-Module', '#ff6600');\n\n\t\tthis.connectedControllers = new Set();\n\t\tthis.unassignedControllers = new Set();\n\n\t\t// Bind this class instance to the event handlers\n\t\tthis.handleGamepadConnected = this.handleGamepadConnected.bind(this);\n\t\tthis.handleGamepadDisconnected = this.handleGamepadDisconnected.bind(this);\n\t\tthis.pollGamepadState = this.pollGamepadState.bind(this);\n\n\t\t// Check for gamepad support\n\t\tif ('getGamepads' in navigator) {\n\t\t\twindow.addEventListener('gamepadconnected', this.handleGamepadConnected);\n\t\t\twindow.addEventListener('gamepaddisconnected', this.handleGamepadDisconnected);\n\t\t\trequestAnimationFrame(this.pollGamepadState);\n\t\t} else {\n\t\t\tthis.logger.prefix('Gamepad-Module').warn('Gamepad API not supported in this browser.');\n\t\t}\n\t}\n\t/**\n\t * Gets the angle between two points\n\t * \n\t * @param {Object} pStartPoint - The starting point\n\t * @param {Object} pEndPoint - The ending point\n\t * @returns {number} The angle between the starting point and the ending point\n\t */\n\tstatic getAngle(pStartPoint, pEndPoint) {\n\t\tconst y = pStartPoint.y - pEndPoint.y;\n\t\tconst x = pStartPoint.x - pEndPoint.x;\n\t\treturn -Math.atan2(y, x) - Math.PI;\n\t}\n\t/**\n\t * This gets the first controller connected. This controller is dominant\n\t * \n\t * @returns {Gamepad} The first controller connected\n\t */\n\tgetMainController() {\n\t\treturn this.controllers['0'];\n\t}\n\t/**\n\t * @returns {Array} An array of all connected controllers\n\t */\n\tgetControllers() {\n\t\treturn { ...this.controllers };\n\t}\n /**\n * Attaches a callback to the specified event.\n\t * \n * @param {Object} pEvent - The event to attach the callback to\n * @param {Function} pCallback - The function to be called when the event is triggered\n * @return {GamepadManagerSingleton} The GamepadManagerSingleton instance\n */\n\ton(pEvent, pCallback) {\n\t\tif (typeof(pEvent) === 'string') {\n\t\t\tif (typeof(pCallback) === 'function') {\n\t\t\t\tswitch (pEvent) {\n\t\t\t\t\tcase 'connect':\n\t\t\t\t\t\tthis.connectHandler[pEvent] = pCallback;\n\t\t\t\t\t\tthis.unassignedControllers.forEach(pController => this.connectHandler[pEvent](pController));\n\t\t\t\t\t\tthis.unassignedControllers.clear();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'disconnect':\n\t\t\t\t\t\tthis.disconnectHandler[pEvent] = pCallback;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthis.logger.prefix('Gamepad-Module').error(`The event \"${pEvent}\" is not supported.`);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.logger.prefix('Gamepad-Module').error(`The callback for event \"${pEvent}\" is not a function.`);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\t/**\n\t * Listener function for when a gamepad is connected\n\t * \n\t * @param {pGamepadEvent} pGamepadEvent - A gamepad event\n\t */\n\thandleGamepadConnected(pGamepadEvent) {\n\t\t// Create a controller from the gamepad that was connected\n\t\t// This controller only saves a snapshot of the data of when it was first created, but we update it based on new polled data\n\t\tconst controller = new Controller(pGamepadEvent.gamepad);\n\n\t\tthis.controllers[controller.index] = controller;\n\t\tthis.connectedControllers.add(controller);\n\t\t\n\t\tif (typeof(this.connectHandler.connect) === 'function') {\n\t\t\tthis.connectHandler.connect(controller);\n\t\t} else {\n\t\t\tthis.unassignedControllers.add(controller);\n\t\t}\n\t}\n\t/**\n\t * Listener function for when the gamepad is disconnected\n\t * \n\t * @param {pGamepadEvent} pGamepadEvent - A gamepad event\n\t */\n\thandleGamepadDisconnected(pGamepadEvent) {\n\t\t// Delete the controller when it's disconnected\n\t\t// Maybe add a option to save gamepad info for a short while, incase it disconnected due to battery? \n\t\t// When reconnected it can prompt an alert that says \"restore configuration for gamepad\". This will restore that configuration to the controller.\n\t\tconst index = pGamepadEvent.gamepad.index;\n\t\tconst controller = this.controllers[index];\n\n\t\tif (typeof(this.disconnectHandler.disconnect) === 'function') this.disconnectHandler.disconnect(controller);\n\n\t\tthis.connectedControllers.delete(controller);\n\t\tdelete this.controllers[index];\n\t}\n\t/**\n\t * Get the latest game state of the connected gamepads (Chrome only saves snapshots of the state, we have to keep polling to get updated states)\n\t */\n\tpollGamepadState() {\n\t\tconst gamepads = navigator.getGamepads();\n\t\tif (!gamepads) return;\n\t\t// Loop through all connected controllers and update their state\n\t\tfor (const gamepad of gamepads) {\n\t\t\t// Can be null if disconnected during the session\n\t\t\tif (gamepad) {\n\t\t\t\tfor (const controller in this.controllers) {\n\t\t\t\t\t// Make sure we are updating the correct controller with the right data from the gamepad at the same index\n\t\t\t\t\tif (gamepad.index === this.controllers[controller].gamepad.index) {\n\t\t\t\t\t\tthis.controllers[controller].updateState(gamepad);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trequestAnimationFrame(this.pollGamepadState);\n\t}\n}\n\n\nexport const GamepadManager = new GamepadManagerSingleton();\n",
"static": true,
"longname": "/Users/doubleactii/Documents/Github/Gamepad/src/gamepad.mjs",
"access": "public",
Expand Down
6 changes: 3 additions & 3 deletions docs/source.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,16 @@
<td class="coverage"><span data-ice="coverage">-</span></td>
<td style="display: none;" data-ice="size">20417 byte</td>
<td style="display: none;" data-ice="lines">599</td>
<td style="display: none;" data-ice="updated">2024-12-05 19:46:07 (UTC)</td>
<td style="display: none;" data-ice="updated">2024-12-01 20:15:22 (UTC)</td>
</tr>
<tr data-ice="file">
<td data-ice="filePath"><span><a href="file/src/gamepad.mjs.html">src/gamepad.mjs</a></span></td>
<td data-ice="identifier" class="identifiers"><span><a href="variable/index.html#static-variable-GamepadManager">GamepadManager</a></span>
<span><a href="class/src/gamepad.mjs~GamepadManagerSingleton.html">GamepadManagerSingleton</a></span></td>
<td class="coverage"><span data-ice="coverage">-</span></td>
<td style="display: none;" data-ice="size">6604 byte</td>
<td style="display: none;" data-ice="size">6595 byte</td>
<td style="display: none;" data-ice="lines">190</td>
<td style="display: none;" data-ice="updated">2024-12-05 20:04:53 (UTC)</td>
<td style="display: none;" data-ice="updated">2024-12-02 16:01:38 (UTC)</td>
</tr>
</tbody>
</table>
Expand Down
2 changes: 1 addition & 1 deletion src/gamepad.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class GamepadManagerSingleton {
switch (pEvent) {
case 'connect':
this.connectHandler[pEvent] = pCallback;
this.unassignedControllers.values().forEach(pController => this.connectHandler[pEvent](pController));
this.unassignedControllers.forEach(pController => this.connectHandler[pEvent](pController));
this.unassignedControllers.clear();
break;

Expand Down

0 comments on commit 6df6a54

Please sign in to comment.