import { useRef, useEffect, MutableRefObject } from "react"; import { Global, css } from "@emotion/react"; import { Vector3 } from "three"; import nipplejs, { JoystickManager } from "nipplejs"; import { useEnvironment } from "../layers/environment"; type NippleMovementProps = { direction: MutableRefObject<Vector3>; }; /** * NippleMovement gives the player a direction to move by taking * input from a nipple (joystick). * * Direction is stored as a Vector3 with the following format * x: left/right movement, + for right * y: forward/back movement, + for forwards * z: up/down movement, + for up * * @param props * @constructor */ const NippleMovement = (props: NippleMovementProps) => { const { direction } = props; const nipple = useRef<JoystickManager>(); const nippleContainer = useRef<HTMLElement>(); const { containerRef } = useEnvironment(); useEffect(() => { if (containerRef.current) { nippleContainer.current = document.createElement("div"); nippleContainer.current.style.position = "fixed"; nippleContainer.current.style.left = "0"; nippleContainer.current.style.bottom = "0"; nippleContainer.current.style.width = "40%"; nippleContainer.current.style.maxWidth = "160px"; nippleContainer.current.style.height = "25%"; nippleContainer.current.style.height = "160px"; nippleContainer.current.style.zIndex = "5"; // add class identifier to nippleContainer to identify touchEvents nippleContainer.current.classList.add("nipple-container"); containerRef.current.appendChild(nippleContainer.current); nipple.current = nipplejs.create({ zone: nippleContainer.current, mode: "static", position: { left: "50%", top: "50%" }, color: "#fff", size: 120, restOpacity: 0.75, }); nipple.current.on("move", (evt, data) => { // i kinda pulled 60 out of my ass tbh const x = (data.distance / 60) * Math.cos(data.angle.radian); const y = (-data.distance / 60) * Math.sin(data.angle.radian); direction.current.set(x, y, 0); }); nipple.current.on("end", () => { direction.current.set(0, 0, 0); }); return () => { if (nipple.current) nipple.current.destroy(); }; } }, []); const nippleStyles = css` .nipple-container > * > .front, .nipple-container > * > .back { background: radial-gradient(white, white 64%, black 86%) !important; } `; return <Global styles={nippleStyles} />; }; export default NippleMovement;