diff --git a/public/assets/images/nwjns/danielle-sprite.png b/public/assets/images/nwjns/danielle-sprite.png new file mode 100644 index 0000000..562887d Binary files /dev/null and b/public/assets/images/nwjns/danielle-sprite.png differ diff --git a/public/assets/images/nwjns/haerin-sprite.png b/public/assets/images/nwjns/haerin-sprite.png new file mode 100644 index 0000000..27cbc13 Binary files /dev/null and b/public/assets/images/nwjns/haerin-sprite.png differ diff --git a/src/app/nwjns-powerpuffgirl/_app.tsx b/src/app/nwjns-powerpuffgirl/_app.tsx new file mode 100644 index 0000000..1b43b97 --- /dev/null +++ b/src/app/nwjns-powerpuffgirl/_app.tsx @@ -0,0 +1,218 @@ +"use client"; + +import { MouseEventHandler, RefObject, useCallback, useEffect, useRef } from "react"; +import Link from "next/link"; + +import { + BACKGROUND_BLUR, + CHARACTER_SIZE, + STAGE_HEIGHT, + STAGE_WIDTH, + STANDARD_HEIGHT, + THRESHOLD_RATIO, +} from "./model/constants"; +import { NWJNSCharacter, Offsets, defaultCharacters } from "./model/types"; + +import { ScreenType } from "@/utils/types"; +import { FPS_OFFSET } from "@/utils/constants"; +import { Coordinate } from "@/utils/physicalEngine"; +import { moveSequence } from "./utils/stream"; +import { getWindowRatio, sleep } from "@/utils/utilFunctions"; + +import "./nwjns.scss"; + +export default function NWJNS_Powerpuffgirl() { + const offsetRef = useRef({ stageWidth: 0, stageHeight: 0, charaSize: 0, screenType: ScreenType.Normal }); + + const stageRef: RefObject = useRef(null); + const bgTopRef: RefObject = useRef(null); + const bgBottomRef: RefObject = useRef(null); + const bgLeftRef: RefObject = useRef(null); + const bgRightRef: RefObject = useRef(null); + const pageBlockRef: RefObject = useRef(null); + + const charaList = useRef>([...defaultCharacters]); + + useEffect(() => { + console.log(window.navigator.userAgent); + resizeInitialize(); + window.addEventListener("resize", resizeInitialize); + + const moveInterval = setInterval(charaMove, FPS_OFFSET); + + interactionInitialize(50); + + return () => { + window.removeEventListener("resize", resizeInitialize); + clearInterval(moveInterval); + }; + }, []); + + const resizeInitialize = () => { + if ( + stageRef.current === null || + bgTopRef.current === null || + bgBottomRef.current === null || + bgLeftRef.current === null || + bgRightRef.current === null + ) + return; + + document.documentElement.style.setProperty("--blur", `${BACKGROUND_BLUR}px`); + + // 스크린 초기화 + for (let i = STANDARD_HEIGHT.length - 1; i >= 0; i--) { + if (getWindowRatio() > 9 / 16) { + if (STANDARD_HEIGHT[i] > window.innerHeight) continue; + } else { + if (STAGE_WIDTH[i] > window.innerWidth) continue; + } + if (i == 0 && pageBlockRef.current) { + pageBlockRef.current.style.display = "flex"; + } else if (pageBlockRef.current) { + pageBlockRef.current.style.display = "none"; + } + + const horGap = (window.innerWidth - STAGE_WIDTH[i]) / 2; + const verGap = (window.innerHeight - STAGE_HEIGHT[i]) / 2; + + // 오프셋 설정 + offsetRef.current.stageWidth = STAGE_WIDTH[i]; + offsetRef.current.stageHeight = STAGE_HEIGHT[i]; + offsetRef.current.charaSize = CHARACTER_SIZE[i]; + + // 배경 resolution + stageRef.current.style.width = STAGE_WIDTH[i] + "px"; + stageRef.current.style.height = STAGE_HEIGHT[i] + "px"; + + bgTopRef.current.style.height = verGap + "px"; + bgBottomRef.current.style.height = verGap + "px"; + bgLeftRef.current.style.width = horGap + "px"; + bgRightRef.current.style.width = horGap + "px"; + + bgTopRef.current.style.width = STAGE_WIDTH[i] + 5 + "px"; + bgBottomRef.current.style.width = STAGE_WIDTH[i] + 5 + "px"; + + // Character size + document.documentElement.style.setProperty("--chara-size", `${CHARACTER_SIZE[i]}px`); + charaList.current.forEach((v) => { + if (v.ref.current) { + v.ref.current.style.backgroundPosition = `${-CHARACTER_SIZE[i] * 2}px, 0`; + } + }); + + break; + } + }; + + const charaMove = useCallback(() => { + charaList.current.forEach((v, i) => { + const charaRef = v.ref; + const charaPhysics = v.physics; + if (charaRef.current === null) return; + + charaPhysics.HOVER.vy = charaPhysics.HOVER_SEQ.next().value; + + let endX = charaPhysics.DST.X + charaPhysics.HOVER.vx; + let endY = charaPhysics.DST.Y + charaPhysics.HOVER.vy; + + charaRef.current.style.left = endX + "px"; + charaRef.current.style.top = endY + "px"; + }); + }, []); + + const singleMove = async (index: number, end: Coordinate, frames: number = 70) => { + const charaRef = charaList.current[index].ref; + const charaPhysics = charaList.current[index].physics; + + if (charaRef.current === null) return; + const start = { X: charaRef.current.offsetLeft, Y: charaRef.current.offsetTop }; + const seq = moveSequence(start, end, frames); + const charaSize = offsetRef.current.charaSize; + let seqNow; + let i = 0; + do { + await sleep(FPS_OFFSET); + + i++; + seqNow = seq.next(); + + if (start.X <= end.X) { + if (i === 1) charaRef.current.style.backgroundPosition = `${-charaSize * 1}px 0`; + if (i === 10) charaRef.current.style.backgroundPosition = `${-charaSize * 0}px 0`; + if (i === frames - 10) charaRef.current.style.backgroundPosition = `${-charaSize * 1}px 0`; + if (i === frames) charaRef.current.style.backgroundPosition = `${-charaSize * 2}px 0`; + } else { + if (i === 1) charaRef.current.style.backgroundPosition = `${-charaSize * 4}px 0`; + if (i === 10) charaRef.current.style.backgroundPosition = `${-charaSize * 3}px 0`; + if (i === frames - 10) charaRef.current.style.backgroundPosition = `${-charaSize * 4}px 0`; + if (i === frames) charaRef.current.style.backgroundPosition = `${-charaSize * 5}px 0`; + } + + charaPhysics.DST.X = seqNow.value.X; + charaPhysics.DST.Y = seqNow.value.Y; + } while (!seqNow.done); + }; + + const interactionInitialize = (frames: number = 70) => { + const distShort = offsetRef.current.charaSize; + const distLong = (distShort * 5) / 4; + + if (stageRef.current) { + stageRef.current.style.zIndex = "1"; + } + + if (getWindowRatio() > THRESHOLD_RATIO) { + singleMove(0, { X: window.innerWidth * 0.15 - distShort, Y: window.innerHeight * 0.5 - distLong }, frames); + singleMove(1, { X: window.innerWidth * 0.15, Y: window.innerHeight * 0.5 }, frames); + singleMove(2, { X: window.innerWidth * 0.15 - distLong, Y: window.innerHeight * 0.5 + distShort }, frames); + singleMove(3, { X: window.innerWidth * 0.15 + distLong, Y: window.innerHeight * 0.5 - distShort }, frames); + singleMove(4, { X: window.innerWidth * 0.15 + distShort, Y: window.innerHeight * 0.5 + distLong }, frames); + } else { + singleMove(0, { X: -window.innerWidth * 0.3 - distShort, Y: window.innerHeight * 0.5 - distLong }, frames); + singleMove(1, { X: -window.innerWidth * 0.3, Y: window.innerHeight * 0.5 }, frames); + singleMove(2, { X: -window.innerWidth * 0.3 - distLong, Y: window.innerHeight * 0.5 + distShort }, frames); + singleMove(3, { X: -window.innerWidth * 0.3 + distLong, Y: window.innerHeight * 0.5 - distShort }, frames); + singleMove(4, { X: -window.innerWidth * 0.3 + distShort, Y: window.innerHeight * 0.5 + distLong }, frames); + } + + setTimeout(() => { + if (stageRef.current) { + stageRef.current.style.zIndex = "0"; + } + }, FPS_OFFSET * frames); + }; + + const mouseClickEvent: MouseEventHandler = (e: React.MouseEvent) => { + charaList.current.map((v, i) => { + if (v.ref.current === null) return; + + if (getWindowRatio() > THRESHOLD_RATIO) { + singleMove(i, { X: v.ref.current.offsetLeft + window.innerWidth * 0.35, Y: v.ref.current.offsetTop }); + } else { + singleMove(i, { X: v.ref.current.offsetLeft + window.innerWidth * 0.8, Y: v.ref.current.offsetTop }); + } + }); + }; + + return ( +
+
+ {charaList.current.map((v, i) => { + return
; + })} +
+
+
+
+ + + 뒤로가기 + +
interactionInitialize()}> + 초기화 +
+
{`Screen size is too small`}
+
+ ); +} diff --git a/src/app/nwjns-powerpuffgirl/model/constants.ts b/src/app/nwjns-powerpuffgirl/model/constants.ts new file mode 100644 index 0000000..a108d44 --- /dev/null +++ b/src/app/nwjns-powerpuffgirl/model/constants.ts @@ -0,0 +1,8 @@ +export const STAGE_WIDTH = [0, 270, 360, 450, 540, 675, 900]; +export const STAGE_HEIGHT = [0, 480, 640, 800, 960, 1200, 1600]; +export const STANDARD_WIDTH = [0, 270, 360, 450, 600, 750, 1000]; +export const STANDARD_HEIGHT = [0, 480, 640, 900, 1050, 1300, 1800]; +export const CHARACTER_SIZE = [0, 40, 60, 80, 100, 120, 160]; + +export const BACKGROUND_BLUR = 5; +export const THRESHOLD_RATIO = 21 / 16; diff --git a/src/app/nwjns-powerpuffgirl/model/types.ts b/src/app/nwjns-powerpuffgirl/model/types.ts new file mode 100644 index 0000000..f6ab0a3 --- /dev/null +++ b/src/app/nwjns-powerpuffgirl/model/types.ts @@ -0,0 +1,140 @@ +import { RefObject, createRef } from "react"; +import { Coordinate, Vector } from "@/utils/physicalEngine"; +import { hoveringSequence } from "../utils/stream"; +import { ScreenType } from "@/utils/types"; + +export type NWJNSCharacter = { + name: string; + ref: RefObject; + physics: NWJNSPhysics; + // images: NWJNSImage; +}; + +// export type NWJNSImage = { +// fow1: StaticImageData; +// fow2: StaticImageData; +// fow3: StaticImageData; +// rev1: StaticImageData; +// rev2: StaticImageData; +// rev3: StaticImageData; +// }; + +export type NWJNSPhysics = { + DST: Coordinate; + HOVER: Vector; + HOVER_SEQ: Generator; +}; + +export type Offsets = { + stageWidth: number; + stageHeight: number; + charaSize: number; + screenType: ScreenType; +}; + +// export const haerinImages = { +// fow1: HaerinFow1, +// fow2: HaerinFow2, +// fow3: HaerinFow3, +// rev1: HaerinRev1, +// rev2: HaerinRev2, +// rev3: HaerinRev3, +// }; + +// export const danielleImages = { +// fow1: DanielleFow1, +// fow2: DanielleFow2, +// fow3: DanielleFow3, +// rev1: DanielleRev1, +// rev2: DanielleRev2, +// rev3: DanielleRev3, +// }; + +export const defaultCharacters: Array = [ + { + name: "minji", + ref: createRef(), + physics: { + DST: { X: 0, Y: 0 } as Coordinate, + HOVER: { vx: 0, vy: 0 } as Vector, + HOVER_SEQ: hoveringSequence(0), + }, + // images: { + // fow1: DanielleFow1, + // fow2: DanielleFow2, + // fow3: DanielleFow3, + // rev1: DanielleRev1, + // rev2: DanielleRev2, + // rev3: DanielleRev3, + // }, + }, + { + name: "hanni", + ref: createRef(), + physics: { + DST: { X: 0, Y: 0 } as Coordinate, + HOVER: { vx: 0, vy: 0 } as Vector, + HOVER_SEQ: hoveringSequence(1), + }, + // images: { + // fow1: DanielleFow1, + // fow2: DanielleFow2, + // fow3: DanielleFow3, + // rev1: DanielleRev1, + // rev2: DanielleRev2, + // rev3: DanielleRev3, + // }, + }, + + { + name: "danielle", + ref: createRef(), + physics: { + DST: { X: 0, Y: 0 } as Coordinate, + HOVER: { vx: 0, vy: 0 } as Vector, + HOVER_SEQ: hoveringSequence(2), + }, + // images: { + // fow1: DanielleFow1, + // fow2: DanielleFow2, + // fow3: DanielleFow3, + // rev1: DanielleRev1, + // rev2: DanielleRev2, + // rev3: DanielleRev3, + // }, + }, + { + name: "haerin", + ref: createRef(), + physics: { + DST: { X: 0, Y: 0 } as Coordinate, + HOVER: { vx: 0, vy: 0 } as Vector, + HOVER_SEQ: hoveringSequence(3), + }, + // images: { + // fow1: HaerinFow1, + // fow2: HaerinFow2, + // fow3: HaerinFow3, + // rev1: HaerinRev1, + // rev2: HaerinRev2, + // rev3: HaerinRev3, + // }, + }, + { + name: "hyein", + ref: createRef(), + physics: { + DST: { X: 0, Y: 0 } as Coordinate, + HOVER: { vx: 0, vy: 0 } as Vector, + HOVER_SEQ: hoveringSequence(4), + }, + // images: { + // fow1: DanielleFow1, + // fow2: DanielleFow2, + // fow3: DanielleFow3, + // rev1: DanielleRev1, + // rev2: DanielleRev2, + // rev3: DanielleRev3, + // }, + }, +]; diff --git a/src/app/nwjns-powerpuffgirl/nwjns.scss b/src/app/nwjns-powerpuffgirl/nwjns.scss new file mode 100644 index 0000000..d7cff44 --- /dev/null +++ b/src/app/nwjns-powerpuffgirl/nwjns.scss @@ -0,0 +1,135 @@ +.nwjns-screen { + position: fixed; + overflow: hidden; + width: 100%; + height: 100%; +} + +.nwjns-stage { + position: absolute; + top: 50%; + left: 50%; + backdrop-filter: blur(5px); + -webkit-backdrop-filter: blur(5px); + + // width: 100%; + // height: 100%; + + border-radius: 5px; + + background-color: rgba(0, 255, 255, 0.9); + + transform: translate(-50%, -50%); +} + +.nwjns-background-blur { + filter: blur(var(--blur)); + -webkit-filter: blur(var(--blur)); + backdrop-filter: blur(1px); + -webkit-backdrop-filter: blur(1px); + + background-color: rgba(174, 255, 0, 0.5); +} + +.nwjns-background-blur.top { + position: absolute; + top: 0px; + left: 50%; + + width: 100vw; + // height: 20vh; + + transform: translateX(-50%); +} +.nwjns-background-blur.bottom { + position: absolute; + bottom: 0px; + left: 50%; + + width: 100vw; + // height: 20vh; + + transform: translateX(-50%); +} +.nwjns-background-blur.left { + position: absolute; + left: 0px; + + // width: 40vw; + height: 100vh; +} +.nwjns-background-blur.right { + position: absolute; + right: 0px; + + // width: 40vw; + height: 100vh; +} + +.chara-div { + position: absolute; + + top: 50%; + left: -10%; + + width: var(--chara-size); + height: var(--chara-size); + + border-radius: 5vh; + border-width: 2px; + border-color: purple; + + transform: translate(-50%, -50%); +} + +.chara-div.haerin { + border-radius: 0px; + border-width: 0px; + + background-image: url("../../../public/assets/images/nwjns/haerin-sprite.png"); + background-repeat: no-repeat; + background-position: 0 0; + background-size: cover; +} +.chara-div.danielle { + border-radius: 0px; + border-width: 0px; + + background-image: url("../../../public/assets/images/nwjns/danielle-sprite.png"); + background-repeat: no-repeat; + background-position: 0 0; + background-size: cover; +} + +.temp { + position: absolute; + // z-index: 1; +} + +.reset { + position: absolute; + // z-index: 1; + + right: 0%; +} + +.nwjns-not-support { + position: fixed; + overflow: hidden; + display: none; + justify-content: center; + align-items: center; + z-index: 99; + + width: 100%; + height: 100%; + + backdrop-filter: blur(5px); + -webkit-backdrop-filter: blur(5px); + + color: white; + font-size: large; + text-align: center; + + background-color: rgba(0, 0, 0, 0.8); +} diff --git a/src/app/nwjns-powerpuffgirl/page.tsx b/src/app/nwjns-powerpuffgirl/page.tsx new file mode 100644 index 0000000..2e94f09 --- /dev/null +++ b/src/app/nwjns-powerpuffgirl/page.tsx @@ -0,0 +1,15 @@ +"use client"; + +import { Provider } from "react-redux"; +import { store } from "@/utils/redux/store"; +import Modal from "@/components/modal"; +import NWJNS_Powerpuffgirl from "./_app"; + +export default function App() { + return ( + + + + + ); +} diff --git a/src/app/nwjns-powerpuffgirl/utils/stream.ts b/src/app/nwjns-powerpuffgirl/utils/stream.ts new file mode 100644 index 0000000..effec50 --- /dev/null +++ b/src/app/nwjns-powerpuffgirl/utils/stream.ts @@ -0,0 +1,47 @@ +import { Coordinate, getBezierArray } from "@/utils/physicalEngine"; + +export function* hoveringSequence(index: number): Generator { + const seq: Array = [-1]; // 0 > -5 > 5 > 0 + for (let i = 1; i < 5; i++) { + seq.push(seq[seq.length - 1] - 1); + seq.push(seq[seq.length - 1]); + } + for (let i = 0; i < 2; i++) { + seq.push(seq[seq.length - 1]); + } + for (let i = 0; i < 10; i++) { + seq.push(seq[seq.length - 1] + 1); + seq.push(seq[seq.length - 1]); + } + for (let i = 0; i < 2; i++) { + seq.push(seq[seq.length - 1]); + } + for (let i = 0; i < 5; i++) { + seq.push(seq[seq.length - 1] - 1); + seq.push(seq[seq.length - 1]); + } + + if (1 <= index && index <= 3) { + for (let i = 0; i < 22; i++) { + yield 0; + } + } + + while (true) { + for (let v of seq) { + yield v; + } + } +} + +export function* moveSequence(start: Coordinate, end: Coordinate, frames: number): Generator { + const moveX = end.X - start.X; + const moveY = end.Y - start.Y; + const xRoute = getBezierArray(frames).map((v) => v * moveX + start.X); + const yRoute = getBezierArray(frames).map((v) => v * moveY + start.Y); + + for (let i = 0; i < frames - 1; i++) { + yield { X: xRoute[i], Y: yRoute[i] } as Coordinate; + } + return { X: xRoute[frames - 1], Y: yRoute[frames - 1] } as Coordinate; +} diff --git a/src/app/sandbox/_app.tsx b/src/app/sandbox/_app.tsx index 1fe2a45..6fae402 100644 --- a/src/app/sandbox/_app.tsx +++ b/src/app/sandbox/_app.tsx @@ -29,7 +29,6 @@ import { SandboxTutorial } from "./demonstrations"; import { GVT_SPEED_OFFSET, SPIN_SPEED_OFFSET, - FPS_OFFSET, UNDER_BOUND, TUTORIAL_INDEX, GRID_4_BY_2, @@ -41,6 +40,7 @@ import { charaSelector } from "@/utils/nwjnsCharacter"; import { modalOpen, modalSwitch, setChild } from "@/utils/redux/modalState"; import SandboxDescription from "./components/SandboxDescription"; import ToyDescription from "./components/ToyDescription"; +import { FPS_OFFSET } from "@/utils/constants"; export default function Sandbox() { // console.log("re-render!"); @@ -83,7 +83,7 @@ export default function Sandbox() { moveRef: createRef(), rotateRef: createRef(), physics: { ...defaultToyPhysics }, - link: "", + link: "/nwjns-powerpuffgirl", image: charaSelector(), }, { diff --git a/src/app/sandbox/components/ToyDescription.tsx b/src/app/sandbox/components/ToyDescription.tsx index 4cc5dc4..1f1ec5d 100644 --- a/src/app/sandbox/components/ToyDescription.tsx +++ b/src/app/sandbox/components/ToyDescription.tsx @@ -5,6 +5,8 @@ import Image, { StaticImageData } from "next/image"; import "./components.scss"; import Link from "next/link"; +import { useDispatch } from "react-redux"; +import { modalClose } from "@/utils/redux/modalState"; interface Props { name: string; @@ -28,6 +30,8 @@ const descriptions: ObjType = { }; export default function ToyDescription({ name, link, Img }: Props) { + const dispatch = useDispatch(); + const DescriptionImage = () => { return (
@@ -62,7 +66,15 @@ export default function ToyDescription({ name, link, Img }: Props) {

{name}

{descriptions[`${name}`]}

-

{name === "qr-code" ? `Take QR!` : {link !== "" ? "Visit" : "Preparing"}}

+

+ {name === "qr-code" ? ( + `Take QR!` + ) : ( + dispatch(modalClose())}> + {link !== "" ? "Visit" : "Preparing"} + + )} +

); diff --git a/src/app/sandbox/components/components.scss b/src/app/sandbox/components/components.scss index 5ff66ff..6f87247 100644 --- a/src/app/sandbox/components/components.scss +++ b/src/app/sandbox/components/components.scss @@ -106,6 +106,7 @@ h3 { color: gray; font-size: 2vh; + text-align: center; transition: 0.5s; transform: translate(-50%, 0%); @@ -123,6 +124,7 @@ h3 { .sandbox-tail { @extend .sandbox-text; bottom: 0%; + width: 90vw; } .sandbox-tail.on-grid { diff --git a/src/app/sandbox/demonstrations.ts b/src/app/sandbox/demonstrations.ts index e38d560..875dbd5 100644 --- a/src/app/sandbox/demonstrations.ts +++ b/src/app/sandbox/demonstrations.ts @@ -1,6 +1,6 @@ /* eslint-disable react-hooks/rules-of-hooks */ import { MutableRefObject, RefObject } from "react"; -import { useSleep } from "../../utils/hooks"; +import { sleep } from "../../utils/utilFunctions"; import { Toy, ToyPhysics } from "./model/types"; import { Coordinate } from "@/utils/physicalEngine"; import { SPIN_SPEED_OFFSET, TUTORIAL_INDEX } from "./model/constants"; @@ -36,18 +36,18 @@ export const SandboxTutorial = async ( spread(TUTORIAL_INDEX, false); - await useSleep(1500); + await sleep(1500); tutorialMessageRef.current.innerHTML = "HOLD"; - await useSleep(1500); + await sleep(1500); tutorialMessageRef.current.innerHTML = "THROW"; toyPhysics.V = { vx: Math.floor(Math.random() * 40) - 20, vy: -30 }; toyPhysics.dR = toyPhysics.V.vx * SPIN_SPEED_OFFSET; toyGravityDrop(TUTORIAL_INDEX); - await useSleep(2000); + await sleep(2000); tutorialMessageRef.current.innerHTML = "TRY IT"; toyPhysics.DST = dockerCoor; @@ -55,11 +55,11 @@ export const SandboxTutorial = async ( dockerRef.current.className = "sandbox-docker tutorial"; - await useSleep(3500); + await sleep(3500); spread(TUTORIAL_INDEX, true); - await useSleep(200); + await sleep(200); toyMoveRef.current.style.visibility = "hidden"; bgShadowRef.current.className = ""; diff --git a/src/app/sandbox/model/constants.ts b/src/app/sandbox/model/constants.ts index 8f2307c..8ccc3b4 100644 --- a/src/app/sandbox/model/constants.ts +++ b/src/app/sandbox/model/constants.ts @@ -1,6 +1,5 @@ export const GVT_SPEED_OFFSET: number = 0.1; export const SPIN_SPEED_OFFSET: number = 0.2; -export const FPS_OFFSET: number = 1000 / 60; // 60fps export const UNDER_BOUND: number = 0.8; export const GRID_2_BY_4 = { cols: 2, rows: 4 }; export const GRID_3_BY_3 = { cols: 3, rows: 3 }; diff --git a/src/components/components.scss b/src/components/components.scss index 7bbef6e..05b4d47 100644 --- a/src/components/components.scss +++ b/src/components/components.scss @@ -7,6 +7,8 @@ min-height: 100vh; min-height: -webkit-fill-available; + backdrop-filter: blur(1px); + opacity: 0; transition: 0.5s; diff --git a/src/utils/constants.ts b/src/utils/constants.ts new file mode 100644 index 0000000..2d94904 --- /dev/null +++ b/src/utils/constants.ts @@ -0,0 +1 @@ +export const FPS_OFFSET: number = 1000 / 60; // 60fps diff --git a/src/utils/hooks.ts b/src/utils/hooks.ts deleted file mode 100644 index 6366d0b..0000000 --- a/src/utils/hooks.ts +++ /dev/null @@ -1 +0,0 @@ -export const useSleep = (delay: number) => new Promise((resolve) => setTimeout(resolve, delay)); diff --git a/src/utils/nwjnsCharacter.ts b/src/utils/nwjnsCharacter.ts index 94ea007..cc44595 100644 --- a/src/utils/nwjnsCharacter.ts +++ b/src/utils/nwjnsCharacter.ts @@ -1,5 +1,8 @@ import { StaticImageData } from "next/image"; +import HaerinSprite from "/public/assets/images/nwjns/haerin-sprite.png"; +import DanielleSprite from "/public/assets/images/nwjns/danielle-sprite.png"; + import HaerinFow1 from "/public/assets/images/nwjns/haerin-fow-1.png"; import HaerinFow2 from "/public/assets/images/nwjns/haerin-fow-2.png"; import HaerinFow3 from "/public/assets/images/nwjns/haerin-fow-3.png"; @@ -20,4 +23,19 @@ export const charaSelector = (): StaticImageData => { return characters[Math.floor(Math.random() * characters.length)]; }; -export { HaerinRev2, HaerinRev3, DanielleRev2, DanielleRev3 }; +export { + HaerinSprite, + DanielleSprite, + HaerinFow1, + HaerinFow2, + HaerinFow3, + HaerinRev1, + HaerinRev2, + HaerinRev3, + DanielleFow1, + DanielleFow2, + DanielleFow3, + DanielleRev1, + DanielleRev2, + DanielleRev3, +}; diff --git a/src/utils/physicalEngine.ts b/src/utils/physicalEngine.ts index 9c69c56..c4392ae 100644 --- a/src/utils/physicalEngine.ts +++ b/src/utils/physicalEngine.ts @@ -1,18 +1,18 @@ -export interface Vector { +export type Vector = { vx: number; vy: number; -} +}; -export interface Coordinate { +export type Coordinate = { X: number; Y: number; -} +}; -export interface Circle { +export type Circle = { x: number; y: number; d: number; -} +}; export const lerp = (start: number, end: number, t: number): number => { return start * (1 - t) + end * t; @@ -60,3 +60,24 @@ export const reactionByCircleCollision = (data: Array, index: num return result; }; + +export const getBezierArray = (n: number): Array => { + const result: Array = []; + + const delay = 5; + n -= delay * 2; + + for (let i = 0; i < delay; i++) { + result.push(0); + } + for (let i = 1; i <= n; i++) { + const t = i / n; + + result.push(t * t * (3 - 2 * t)); + } + for (let i = 0; i < delay; i++) { + result.push(1); + } + + return result; +}; diff --git a/src/utils/types.ts b/src/utils/types.ts new file mode 100644 index 0000000..8bd04ba --- /dev/null +++ b/src/utils/types.ts @@ -0,0 +1,6 @@ +export enum ScreenType { + Normal = 0, + Vertical = 1, + Mobile = 2, + Tablet = 3, +} diff --git a/src/utils/utilFunctions.ts b/src/utils/utilFunctions.ts new file mode 100644 index 0000000..e603a0e --- /dev/null +++ b/src/utils/utilFunctions.ts @@ -0,0 +1,4 @@ +export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); +export const getWindowRatio = (): number => { + return window.innerWidth / window.innerHeight; +};