added a demo mode
This commit is contained in:
parent
af6c61bec5
commit
495a49f681
@ -65,6 +65,7 @@
|
|||||||
|
|
||||||
<script src="https://static.e7d.io/libs/jquery/3.1.1/jquery.min.js"></script>
|
<script src="https://static.e7d.io/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||||
<script src="js/urlParam.jquery.js"></script>
|
<script src="js/urlParam.jquery.js"></script>
|
||||||
|
<script src="js/gamepad-demo.js"></script>
|
||||||
<script src="js/gamepad.js"></script>
|
<script src="js/gamepad.js"></script>
|
||||||
<script src="js/app.js"></script>
|
<script src="js/app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
221
js/gamepad-demo.js
Normal file
221
js/gamepad-demo.js
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
/**
|
||||||
|
* The Gamepad demo class
|
||||||
|
*
|
||||||
|
* @class GamepadDemo
|
||||||
|
*/
|
||||||
|
class GamepadDemo {
|
||||||
|
/**
|
||||||
|
* Creates an instance of GamepadDemo.
|
||||||
|
*
|
||||||
|
* @param Gamepad gamepad
|
||||||
|
*/
|
||||||
|
constructor(gamepad) {
|
||||||
|
this.gamepad = gamepad;
|
||||||
|
this.demoGamepad = {
|
||||||
|
'id': id,
|
||||||
|
'timestamp': 0,
|
||||||
|
'index': 'demo',
|
||||||
|
'mapping': 'standard',
|
||||||
|
'axes': [],
|
||||||
|
'buttons': [],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let axisIndex = 0; axisIndex < 6; axisIndex++) {
|
||||||
|
this.demoGamepad.axes[axisIndex] = 0;
|
||||||
|
}
|
||||||
|
for (let buttonIndex = 0; buttonIndex < 20; buttonIndex++) {
|
||||||
|
this.demoGamepad.buttons[buttonIndex] = {
|
||||||
|
pressed: false,
|
||||||
|
value: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the demonstration mode
|
||||||
|
*
|
||||||
|
* @param {string} [mode='random']
|
||||||
|
* @param {string} [id='xinput']
|
||||||
|
*/
|
||||||
|
start(mode = 'random', id = 'xinput') {
|
||||||
|
// remove any active gamepad
|
||||||
|
this.gamepad.removeGamepad(true);
|
||||||
|
|
||||||
|
// add the demo gamepad to the gamepads list
|
||||||
|
this.gamepad.gamepads['demo'] = this.demoGamepad;
|
||||||
|
// map the demo gamepad as active gamepad
|
||||||
|
this.gamepad.mapGamepad('demo');
|
||||||
|
|
||||||
|
// determine the callback to use following the demo mode
|
||||||
|
let callback;
|
||||||
|
switch (mode) {
|
||||||
|
case 'random':
|
||||||
|
callback = this.randomModeCallback;
|
||||||
|
this.demoUpdateDelay = 100;
|
||||||
|
break;
|
||||||
|
case 'realist':
|
||||||
|
callback = this.realistModeCallback;
|
||||||
|
this.demoUpdateDelay = false;
|
||||||
|
break;
|
||||||
|
case 'sequential':
|
||||||
|
default:
|
||||||
|
callback = this.launchSequentialDemoMode;
|
||||||
|
this.controlType = 'axis';
|
||||||
|
this.controlIndex = 0;
|
||||||
|
this.demoUpdateDelay = 1000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute the callback once
|
||||||
|
callback.bind(this)();
|
||||||
|
if (this.demoUpdateDelay) {
|
||||||
|
// setup an repeat callback if needed
|
||||||
|
this.demoInterval = window.setInterval(
|
||||||
|
() => {
|
||||||
|
callback.bind(this)();
|
||||||
|
},
|
||||||
|
this.demoUpdateDelay
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the demonstration mode
|
||||||
|
*/
|
||||||
|
stop() {
|
||||||
|
// stop any running demo callback
|
||||||
|
window.clearInterval(this.demoInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the random mode callback
|
||||||
|
*/
|
||||||
|
randomModeCallback() {
|
||||||
|
// set a random value for each axis
|
||||||
|
for (let axisIndex = 0; axisIndex < this.demoGamepad.axes.length; axisIndex++) {
|
||||||
|
this.demoGamepad.axes[axisIndex] = (Math.random() * 2) - 1;
|
||||||
|
}
|
||||||
|
// set a random value for each button
|
||||||
|
for (let buttonIndex = 0; buttonIndex < this.demoGamepad.buttons.length; buttonIndex++) {
|
||||||
|
this.pressButton(buttonIndex, Math.random() > 0.5, Math.random());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the realistic mode callback
|
||||||
|
*/
|
||||||
|
realistModeCallback() {
|
||||||
|
// TODO: capture a real usage, approx. 10s
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the sequential mode callback
|
||||||
|
*/
|
||||||
|
sequentialModeCallback() {
|
||||||
|
// store the current index locally
|
||||||
|
const index = this.controlIndex;
|
||||||
|
|
||||||
|
// Axis
|
||||||
|
if ('axis' === this.controlType) {
|
||||||
|
// move axis from neutral to maximum, then minimum, then neutral again
|
||||||
|
for (let i = 0; i <= 1; i = +(i + 0.01).toFixed(2)) {
|
||||||
|
let value = 0;
|
||||||
|
if (i > 0.75) {
|
||||||
|
value = (1 - i) * 4;
|
||||||
|
} else if (i > 0.25) {
|
||||||
|
value = (i - 0.5) * 4;
|
||||||
|
} else {
|
||||||
|
value = (-i) * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setTimeout(
|
||||||
|
() => {
|
||||||
|
this.moveAxis(
|
||||||
|
index,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
},
|
||||||
|
this.demoUpdateDelay * 0.7 * i
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// job is done for this axis, move to next axis
|
||||||
|
this.controlIndex++;
|
||||||
|
if (this.controlIndex >= this.demoGamepad.axes.length) {
|
||||||
|
// if all axis where animated, change for buttons
|
||||||
|
this.controlType = 'button';
|
||||||
|
this.controlIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('button' === this.controlType) {
|
||||||
|
// update button pressure from null to maximum, then release again
|
||||||
|
for (let i = 0; i <= 1; i = +(i + 0.01).toFixed(2)) {
|
||||||
|
let value = 0;
|
||||||
|
if (i > 0.5) {
|
||||||
|
value = (1 - i) * 2;
|
||||||
|
} else {
|
||||||
|
value = i * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setTimeout(
|
||||||
|
() => {
|
||||||
|
this.pressButton(
|
||||||
|
index,
|
||||||
|
value > 0,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
},
|
||||||
|
this.demoUpdateDelay * 0.7 * i
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// job is done for this axis, move to next button
|
||||||
|
this.controlIndex++;
|
||||||
|
if (this.controlIndex >= this.demoGamepad.buttons.length) {
|
||||||
|
// if all axis where animated, change for axes
|
||||||
|
this.controlType = 'axis';
|
||||||
|
this.controlIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulates a button press
|
||||||
|
*
|
||||||
|
* @param {any} index
|
||||||
|
* @param {boolean} [pressed=true]
|
||||||
|
* @param {number} [value=1]
|
||||||
|
*/
|
||||||
|
pressButton(index, pressed = true, value = 1) {
|
||||||
|
// no pressure means a null value
|
||||||
|
if (!pressed) {
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update gamepad timestamp
|
||||||
|
this.demoGamepad.timestamp++;
|
||||||
|
// update button status
|
||||||
|
this.demoGamepad.buttons[index] = {
|
||||||
|
'pressed': pressed,
|
||||||
|
'value': value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulates an axis movement
|
||||||
|
*
|
||||||
|
* @param {any} index
|
||||||
|
* @param {number} [value=1]
|
||||||
|
*/
|
||||||
|
moveAxis(index, value = 1) {
|
||||||
|
// update gamepad timestamp
|
||||||
|
this.demoGamepad.timestamp++;
|
||||||
|
// update axis status
|
||||||
|
this.demoGamepad.axes[index] = value;
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ class Gamepad {
|
|||||||
* Creates an instance of Gamepad.
|
* Creates an instance of Gamepad.
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
this.haveEvents = 'GamepadEvent' in window;
|
this.gamepadDemo = new GamepadDemo(this);
|
||||||
|
|
||||||
// cached DOM references
|
// cached DOM references
|
||||||
this.$gamepad = $('.gamepad');
|
this.$gamepad = $('.gamepad');
|
||||||
@ -56,8 +56,11 @@ class Gamepad {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// listen for gamepad related events
|
// listen for gamepad related events
|
||||||
window.addEventListener("gamepadconnected", this.onGamepadConnect.bind(this));
|
this.haveEvents = 'GamepadEvent' in window;
|
||||||
window.addEventListener("gamepaddisconnected", this.onGamepadDisconnect.bind(this));
|
if (this.haveEvents) {
|
||||||
|
window.addEventListener("gamepadconnected", this.onGamepadConnect.bind(this));
|
||||||
|
window.addEventListener("gamepaddisconnected", this.onGamepadDisconnect.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
// listen for keyboard events
|
// listen for keyboard events
|
||||||
window.addEventListener("keydown", this.onKeyDown.bind(this));
|
window.addEventListener("keydown", this.onKeyDown.bind(this));
|
||||||
@ -67,6 +70,7 @@ class Gamepad {
|
|||||||
|
|
||||||
// read URI for display parameters to initalize
|
// read URI for display parameters to initalize
|
||||||
this.params = {
|
this.params = {
|
||||||
|
demoMode: $.urlParam('demo') || null,
|
||||||
gamepadColor: $.urlParam('color') || $.urlParam('c') || null,
|
gamepadColor: $.urlParam('color') || $.urlParam('c') || null,
|
||||||
gamepadIndex: $.urlParam('index') || $.urlParam('i') || null,
|
gamepadIndex: $.urlParam('index') || $.urlParam('i') || null,
|
||||||
gamepadType: $.urlParam('type') || $.urlParam('t') || null,
|
gamepadType: $.urlParam('type') || $.urlParam('t') || null,
|
||||||
@ -81,6 +85,12 @@ class Gamepad {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.params.demoMode) {
|
||||||
|
this.gamepadDemo.start(this.params.demoMode);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// by default, enqueue a delayed display of the help modal
|
// by default, enqueue a delayed display of the help modal
|
||||||
this.displayGamepadHelp();
|
this.displayGamepadHelp();
|
||||||
}
|
}
|
||||||
@ -139,7 +149,7 @@ class Gamepad {
|
|||||||
switch (e.code) {
|
switch (e.code) {
|
||||||
case "Delete":
|
case "Delete":
|
||||||
case "Escape":
|
case "Escape":
|
||||||
this.removeGamepad(this.activeGamepadIndex);
|
this.removeGamepad(true);
|
||||||
break;
|
break;
|
||||||
case "KeyC":
|
case "KeyC":
|
||||||
this.changeGamepadColor();
|
this.changeGamepadColor();
|
||||||
@ -170,7 +180,10 @@ class Gamepad {
|
|||||||
*/
|
*/
|
||||||
refreshGamepads() {
|
refreshGamepads() {
|
||||||
// get fresh information from DOM about gamepads
|
// get fresh information from DOM about gamepads
|
||||||
this.gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);
|
const navigatorGamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);
|
||||||
|
for (let key in navigatorGamepads) {
|
||||||
|
this.gamepads[key] = navigatorGamepads[key];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -200,8 +213,14 @@ class Gamepad {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure to kill demo mode
|
||||||
|
if ('demo' === this.activeGamepadIndex) {
|
||||||
|
this.gamepadDemo.stop();
|
||||||
|
}
|
||||||
|
|
||||||
// if this is the active gamepad
|
// if this is the active gamepad
|
||||||
if (gamepadIndex === this.activeGamepadIndex) {
|
if (true === gamepadIndex ||
|
||||||
|
this.activeGamepadIndex === gamepadIndex) {
|
||||||
// clear associated date
|
// clear associated date
|
||||||
this.activeGamepadIndex = null;
|
this.activeGamepadIndex = null;
|
||||||
this.activeGamepad = null;
|
this.activeGamepad = null;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
$.urlParam = function(name) {
|
$.urlParam = function(name) {
|
||||||
let results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
|
let results = new RegExp('[\?&]' + name + '(=([^&#]*))?').exec(window.location.href);
|
||||||
if (results === null) {
|
if (results === null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return decodeURIComponent(results[1]) || 0;
|
return decodeURIComponent(results[2] || true) || true;
|
||||||
}
|
}
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user