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 = () => {
|
|
|
|
this.patterns = this.getBase();
|
|
|
|
};
|
|
|
|
getBase = () => {
|
|
|
|
return [
|
2022-06-15 15:35:22 +03:00
|
|
|
{
|
2022-06-18 23:11:09 +03:00
|
|
|
"name": "Dotted Weak",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "😌",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 100,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 0.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2022-06-17 12:42:19 +03:00
|
|
|
{
|
2022-06-18 23:11:09 +03:00
|
|
|
"name": "Dotted Strong",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "😉",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 100,
|
|
|
|
"weakMagnitude": 0.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2022-06-21 23:06:36 +03:00
|
|
|
{
|
|
|
|
"name": "Dotted AC",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "🤨",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 100,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 0.0
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 100,
|
|
|
|
"weakMagnitude": 0.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2022-06-18 23:11:09 +03:00
|
|
|
{
|
|
|
|
"name": "Dotted Max",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "🙃",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 100,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "Short Dashed Weak",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "🙂",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 250,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 0.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "Short Dashed Strong",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "😇",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 250,
|
|
|
|
"weakMagnitude": 0.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2022-06-21 23:06:36 +03:00
|
|
|
{
|
|
|
|
"name": "Short Dashed AC",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "🤤",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 250,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 0.0
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 250,
|
|
|
|
"weakMagnitude": 0.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2022-06-18 23:11:09 +03:00
|
|
|
{
|
|
|
|
"name": "Short Dashed Max",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "😊",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 250,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "Long Dashed Weak",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "😋",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 500,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 0.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "Long Dashed Strong",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "😜",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 500,
|
|
|
|
"weakMagnitude": 0.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2022-06-21 23:06:36 +03:00
|
|
|
{
|
|
|
|
"name": "Long Dashed AC",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "😝",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 500,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 0.0
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 500,
|
|
|
|
"weakMagnitude": 0.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2022-06-18 23:11:09 +03:00
|
|
|
{
|
|
|
|
"name": "Long Dashed Max",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "🤪",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 100,
|
|
|
|
"duration": 500,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "Constant Weak",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "😏",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 0,
|
|
|
|
"duration": 1000,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 0.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2022-06-17 12:42:19 +03:00
|
|
|
{
|
2022-06-18 23:11:09 +03:00
|
|
|
"name": "Constant Strong",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "🤩",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 0,
|
|
|
|
"duration": 1000,
|
|
|
|
"weakMagnitude": 0.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2022-06-21 23:06:36 +03:00
|
|
|
{
|
|
|
|
"name": "Constant AC",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "😵",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 0,
|
|
|
|
"duration": 1000,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 0.0
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"startDelay": 0,
|
|
|
|
"duration": 1000,
|
|
|
|
"weakMagnitude": 0.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2022-06-18 23:11:09 +03:00
|
|
|
{
|
|
|
|
"name": "Constant Max",
|
|
|
|
"type": "Simple",
|
|
|
|
"icon": "😍",
|
|
|
|
"pattern": [
|
|
|
|
{
|
|
|
|
"startDelay": 0,
|
|
|
|
"duration": 1000,
|
|
|
|
"weakMagnitude": 1.0,
|
|
|
|
"strongMagnitude": 1.0
|
|
|
|
}
|
|
|
|
]
|
2022-06-18 21:24:30 +03:00
|
|
|
}
|
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();
|
|
|
|
this.print(this.library.patterns);
|
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-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
|
|
|
|