diff --git a/src/App.tsx b/src/App.tsx
index b9aed70..32f2d13 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -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 (
@@ -14,6 +23,7 @@ const App = () => {
+
);
diff --git a/src/components/InputHandler.tsx b/src/components/InputHandler.tsx
index f82cdd0..c42fdaa 100644
--- a/src/components/InputHandler.tsx
+++ b/src/components/InputHandler.tsx
@@ -120,9 +120,6 @@ const InputHandler = memo(() => {
return () => {
window.removeEventListener("keydown", handleKeyBoardEvent);
- window.removeEventListener("keyup", () => {
- firedRef.current = false;
- });
};
}, [handleKeyBoardEvent]);
diff --git a/src/dom-components/Header.tsx b/src/dom-components/Header.tsx
index f14ea03..1aac193 100644
--- a/src/dom-components/Header.tsx
+++ b/src/dom-components/Header.tsx
@@ -10,6 +10,7 @@ const Header = () => {
start
guide
discord
+ keybinding
);
};
diff --git a/src/dom-components/Keybinding.tsx b/src/dom-components/Keybinding.tsx
new file mode 100644
index 0000000..d558bee
--- /dev/null
+++ b/src/dom-components/Keybinding.tsx
@@ -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 (
+ <>
+
+
+
+ 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.
+
+
+
+
+
+ {Object.entries(bindings).map((pair, idx) => (
+ startKeybindListener(pair[0])} key={idx}>
+ {formatKey(pair[0])}
+ {pair[1]}
+
+ ))}
+
+
+
+
+
+ Reset to default bindings
+
+ >
+ );
+};
+
+export default Keybinding;
diff --git a/src/dom-components/Notes.tsx b/src/dom-components/Notes.tsx
index d655d88..64da758 100644
--- a/src/dom-components/Notes.tsx
+++ b/src/dom-components/Notes.tsx
@@ -60,10 +60,7 @@ const Notes = () => {
Your setup must support WebGL2 in order to play this game. You
can check this directly by going to{" "}
-
+
this website
. If it's not supported, this is most likely due to your
@@ -174,6 +171,14 @@ const Notes = () => {
+
+
+ If you'd like to change the keybindings, go{" "}
+
+ here
+
+ .
+
diff --git a/src/helpers/keybinding-helpers.ts b/src/helpers/keybinding-helpers.ts
new file mode 100644
index 0000000..ef2db63
--- /dev/null
+++ b/src/helpers/keybinding-helpers.ts
@@ -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;
+ }
+};
diff --git a/src/static/css/keybinding.css b/src/static/css/keybinding.css
new file mode 100644
index 0000000..85aaa80
--- /dev/null
+++ b/src/static/css/keybinding.css
@@ -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;
+}
diff --git a/src/static/css/notes.css b/src/static/css/notes.css
index 0b0dbc7..a23615a 100644
--- a/src/static/css/notes.css
+++ b/src/static/css/notes.css
@@ -56,7 +56,7 @@
vertical-align: middle;
}
-.webgl-anchor {
+.notes-a {
text-align: unset;
font-size: unset;
font-weight: unset;
diff --git a/src/store.ts b/src/store.ts
index 10684ca..82815d4 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -105,6 +105,8 @@ type State = {
siteSaveState: SiteSaveState;
+ keybindings: Record;
+
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) =>
+ set(() => ({ keybindings: to })),
+
restartGameState: () =>
set(() => ({
siteSaveState: {
diff --git a/src/utils/CustomTextureLoader.ts b/src/utils/CustomTextureLoader.ts
deleted file mode 100644
index 5b6abac..0000000
--- a/src/utils/CustomTextureLoader.ts
+++ /dev/null
@@ -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;
diff --git a/src/utils/getKeyPress.ts b/src/utils/getKeyPress.ts
index 5872288..653db29 100644
--- a/src/utils/getKeyPress.ts
+++ b/src/utils/getKeyPress.ts
@@ -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;