feat(2d-nds): physical buttons
This commit is contained in:
@@ -6,6 +6,49 @@ const app = useAppStore();
|
||||
const windowSize = useWindowSize();
|
||||
const hintsContainer = useTemplateRef("hintsContainer");
|
||||
|
||||
const buttonsDown = reactive(new Set<string>());
|
||||
let mousePressedButton: string | null = null;
|
||||
|
||||
const dPadStyle = computed(() => {
|
||||
const rx =
|
||||
(buttonsDown.has("UP") ? -1 : 0) + (buttonsDown.has("DOWN") ? 1 : 0);
|
||||
const ry =
|
||||
(buttonsDown.has("LEFT") ? -1 : 0) + (buttonsDown.has("RIGHT") ? 1 : 0);
|
||||
if (!rx && !ry) return {};
|
||||
return { transform: `rotateX(${rx * 12}deg) rotateY(${ry * 12}deg)` };
|
||||
});
|
||||
|
||||
const pressButton = (button: string) => {
|
||||
if (mousePressedButton) {
|
||||
buttonsDown.delete(mousePressedButton);
|
||||
window.dispatchEvent(
|
||||
new KeyboardEvent("keyup", { key: `NDS_${mousePressedButton}` }),
|
||||
);
|
||||
}
|
||||
buttonsDown.add(button);
|
||||
mousePressedButton = button;
|
||||
window.dispatchEvent(new KeyboardEvent("keydown", { key: `NDS_${button}` }));
|
||||
};
|
||||
|
||||
const releaseButton = () => {
|
||||
if (!mousePressedButton) return;
|
||||
buttonsDown.delete(mousePressedButton);
|
||||
window.dispatchEvent(
|
||||
new KeyboardEvent("keyup", { key: `NDS_${mousePressedButton}` }),
|
||||
);
|
||||
mousePressedButton = null;
|
||||
};
|
||||
|
||||
useKeyDown(({ ndsButton }) => {
|
||||
if (ndsButton) buttonsDown.add(ndsButton);
|
||||
});
|
||||
|
||||
useKeyUp(({ ndsButton }) => {
|
||||
if (ndsButton) buttonsDown.delete(ndsButton);
|
||||
});
|
||||
|
||||
useMouseUp(releaseButton);
|
||||
|
||||
const ndsScale = computed(() => {
|
||||
const scaleX = (windowSize.width.value - 40) / 235;
|
||||
const scaleY = (windowSize.height.value - 40) / 431;
|
||||
@@ -59,25 +102,77 @@ defineExpose({ ndsScale });
|
||||
|
||||
<div class="nds2d-d-pad-shadow"></div>
|
||||
<div class="nds2d-d-pad">
|
||||
<div class="nds2d-d-pad-base"></div>
|
||||
<div class="nds2d-d-pad-light"></div>
|
||||
<div class="nds2d-d-pad-tip nds2d-tip-up"></div>
|
||||
<div class="nds2d-d-pad-tip nds2d-tip-down"></div>
|
||||
<div class="nds2d-d-pad-tip nds2d-tip-left"></div>
|
||||
<div class="nds2d-d-pad-tip nds2d-tip-right"></div>
|
||||
<div class="nds2d-d-pad-marker nds2d-dpm-up"></div>
|
||||
<div class="nds2d-d-pad-marker nds2d-dpm-down"></div>
|
||||
<div class="nds2d-d-pad-marker nds2d-dpm-left"></div>
|
||||
<div class="nds2d-d-pad-marker nds2d-dpm-right"></div>
|
||||
<div class="nds2d-d-pad-inner" :style="dPadStyle">
|
||||
<div class="nds2d-d-pad-base"></div>
|
||||
<div class="nds2d-d-pad-light"></div>
|
||||
<div
|
||||
class="nds2d-d-pad-tip nds2d-tip-up"
|
||||
:class="{ pressed: buttonsDown.has('UP') }"
|
||||
@mousedown.prevent="pressButton('UP')"
|
||||
></div>
|
||||
<div
|
||||
class="nds2d-d-pad-tip nds2d-tip-down"
|
||||
:class="{ pressed: buttonsDown.has('DOWN') }"
|
||||
@mousedown.prevent="pressButton('DOWN')"
|
||||
></div>
|
||||
<div
|
||||
class="nds2d-d-pad-tip nds2d-tip-left"
|
||||
:class="{ pressed: buttonsDown.has('LEFT') }"
|
||||
@mousedown.prevent="pressButton('LEFT')"
|
||||
></div>
|
||||
<div
|
||||
class="nds2d-d-pad-tip nds2d-tip-right"
|
||||
:class="{ pressed: buttonsDown.has('RIGHT') }"
|
||||
@mousedown.prevent="pressButton('RIGHT')"
|
||||
></div>
|
||||
<div class="nds2d-d-pad-marker nds2d-dpm-up"></div>
|
||||
<div class="nds2d-d-pad-marker nds2d-dpm-down"></div>
|
||||
<div class="nds2d-d-pad-marker nds2d-dpm-left"></div>
|
||||
<div class="nds2d-d-pad-marker nds2d-dpm-right"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nds2d-button nds2d-btn-x">X</div>
|
||||
<div class="nds2d-button nds2d-btn-a">A</div>
|
||||
<div class="nds2d-button nds2d-btn-b">B</div>
|
||||
<div class="nds2d-button nds2d-btn-y">Y</div>
|
||||
<div
|
||||
class="nds2d-button nds2d-btn-x"
|
||||
:class="{ pressed: buttonsDown.has('X') }"
|
||||
@mousedown.prevent="pressButton('X')"
|
||||
>
|
||||
X
|
||||
</div>
|
||||
<div
|
||||
class="nds2d-button nds2d-btn-a"
|
||||
:class="{ pressed: buttonsDown.has('A') }"
|
||||
@mousedown.prevent="pressButton('A')"
|
||||
>
|
||||
A
|
||||
</div>
|
||||
<div
|
||||
class="nds2d-button nds2d-btn-b"
|
||||
:class="{ pressed: buttonsDown.has('B') }"
|
||||
@mousedown.prevent="pressButton('B')"
|
||||
>
|
||||
B
|
||||
</div>
|
||||
<div
|
||||
class="nds2d-button nds2d-btn-y"
|
||||
:class="{ pressed: buttonsDown.has('Y') }"
|
||||
@mousedown.prevent="pressButton('Y')"
|
||||
>
|
||||
Y
|
||||
</div>
|
||||
|
||||
<div class="nds2d-small-button nds2d-start"></div>
|
||||
<div class="nds2d-small-button nds2d-select"></div>
|
||||
<div
|
||||
class="nds2d-small-button nds2d-start"
|
||||
:class="{ pressed: buttonsDown.has('START') }"
|
||||
@mousedown.prevent="pressButton('START')"
|
||||
></div>
|
||||
<div class="nds2d-small-button-label nds2d-start-label">START</div>
|
||||
<div
|
||||
class="nds2d-small-button nds2d-select"
|
||||
:class="{ pressed: buttonsDown.has('SELECT') }"
|
||||
@mousedown.prevent="pressButton('SELECT')"
|
||||
></div>
|
||||
<div class="nds2d-small-button-label nds2d-select-label">SELECT</div>
|
||||
|
||||
<div
|
||||
ref="hintsContainer"
|
||||
@@ -335,6 +430,13 @@ defineExpose({ ndsScale });
|
||||
);
|
||||
}
|
||||
|
||||
.nds2d-d-pad-inner {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: transform 0.06s ease;
|
||||
}
|
||||
|
||||
.nds2d-d-pad-base {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
@@ -351,6 +453,10 @@ defineExpose({ ndsScale });
|
||||
|
||||
.nds2d-d-pad-tip {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
filter 0.06s ease,
|
||||
box-shadow 0.06s ease;
|
||||
}
|
||||
|
||||
.nds2d-tip-up {
|
||||
@@ -361,6 +467,11 @@ defineExpose({ ndsScale });
|
||||
box-shadow: inset 0 2px 3px -1px #444;
|
||||
}
|
||||
|
||||
.nds2d-tip-up.pressed {
|
||||
filter: brightness(0.75);
|
||||
box-shadow: inset 0 6px 4px -6px #222;
|
||||
}
|
||||
|
||||
.nds2d-tip-down {
|
||||
left: 19px;
|
||||
bottom: 0;
|
||||
@@ -369,6 +480,11 @@ defineExpose({ ndsScale });
|
||||
box-shadow: inset 0 -2px 3px -1px #444;
|
||||
}
|
||||
|
||||
.nds2d-tip-down.pressed {
|
||||
filter: brightness(0.75);
|
||||
box-shadow: inset 0 -6px 4px -6px #222;
|
||||
}
|
||||
|
||||
.nds2d-tip-left {
|
||||
left: 0;
|
||||
top: 19px;
|
||||
@@ -377,6 +493,11 @@ defineExpose({ ndsScale });
|
||||
box-shadow: inset 2px 0 3px -1px #444;
|
||||
}
|
||||
|
||||
.nds2d-tip-left.pressed {
|
||||
filter: brightness(0.75);
|
||||
box-shadow: inset 6px 0 4px -6px #222;
|
||||
}
|
||||
|
||||
.nds2d-tip-right {
|
||||
right: 0;
|
||||
top: 19px;
|
||||
@@ -385,9 +506,15 @@ defineExpose({ ndsScale });
|
||||
box-shadow: inset -2px 0 3px -1px #444;
|
||||
}
|
||||
|
||||
.nds2d-tip-right.pressed {
|
||||
filter: brightness(0.75);
|
||||
box-shadow: inset -6px 0 4px -6px #222;
|
||||
}
|
||||
|
||||
.nds2d-d-pad-marker {
|
||||
position: absolute;
|
||||
background: #999;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.nds2d-dpm-up,
|
||||
@@ -424,6 +551,7 @@ defineExpose({ ndsScale });
|
||||
|
||||
.nds2d-button {
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
@@ -438,6 +566,16 @@ defineExpose({ ndsScale });
|
||||
box-shadow:
|
||||
3px 2px 3px -2px #111,
|
||||
inset 2px 2px 3px -1px #444;
|
||||
transition:
|
||||
box-shadow 0.06s ease,
|
||||
transform 0.06s ease;
|
||||
}
|
||||
|
||||
.nds2d-button.pressed {
|
||||
box-shadow:
|
||||
1px 1px 1px -1px #111,
|
||||
inset 2px 2px 3px -1px #222;
|
||||
transform: scale(0.91) translateY(1px);
|
||||
}
|
||||
|
||||
.nds2d-btn-x {
|
||||
@@ -462,6 +600,7 @@ defineExpose({ ndsScale });
|
||||
|
||||
.nds2d-small-button {
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
@@ -473,6 +612,16 @@ defineExpose({ ndsScale });
|
||||
box-shadow:
|
||||
3px 2px 3px -2px #111,
|
||||
inset 2px 2px 3px -1px #444;
|
||||
transition:
|
||||
box-shadow 0.06s ease,
|
||||
transform 0.06s ease;
|
||||
}
|
||||
|
||||
.nds2d-small-button.pressed {
|
||||
box-shadow:
|
||||
1px 1px 1px -1px #111,
|
||||
inset 1px 1px 2px -1px #222;
|
||||
transform: scale(0.88) translateY(1px);
|
||||
}
|
||||
|
||||
.nds2d-select {
|
||||
@@ -480,22 +629,21 @@ defineExpose({ ndsScale });
|
||||
right: 70px;
|
||||
}
|
||||
|
||||
.nds2d-start::after {
|
||||
.nds2d-small-button-label {
|
||||
position: absolute;
|
||||
content: "START";
|
||||
font-size: 7px;
|
||||
color: #999;
|
||||
left: 15px;
|
||||
top: 0px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.nds2d-select::after {
|
||||
position: absolute;
|
||||
content: "SELECT";
|
||||
font-size: 7px;
|
||||
color: #999;
|
||||
left: 15px;
|
||||
top: 0px;
|
||||
.nds2d-start-label {
|
||||
bottom: 53px;
|
||||
right: 44px;
|
||||
}
|
||||
|
||||
.nds2d-select-label {
|
||||
bottom: 29px;
|
||||
right: 40px;
|
||||
}
|
||||
|
||||
.nds2d-hints-container {
|
||||
|
||||
Reference in New Issue
Block a user