mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-07-18 09:06:00 +00:00
* Add player index * Add second player * Add player index slider * add multiplayer * WIP * Clean up * Add multiplayer play
265 lines
8.5 KiB
JavaScript
Vendored
265 lines
8.5 KiB
JavaScript
Vendored
/**
|
|
* Touch controls.
|
|
*
|
|
* Virtual Gamepad / Joystick
|
|
* Left panel - Dpad
|
|
*
|
|
* @link https://jsfiddle.net/aa0et7tr/5/
|
|
* @version 1
|
|
*/
|
|
const touch = (() => {
|
|
const MAX_DIFF = 20; // radius of circle boundary
|
|
|
|
// vpad state, use for mouse button down
|
|
let vpadState = {[KEY.UP]: false, [KEY.DOWN]: false, [KEY.LEFT]: false, [KEY.RIGHT]: false};
|
|
|
|
let vpadTouchIdx = null;
|
|
let vpadTouchDrag = null;
|
|
let vpadHolder = $("#circle-pad-holder");
|
|
let vpadCircle = $("#circle-pad");
|
|
|
|
const window_ = $(window);
|
|
const buttons = $(".btn");
|
|
const playerSlider = $("#playeridx")
|
|
const dpad = $(".dpad");
|
|
|
|
function resetVpadState() {
|
|
// trigger up event?
|
|
checkVpadState(KEY.UP, false);
|
|
checkVpadState(KEY.DOWN, false);
|
|
checkVpadState(KEY.LEFT, false);
|
|
checkVpadState(KEY.RIGHT, false);
|
|
|
|
vpadTouchDrag = null;
|
|
vpadTouchIdx = null;
|
|
dpad.removeClass('pressed');
|
|
}
|
|
|
|
function checkVpadState(axis, state) {
|
|
if (state !== vpadState[axis]) {
|
|
vpadState[axis] = state;
|
|
event.pub(state ? KEY_PRESSED : KEY_RELEASED, {key: axis});
|
|
}
|
|
}
|
|
|
|
function handleVpadJoystickDown(event) {
|
|
vpadCircle.css('transition', '0s');
|
|
vpadCircle.css('-moz-transition', '0s');
|
|
vpadCircle.css('-webkit-transition', '0s');
|
|
|
|
if (event.changedTouches) {
|
|
resetVpadState();
|
|
vpadTouchIdx = event.changedTouches[0].identifier;
|
|
event.clientX = event.changedTouches[0].clientX;
|
|
event.clientY = event.changedTouches[0].clientY;
|
|
}
|
|
|
|
vpadTouchDrag = {x: event.clientX, y: event.clientY};
|
|
}
|
|
|
|
function handleVpadJoystickUp() {
|
|
if (vpadTouchDrag === null) return;
|
|
|
|
vpadCircle.css('transition', '.2s');
|
|
vpadCircle.css('-moz-transition', '.2s');
|
|
vpadCircle.css('-webkit-transition', '.2s');
|
|
vpadCircle.css('transform', 'translate3d(0px, 0px, 0px)');
|
|
vpadCircle.css('-moz-transform', 'translate3d(0px, 0px, 0px)');
|
|
vpadCircle.css('-webkit-transform', 'translate3d(0px, 0px, 0px)');
|
|
|
|
resetVpadState();
|
|
}
|
|
|
|
function handleVpadJoystickMove(event) {
|
|
if (vpadTouchDrag === null) return;
|
|
|
|
if (event.changedTouches) {
|
|
// check if moving source is from other touch?
|
|
for (let i = 0; i < event.changedTouches.length; i++) {
|
|
if (event.changedTouches[i].identifier === vpadTouchIdx) {
|
|
event.clientX = event.changedTouches[i].clientX;
|
|
event.clientY = event.changedTouches[i].clientY;
|
|
}
|
|
}
|
|
if (event.clientX === undefined || event.clientY === undefined)
|
|
return;
|
|
}
|
|
|
|
let xDiff = event.clientX - vpadTouchDrag.x;
|
|
let yDiff = event.clientY - vpadTouchDrag.y;
|
|
let angle = Math.atan2(yDiff, xDiff);
|
|
let distance = Math.min(MAX_DIFF, Math.hypot(xDiff, yDiff));
|
|
let xNew = distance * Math.cos(angle);
|
|
let yNew = distance * Math.sin(angle);
|
|
|
|
if (env.display().isLayoutSwitched) {
|
|
let tmp = xNew;
|
|
xNew = yNew;
|
|
yNew = -tmp;
|
|
}
|
|
|
|
let style = `translate(${xNew}px, ${yNew}px)`;
|
|
vpadCircle.css('transform', style);
|
|
vpadCircle.css('-webkit-transform', style);
|
|
vpadCircle.css('-moz-transform', style);
|
|
|
|
let xRatio = xNew / MAX_DIFF;
|
|
let yRatio = yNew / MAX_DIFF;
|
|
checkVpadState(KEY.LEFT, xRatio <= -0.5);
|
|
checkVpadState(KEY.RIGHT, xRatio >= 0.5);
|
|
checkVpadState(KEY.UP, yRatio <= -0.5);
|
|
checkVpadState(KEY.DOWN, yRatio >= 0.5);
|
|
}
|
|
|
|
/*
|
|
Right side - Control buttons
|
|
*/
|
|
|
|
function handleButtonDown() {
|
|
checkVpadState($(this).attr('value'), true);
|
|
// add touchIdx?
|
|
}
|
|
|
|
function handleButtonUp() {
|
|
checkVpadState($(this).attr('value'), false);
|
|
}
|
|
|
|
|
|
/*
|
|
Player index slider
|
|
*/
|
|
|
|
function handlePlayerSlider() {
|
|
socket.updatePlayerIndex($(this).val() - 1);
|
|
}
|
|
|
|
|
|
/*
|
|
Touch menu
|
|
*/
|
|
|
|
let menuTouchIdx = null;
|
|
let menuTouchDrag = null;
|
|
let menuTouchTime = null;
|
|
|
|
function handleMenuDown(event) {
|
|
// Identify of touch point
|
|
if (event.changedTouches) {
|
|
menuTouchIdx = event.changedTouches[0].identifier;
|
|
event.clientX = event.changedTouches[0].clientX;
|
|
event.clientY = event.changedTouches[0].clientY;
|
|
}
|
|
|
|
menuTouchDrag = {x: event.clientX, y: event.clientY,};
|
|
menuTouchTime = Date.now();
|
|
}
|
|
|
|
function handleMenuMove(evt) {
|
|
if (menuTouchDrag === null) return;
|
|
|
|
if (evt.changedTouches) {
|
|
// check if moving source is from other touch?
|
|
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
if (evt.changedTouches[i].identifier === menuTouchIdx) {
|
|
evt.clientX = evt.changedTouches[i].clientX;
|
|
evt.clientY = evt.changedTouches[i].clientY;
|
|
}
|
|
}
|
|
if (evt.clientX === undefined || evt.clientY === undefined)
|
|
return;
|
|
}
|
|
|
|
const pos = env.display().isLayoutSwitched ? evt.clientX - menuTouchDrag.x : menuTouchDrag.y - evt.clientY;
|
|
event.pub(MENU_PRESSED, pos);
|
|
}
|
|
|
|
function handleMenuUp(evt) {
|
|
if (menuTouchDrag === null) return;
|
|
if (evt.changedTouches) {
|
|
if (evt.changedTouches[0].identifier !== menuTouchIdx)
|
|
return;
|
|
evt.clientX = evt.changedTouches[0].clientX;
|
|
evt.clientY = evt.changedTouches[0].clientY;
|
|
}
|
|
|
|
let newY = env.display().isLayoutSwitched ? -menuTouchDrag.x + evt.clientX : menuTouchDrag.y - evt.clientY;
|
|
|
|
let interval = Date.now() - menuTouchTime; // 100ms?
|
|
if (interval < 200) {
|
|
// calc velo
|
|
newY = newY / interval * 250;
|
|
}
|
|
|
|
// current item?
|
|
event.pub(MENU_RELEASED, newY);
|
|
menuTouchDrag = null;
|
|
}
|
|
|
|
/*
|
|
Common events
|
|
*/
|
|
function handleWindowMove(event) {
|
|
event.preventDefault();
|
|
handleVpadJoystickMove(event);
|
|
handleMenuMove(event);
|
|
|
|
// moving touch
|
|
if (event.changedTouches) {
|
|
for (let i = 0; i < event.changedTouches.length; i++) {
|
|
if (event.changedTouches[i].identifier !== menuTouchIdx && event.changedTouches[i].identifier !== vpadTouchIdx) {
|
|
// check class
|
|
|
|
let elem = document.elementFromPoint(event.changedTouches[i].clientX, event.changedTouches[i].clientY);
|
|
if (elem.classList.contains('btn')) {
|
|
$(elem).trigger('touchstart');
|
|
} else {
|
|
buttons.trigger('touchend');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function handleWindowUp(ev) {
|
|
handleVpadJoystickUp(ev);
|
|
handleMenuUp(ev);
|
|
buttons.trigger('touchend');
|
|
}
|
|
|
|
// touch/mouse events for control buttons. mouseup events is binded to window.
|
|
buttons.on('mousedown', handleButtonDown);
|
|
buttons.on('touchstart', handleButtonDown);
|
|
buttons.on('touchend', handleButtonUp);
|
|
|
|
// touch/mouse events for dpad. mouseup events is binded to window.
|
|
vpadHolder.on('mousedown', handleVpadJoystickDown);
|
|
vpadHolder.on('touchstart', handleVpadJoystickDown);
|
|
vpadHolder.on('touchend', handleVpadJoystickUp);
|
|
|
|
// touch/mouse events for player slider.
|
|
playerSlider.on('oninput', handlePlayerSlider);
|
|
playerSlider.on('onchange', handlePlayerSlider);
|
|
playerSlider.on('mouseup', handlePlayerSlider);
|
|
|
|
// Bind events for menu
|
|
// TODO change this flow
|
|
event.pub(MENU_HANDLER_ATTACHED, {event: 'mousedown', handler: handleMenuDown});
|
|
event.pub(MENU_HANDLER_ATTACHED, {event: 'touchstart', handler: handleMenuDown});
|
|
event.pub(MENU_HANDLER_ATTACHED, {event: 'touchend', handler: handleMenuUp});
|
|
|
|
return {
|
|
init: () => {
|
|
// add buttons into the state 🤦
|
|
$('.btn, .btn-big').each((_, el) => {
|
|
vpadState[$(el).attr('value')] = false;
|
|
});
|
|
|
|
// Bind events for window
|
|
window_.on('mousemove', handleWindowMove);
|
|
window_[0].addEventListener('touchmove', handleWindowMove, {passive: false});
|
|
window_.on('mouseup', handleWindowUp);
|
|
|
|
log.info('[input] touch input has been initialized');
|
|
}
|
|
}
|
|
})($, document, event, KEY, window);
|