2022-06-15 15:35:22 +03:00
|
|
|
/* -------------- */
|
|
|
|
/* GAMEPAD MASTER */
|
|
|
|
/* -------------- */
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
2022-06-18 23:11:09 +03:00
|
|
|
class Library {
|
|
|
|
constructor() {
|
|
|
|
if (typeof Library.instance === 'object') {
|
|
|
|
return Library.instance;
|
|
|
|
};
|
|
|
|
this.init();
|
|
|
|
Library.instance = this;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
init = () => {
|
2022-06-22 21:05:10 +03:00
|
|
|
this.state = 'load';
|
|
|
|
this.patterns = this.update();
|
|
|
|
};
|
|
|
|
update = async () => {
|
|
|
|
const url = 'https://wavelovers.ru/assets/patterns.json';
|
|
|
|
try {
|
|
|
|
const response = await fetch(url);
|
|
|
|
if (response.ok) {
|
|
|
|
let json = await response.json();
|
|
|
|
this.patterns = json;
|
|
|
|
this.state = 'draw';
|
|
|
|
} else {
|
|
|
|
console.log('Connect to the Internet for download more patterns...');
|
|
|
|
this.state = 'fail';
|
|
|
|
};
|
|
|
|
} catch (error) {
|
|
|
|
console.log('[error]', error);
|
|
|
|
};
|
2022-06-18 23:11:09 +03:00
|
|
|
};
|
|
|
|
};
|
2022-06-15 15:35:22 +03:00
|
|
|
|
|
|
|
class Gamepad {
|
2022-06-18 23:11:09 +03:00
|
|
|
constructor(gamepad, $container) {
|
2022-06-15 15:35:22 +03:00
|
|
|
this.unit = gamepad;
|
|
|
|
this.$container = $container;
|
|
|
|
this.init();
|
|
|
|
};
|
|
|
|
|
|
|
|
init = () => {
|
|
|
|
this.id = Date.now();
|
2022-06-17 13:00:12 +03:00
|
|
|
this.canVibrate = (this.unit.vibrationActuator) ? true : false;
|
2022-06-15 15:35:22 +03:00
|
|
|
this.isVibrating = false;
|
2022-06-18 23:11:09 +03:00
|
|
|
|
|
|
|
this.library = new Library;
|
|
|
|
|
2022-06-15 15:35:22 +03:00
|
|
|
this.index = 0;
|
2022-06-18 23:11:09 +03:00
|
|
|
this.pattern = this.library.patterns[this.index].pattern;
|
|
|
|
|
2022-06-15 15:35:22 +03:00
|
|
|
this.generateBox();
|
|
|
|
};
|
|
|
|
|
|
|
|
delete = () => {
|
|
|
|
this.$list_item.parentNode.removeChild(this.$list_item);
|
|
|
|
};
|
|
|
|
generateBox = () => {
|
|
|
|
const $list_item = document.createElement('div');
|
|
|
|
const $info_box = document.createElement('div');
|
|
|
|
|
|
|
|
$list_item.classList.add('list-item');
|
|
|
|
$info_box.classList.add('list-item__info');
|
|
|
|
|
|
|
|
$list_item.appendChild($info_box);
|
|
|
|
this.$container.appendChild($list_item);
|
|
|
|
|
|
|
|
this.$list_item = $list_item;
|
|
|
|
this.$info_box = $info_box;
|
|
|
|
this.draw();
|
|
|
|
};
|
|
|
|
draw = () => {
|
|
|
|
this.$info_box.innerHTML = `
|
2022-06-17 18:10:41 +03:00
|
|
|
<span>Gamepad #${this.unit.index + 1}. ${this.unit.id}.</span>`;
|
2022-06-15 15:35:22 +03:00
|
|
|
if (this.isSelected === true) {
|
|
|
|
this.$list_item.classList.add('list-item_selected');
|
|
|
|
} else {
|
|
|
|
this.$list_item.classList.remove('list-item_selected');
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
update = () => {
|
|
|
|
let gamepads = navigator.getGamepads();
|
|
|
|
this.unit = gamepads[this.unit.index];
|
|
|
|
};
|
|
|
|
|
|
|
|
reset = () => {
|
|
|
|
this.isVibrating = false;
|
|
|
|
this.unit.vibrationActuator.reset();
|
|
|
|
};
|
|
|
|
vibrate = async () => {
|
|
|
|
this.isVibrating = true;
|
2022-06-18 23:11:09 +03:00
|
|
|
this.pattern = this.library.patterns[this.index].pattern;
|
2022-06-15 15:35:22 +03:00
|
|
|
|
|
|
|
while (this.isVibrating) {
|
|
|
|
for (let i = 0; i < this.pattern.length; i++) {
|
|
|
|
if (this.isVibrating) {
|
|
|
|
this.unit.vibrationActuator.playEffect('dual-rumble', this.pattern[i]);
|
|
|
|
await this.sleep(this.pattern[i].startDelay + this.pattern[i].duration + 100);
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
sleep = (ms) => {
|
|
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
|
|
};
|
2022-06-16 21:20:25 +03:00
|
|
|
change = (index) => {
|
|
|
|
this.index = index;
|
2022-06-18 23:11:09 +03:00
|
|
|
this.pattern = this.library.patterns[this.index].pattern;
|
2022-06-16 21:20:25 +03:00
|
|
|
};
|
2022-06-15 15:35:22 +03:00
|
|
|
};
|
|
|
|
|
2022-06-21 17:30:54 +03:00
|
|
|
class Wavelovers {
|
2022-06-15 15:35:22 +03:00
|
|
|
constructor() {
|
|
|
|
this.init();
|
|
|
|
};
|
|
|
|
init = () => {
|
|
|
|
this.#DOMs();
|
2022-06-18 23:11:09 +03:00
|
|
|
this.library = new Library();
|
2022-06-18 20:36:35 +03:00
|
|
|
|
2022-06-15 15:35:22 +03:00
|
|
|
if (!this.checkGamepadSupport()) {
|
|
|
|
console.log(`This browser does not support of gamepads.`);
|
|
|
|
this.$MESSAGE.innerText = `This browser does not support of gamepads.`;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
console.log(`Press any gamepad's button or connect new gamepad.`);
|
|
|
|
this.$MESSAGE.innerText = `Press any gamepad's button or connect new gamepad.`;
|
|
|
|
};
|
|
|
|
|
|
|
|
this.gamepads = [];
|
|
|
|
this.#eventListeners();
|
|
|
|
this.interval = setInterval(this.eventLoop, 1);
|
|
|
|
};
|
|
|
|
|
|
|
|
eventLoop = () => {
|
|
|
|
this.update();
|
|
|
|
this.draw();
|
|
|
|
};
|
|
|
|
update = () => {
|
|
|
|
if (this.gamepads.length > 0) {
|
2022-06-17 16:36:30 +03:00
|
|
|
this.$MESSAGE.classList.add('hidden');
|
|
|
|
this.$DEVICE_LIST.classList.remove('hidden');
|
2022-06-15 15:35:22 +03:00
|
|
|
this.gamepads.forEach(gamepad => {
|
|
|
|
gamepad.update();
|
|
|
|
});
|
|
|
|
} else {
|
2022-06-17 16:36:30 +03:00
|
|
|
this.$MESSAGE.classList.remove('hidden');
|
|
|
|
this.$DEVICE_LIST.classList.add('hidden');
|
2022-06-15 15:35:22 +03:00
|
|
|
};
|
|
|
|
};
|
|
|
|
draw = () => {
|
|
|
|
if (this.gamepads.length > 0) {
|
|
|
|
this.gamepads.forEach(gamepad => {
|
|
|
|
gamepad.draw();
|
|
|
|
});
|
|
|
|
};
|
2022-06-22 21:05:10 +03:00
|
|
|
if (this.library.state === 'draw') {
|
|
|
|
this.print(this.library.patterns);
|
|
|
|
this.library.state = 'ready';
|
|
|
|
};
|
|
|
|
if (this.library.state === 'fail') {
|
|
|
|
this.$PATTERN_LIST.innerHTML = `
|
|
|
|
<div class="message">
|
|
|
|
<span>Loading error...</span>
|
|
|
|
</div>`;
|
|
|
|
};
|
2022-06-15 15:35:22 +03:00
|
|
|
};
|
|
|
|
|
2022-06-16 20:47:46 +03:00
|
|
|
print = (patterns) => {
|
2022-06-17 15:21:23 +03:00
|
|
|
this.$PATTERN_LIST.innerHTML = '';
|
2022-06-16 21:20:25 +03:00
|
|
|
patterns.forEach((pattern, index) => {
|
|
|
|
const $container = document.createElement('div');
|
|
|
|
const $icon = document.createElement('span');
|
|
|
|
const $name = document.createElement('span');
|
|
|
|
|
|
|
|
$container.classList.add('pattern-item');
|
|
|
|
$icon.classList.add('pattern-item__icon');
|
|
|
|
$name.classList.add('pattern-item__name');
|
|
|
|
|
|
|
|
$icon.innerHTML = pattern.icon;
|
|
|
|
$name.innerHTML = pattern.name;
|
|
|
|
|
|
|
|
$container.appendChild($icon);
|
|
|
|
$container.appendChild($name);
|
|
|
|
|
|
|
|
$container.addEventListener('click', () => this.change(index));
|
|
|
|
|
|
|
|
this.$PATTERN_LIST.appendChild($container);
|
2022-06-17 15:21:23 +03:00
|
|
|
pattern['container'] = $container;
|
2022-06-16 20:47:46 +03:00
|
|
|
});
|
|
|
|
};
|
2022-06-16 21:20:25 +03:00
|
|
|
change = (index) => {
|
|
|
|
if (this.gamepads.length > 0) {
|
|
|
|
this.gamepads.forEach(gamepad => {
|
2022-06-18 12:08:13 +03:00
|
|
|
if (gamepad.canVibrate === true) {
|
2022-06-18 23:11:09 +03:00
|
|
|
this.unselect(this.library.patterns);
|
2022-06-18 12:08:13 +03:00
|
|
|
if (gamepad.index === index &&
|
|
|
|
gamepad.isVibrating === true) {
|
|
|
|
gamepad.reset();
|
|
|
|
} else {
|
|
|
|
gamepad.reset()
|
|
|
|
gamepad.change(index);
|
|
|
|
gamepad.vibrate();
|
2022-06-18 23:11:09 +03:00
|
|
|
this.select(this.library.patterns, index);
|
2022-06-18 12:08:13 +03:00
|
|
|
};
|
2022-06-16 21:20:25 +03:00
|
|
|
};
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
console.log('No connected devices...');
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-06-18 23:11:09 +03:00
|
|
|
unselect = (patterns) => {
|
|
|
|
patterns.forEach(pattern => {
|
2022-06-17 18:10:41 +03:00
|
|
|
pattern['container'].classList.remove('pattern-item__selected');
|
|
|
|
});
|
|
|
|
};
|
2022-06-18 23:11:09 +03:00
|
|
|
select = (patterns, index) => {
|
|
|
|
patterns[index]['container'].classList.add('pattern-item__selected');
|
2022-06-17 18:10:41 +03:00
|
|
|
};
|
|
|
|
|
2022-06-16 21:20:25 +03:00
|
|
|
checkGamepadSupport = () => {
|
|
|
|
return 'getGamepads' in window.navigator;
|
|
|
|
};
|
2022-06-16 20:47:46 +03:00
|
|
|
|
2022-06-15 15:35:22 +03:00
|
|
|
#DOMs = () => {
|
|
|
|
this.$DEVICE_BOX = document.querySelector('#device-box');
|
2022-06-17 16:36:30 +03:00
|
|
|
this.$MESSAGE = document.querySelector('#message');
|
2022-06-16 20:47:46 +03:00
|
|
|
this.$DEVICE_LIST = document.querySelector('#device-list');
|
|
|
|
this.$PATTERN_BOX = document.querySelector('#pattern-box');
|
|
|
|
this.$PATTERN_LIST = document.querySelector('#pattern-list');
|
2022-06-15 15:35:22 +03:00
|
|
|
};
|
|
|
|
#eventListeners = () => {
|
|
|
|
window.addEventListener('gamepadconnected', (event) => {
|
2022-06-17 18:10:41 +03:00
|
|
|
if (this.gamepads.length > 1) {
|
|
|
|
return;
|
|
|
|
} else {
|
2022-06-18 23:11:09 +03:00
|
|
|
this.gamepads.push(new Gamepad(event.gamepad, this.$DEVICE_LIST));
|
2022-06-17 18:10:41 +03:00
|
|
|
};
|
2022-06-15 15:35:22 +03:00
|
|
|
});
|
|
|
|
window.addEventListener('gamepaddisconnected', (event) => {
|
|
|
|
this.gamepads.forEach((gamepad, index) => {
|
|
|
|
if (gamepad.unit.id === event.gamepad.id) {
|
|
|
|
this.gamepads[index].delete();
|
|
|
|
this.gamepads.splice(index, 1);
|
|
|
|
};
|
|
|
|
});
|
2022-06-18 12:08:13 +03:00
|
|
|
this.unselect();
|
2022-06-15 15:35:22 +03:00
|
|
|
});
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/* -------------- */
|
|
|
|
/* INITIALIZATION */
|
|
|
|
/* -------------- */
|
|
|
|
|
2022-06-21 17:30:54 +03:00
|
|
|
const WAVELOVERS = new Wavelovers();
|
2022-06-15 15:35:22 +03:00
|
|
|
|