added custom keybinding support

This commit is contained in:
ad044 2021-04-05 17:51:54 +04:00
parent e170489c46
commit 2f8f30d1ba
11 changed files with 200 additions and 89 deletions

View file

@ -1,12 +1,21 @@
import React from "react";
import React, { useEffect } from "react";
import "./static/css/page.css";
import Game from "./dom-components/Game";
import { HashRouter, Route, Switch } from "react-router-dom";
import Notes from "./dom-components/Notes";
import MainPage from "./dom-components/MainPage";
import Guide from "./dom-components/Guide";
import Keybinding from "./dom-components/Keybinding";
import { useStore } from "./store";
const App = () => {
const setKeybindings = useStore((state) => state.setKeybindings);
useEffect(() => {
const keybindingSettings = localStorage.getItem("lainKeybindings");
if (keybindingSettings) setKeybindings(JSON.parse(keybindingSettings));
}, [setKeybindings]);
return (
<HashRouter>
<Switch>
@ -14,6 +23,7 @@ const App = () => {
<Route path={"/notes"} exact component={Notes} />
<Route path={"/game"} exact component={Game} />
<Route path={"/guide"} exact component={Guide} />
<Route path={"/keybinding"} exact component={Keybinding} />
</Switch>
</HashRouter>
);

View file

@ -120,9 +120,6 @@ const InputHandler = memo(() => {
return () => {
window.removeEventListener("keydown", handleKeyBoardEvent);
window.removeEventListener("keyup", () => {
firedRef.current = false;
});
};
}, [handleKeyBoardEvent]);

View file

@ -10,6 +10,7 @@ const Header = () => {
<Link to="/game">start</Link>
<Link to="/guide">guide</Link>
<a href="https://discord.com/invite/W22Ga2R">discord</a>
<Link to="/keybinding">keybinding</Link>
</div>
);
};

View file

@ -0,0 +1,104 @@
import React, { useCallback, useEffect } from "react";
import { formatKey } from "../helpers/keybinding-helpers";
import "../static/css/keybinding.css";
import { useStore } from "../store";
import Header from "./Header";
const Keybinding = () => {
const setKeybindings = useStore((state) => state.setKeybindings);
const bindings = useStore((state) => state.keybindings);
useEffect(() => {
document.title = "< keybinding >";
}, []);
const handleRemap = useCallback(
(keyToRemap: string, to: string) => {
if (to.length === 1) to = to.toLowerCase();
const exists = Object.values(bindings).includes(to);
if (!exists) {
const newBindings = { ...bindings, [keyToRemap]: to };
setKeybindings(newBindings);
localStorage.setItem("lainKeybindings", JSON.stringify(newBindings));
} else {
const takenKeybind = Object.keys(bindings).find(
(k) => bindings[k] === to
);
if (takenKeybind) {
const newBindings = {
...bindings,
[takenKeybind]: "",
[keyToRemap]: to,
};
setKeybindings(newBindings);
localStorage.setItem("lainKeybindings", JSON.stringify(newBindings));
}
}
},
[bindings, setKeybindings]
);
const startKeybindListener = useCallback(
(keyToRemap: string) => {
window.addEventListener(
"keydown",
(event) => handleRemap(keyToRemap, event.key),
{ once: true }
);
},
[handleRemap]
);
const resetToDefault = useCallback(() => {
setKeybindings({
DOWN: "ArrowDown",
LEFT: "ArrowLeft",
UP: "ArrowUp",
RIGHT: "ArrowRight",
CIRCLE: "x",
CROSS: "z",
TRIANGLE: "d",
SQUARE: "s",
R2: "t",
L2: "e",
L1: "w",
R1: "r",
START: "v",
SELECT: "c",
});
localStorage.removeItem("lainKeybindings");
}, [setKeybindings]);
return (
<>
<Header />
<br />
<p className="keybinding-note">
This is the keybindings page. To change a keybinding, just click on it
and press the button you wish to bind it to after. In order for this to
take effect, you must refresh the game page.
</p>
<br />
<div className="keybinding">
<table className="control-table">
<tbody>
{Object.entries(bindings).map((pair, idx) => (
<tr onClick={() => startKeybindListener(pair[0])} key={idx}>
<td>{formatKey(pair[0])}</td>
<td>{pair[1]}</td>
</tr>
))}
</tbody>
</table>
</div>
<br />
<button className="reset-to-default-button" onClick={resetToDefault}>
Reset to default bindings
</button>
</>
);
};
export default Keybinding;

View file

@ -60,10 +60,7 @@ const Notes = () => {
<p>
Your setup must support WebGL2 in order to play this game. You
can check this directly by going to{" "}
<a
href={"https://get.webgl.org/webgl2/"}
className="webgl-anchor"
>
<a href={"https://get.webgl.org/webgl2/"} className="notes-a">
this website
</a>
. If it's not supported, this is most likely due to your
@ -174,6 +171,14 @@ const Notes = () => {
</tr>
</tbody>
</table>
<br />
<span className="text-center">
If you'd like to change the keybindings, go{" "}
<Link to={"/keybinding"} className="notes-a">
here
</Link>
.
</span>
</td>
</tr>

View file

@ -0,0 +1,22 @@
export const formatKey = (key: string) => {
switch (key) {
case "DOWN":
return "↓";
case "LEFT":
return "←";
case "UP":
return "↑";
case "RIGHT":
return "→";
case "CIRCLE":
return "◯";
case "CROSS":
return "✖";
case "SQUARE":
return "◼";
case "TRIANGLE":
return "▲";
default:
return key;
}
};

View file

@ -0,0 +1,20 @@
.keybinding {
color: white;
display: block;
margin: 0 auto;
text-align: center;
font-size: 1.5rem;
}
.keybinding-note {
text-align: center;
font-size: 1.7rem;
color: white;
padding-left: 5em;
padding-right: 5em;
}
.reset-to-default-button {
display: block;
margin: 0 auto;
}

View file

@ -56,7 +56,7 @@
vertical-align: middle;
}
.webgl-anchor {
.notes-a {
text-align: unset;
font-size: unset;
font-weight: unset;

View file

@ -105,6 +105,8 @@ type State = {
siteSaveState: SiteSaveState;
keybindings: Record<string, string>;
inputCooldown: number;
};
@ -237,6 +239,24 @@ export const useStore = create(
},
},
// keybindings
keybindings: {
DOWN: "ArrowDown",
LEFT: "ArrowLeft",
UP: "ArrowUp",
RIGHT: "ArrowRight",
CIRCLE: "x",
CROSS: "z",
TRIANGLE: "d",
SQUARE: "s",
R2: "t",
L2: "e",
L1: "w",
R1: "r",
START: "v",
SELECT: "c",
},
inputCooldown: -1,
} as State,
(set) => ({
@ -340,6 +360,9 @@ export const useStore = create(
playerName: userState.playerName,
})),
setKeybindings: (to: Record<string, string>) =>
set(() => ({ keybindings: to })),
restartGameState: () =>
set(() => ({
siteSaveState: {

View file

@ -1,59 +0,0 @@
import {
Loader,
RGBAFormat,
RGBFormat,
ImageLoader,
Texture,
LinearFilter,
NearestFilter,
ClampToEdgeWrapping,
} from "three";
/*
custom implementation of TextureLoader that automatically sets minFilter to NearestFilter for proper WebGL1 support.
this is still experimental
*/
export class CustomTextureLoader extends Loader {
load = (
url: string,
onLoad?: (texture: Texture) => void,
onProgress?: (event: ProgressEvent) => void,
onError?: (event: ErrorEvent) => void
): Texture => {
const texture = new Texture();
texture.generateMipmaps = false;
texture.wrapS = texture.wrapT = ClampToEdgeWrapping;
texture.minFilter = LinearFilter;
const loader = new ImageLoader(this.manager);
loader.setCrossOrigin(this.crossOrigin);
loader.setPath(this.path);
loader.load(
url,
function (image: HTMLImageElement) {
texture.image = image;
const isJPEG =
url.search(/\.jpe?g($|\?)/i) > 0 ||
url.search(/^data:image\/jpeg/) === 0;
texture.format = isJPEG ? RGBFormat : RGBAFormat;
texture.needsUpdate = true;
if (onLoad !== undefined) {
onLoad(texture);
}
},
onProgress,
onError
);
return texture;
};
}
export default CustomTextureLoader;

View file

@ -1,25 +1,13 @@
const getKeyPress = (key: string) => {
// make the keybinds work with caps lock on aswell
if (["X", "Z", "D", "E", "V", "T", "W", "R", "S", "C"].includes(key))
key = key.toLowerCase();
import { useStore } from "../store";
const keyCodeAssocs = {
ArrowDown: "DOWN",
ArrowLeft: "LEFT",
ArrowUp: "UP",
ArrowRight: "RIGHT",
x: "CIRCLE",
z: "CROSS",
d: "TRIANGLE",
s: "SQUARE",
t: "R2",
e: "L2",
w: "L1",
r: "R1",
v: "START",
c: "SELECT",
};
return keyCodeAssocs[key as keyof typeof keyCodeAssocs];
const getKeyPress = (key: string) => {
const keybindings = useStore.getState().keybindings;
console.log(keybindings);
// make the keybinds work with caps lock on aswell
if (key.length === 1) key = key.toLowerCase();
return Object.keys(keybindings).find((k) => keybindings[k] === key);
};
export default getKeyPress;