diff --git a/public/fonts/ibm-plex-sans-v19-latin-100.woff2 b/public/fonts/ibm-plex-sans-v19-latin-100.woff2 new file mode 100755 index 0000000..bbe5a8b Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-100.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-100italic.woff2 b/public/fonts/ibm-plex-sans-v19-latin-100italic.woff2 new file mode 100755 index 0000000..075d1c8 Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-100italic.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-200.woff2 b/public/fonts/ibm-plex-sans-v19-latin-200.woff2 new file mode 100755 index 0000000..13e9069 Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-200.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-200italic.woff2 b/public/fonts/ibm-plex-sans-v19-latin-200italic.woff2 new file mode 100755 index 0000000..0947013 Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-200italic.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-300.woff2 b/public/fonts/ibm-plex-sans-v19-latin-300.woff2 new file mode 100755 index 0000000..8737b6b Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-300.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-300italic.woff2 b/public/fonts/ibm-plex-sans-v19-latin-300italic.woff2 new file mode 100755 index 0000000..a5f9f4c Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-300italic.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-500.woff2 b/public/fonts/ibm-plex-sans-v19-latin-500.woff2 new file mode 100755 index 0000000..adbbd4c Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-500.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-500italic.woff2 b/public/fonts/ibm-plex-sans-v19-latin-500italic.woff2 new file mode 100755 index 0000000..6d6a9b1 Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-500italic.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-600.woff2 b/public/fonts/ibm-plex-sans-v19-latin-600.woff2 new file mode 100755 index 0000000..0ac91d6 Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-600.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-600italic.woff2 b/public/fonts/ibm-plex-sans-v19-latin-600italic.woff2 new file mode 100755 index 0000000..c71f94c Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-600italic.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-700.woff2 b/public/fonts/ibm-plex-sans-v19-latin-700.woff2 new file mode 100755 index 0000000..da7d57f Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-700.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-700italic.woff2 b/public/fonts/ibm-plex-sans-v19-latin-700italic.woff2 new file mode 100755 index 0000000..9cd1838 Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-700italic.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-italic.woff2 b/public/fonts/ibm-plex-sans-v19-latin-italic.woff2 new file mode 100755 index 0000000..eea1618 Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-italic.woff2 differ diff --git a/public/fonts/ibm-plex-sans-v19-latin-regular.woff2 b/public/fonts/ibm-plex-sans-v19-latin-regular.woff2 new file mode 100755 index 0000000..93bcd64 Binary files /dev/null and b/public/fonts/ibm-plex-sans-v19-latin-regular.woff2 differ diff --git a/src/assets/fonts.css b/src/assets/fonts.css new file mode 100644 index 0000000..06cbeaa --- /dev/null +++ b/src/assets/fonts.css @@ -0,0 +1,112 @@ +/* ibm-plex-sans-100 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: normal; + font-weight: 100; + src: url('/fonts/ibm-plex-sans-v19-latin-100.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-100italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: italic; + font-weight: 100; + src: url('/fonts/ibm-plex-sans-v19-latin-100italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-200 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: normal; + font-weight: 200; + src: url('/fonts/ibm-plex-sans-v19-latin-200.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-200italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: italic; + font-weight: 200; + src: url('/fonts/ibm-plex-sans-v19-latin-200italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-300 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: normal; + font-weight: 300; + src: url('/fonts/ibm-plex-sans-v19-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-300italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: italic; + font-weight: 300; + src: url('/fonts/ibm-plex-sans-v19-latin-300italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-regular - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: normal; + font-weight: 400; + src: url('/fonts/ibm-plex-sans-v19-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: italic; + font-weight: 400; + src: url('/fonts/ibm-plex-sans-v19-latin-italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-500 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: normal; + font-weight: 500; + src: url('/fonts/ibm-plex-sans-v19-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-500italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: italic; + font-weight: 500; + src: url('/fonts/ibm-plex-sans-v19-latin-500italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-600 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: normal; + font-weight: 600; + src: url('/fonts/ibm-plex-sans-v19-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-600italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: italic; + font-weight: 600; + src: url('/fonts/ibm-plex-sans-v19-latin-600italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-700 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: normal; + font-weight: 700; + src: url('/fonts/ibm-plex-sans-v19-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* ibm-plex-sans-700italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: 'IBM Plex Sans'; + font-style: italic; + font-weight: 700; + src: url('/fonts/ibm-plex-sans-v19-latin-700italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} \ No newline at end of file diff --git a/src/index.css b/src/index.css index 58e236c..0319206 100644 --- a/src/index.css +++ b/src/index.css @@ -4,4 +4,8 @@ :root { --color-primary: #49509e; +} + +html, body { + font-family: 'IBM Plex Sans', sans; } \ No newline at end of file diff --git a/src/root.tsx b/src/root.tsx index f54496c..eaa546e 100644 --- a/src/root.tsx +++ b/src/root.tsx @@ -1,5 +1,6 @@ import Stage from "./stage"; +import "./assets/fonts.css"; import "./index.css"; export default function Root() { diff --git a/src/stage/index.tsx b/src/stage/index.tsx index 101725e..dedd652 100644 --- a/src/stage/index.tsx +++ b/src/stage/index.tsx @@ -9,6 +9,10 @@ import TimerProvider from "./providers/timer"; import CooldownProvider from "./providers/cooldown"; import CooldownUI from "./ui/cooldown"; +import "./objects/common.css"; +import OverviewProvider from "./providers/overview"; +import OverviewUI from "./ui/overview"; + const StageContainer = styled("div")` width: 100vw; height: 100vh; @@ -55,20 +59,23 @@ export default function Stage() { return ( - - - - {/* Objects */} - - + + + + + {/* Objects */} + + - + - {/* UI Elements */} - - - - + {/* UI Elements */} + + + + + + ); } diff --git a/src/stage/objects/common.css b/src/stage/objects/common.css new file mode 100644 index 0000000..12d66fc --- /dev/null +++ b/src/stage/objects/common.css @@ -0,0 +1,7 @@ +svg { + opacity: 1; +} + +svg[data-dispose=yes] { + opacity: 0; +} \ No newline at end of file diff --git a/src/stage/objects/crystal.tsx b/src/stage/objects/crystal.tsx index 586fa2e..78e1d07 100644 --- a/src/stage/objects/crystal.tsx +++ b/src/stage/objects/crystal.tsx @@ -3,6 +3,7 @@ import { vector2d } from "../vector"; import { createMemo, createSignal } from "solid-js"; import { useTimer } from "../providers/timer"; import { checkElementOverlap } from "./collision"; +import { useOverview } from "../providers/overview"; import "./crystal.css"; @@ -20,6 +21,8 @@ export default function Crystal(props: { size?: number; position?: vector2d }) { // Health + const [_, { set }] = useOverview(); + const [health, setHealth] = createSignal(100); const [maxHealth, setMaxHealth] = createSignal(100); @@ -28,30 +31,32 @@ export default function Crystal(props: { size?: number; position?: vector2d }) { const isAlive = createMemo(() => health() > 0); function calcHostileCauseDamage() { - const units = document.querySelectorAll(".hostile"); + const units = document.querySelectorAll( + ".hostile:not([data-dispose=yes])" + ); const crystal = document.querySelector(".crystal"); let damage = 0; for (const unit of units) { if (crystal && checkElementOverlap(crystal, unit)) { damage += parseInt(unit.getAttribute("data-damage") ?? "0"); - unit.setAttribute("data-need-dispose", "yes"); + unit.setAttribute("data-dispose", "yes"); } } return damage; } function dealHostileUnderCrystal() { - const units = document.querySelectorAll( - ".attackers[data-need-dispose=yes]" - ); - units.forEach((unit) => unit.remove()); + const units = document.querySelectorAll(".attackers[data-dispose=yes]"); + // Delay 175ms to remove that node cuz animation is 150ms plus 25ms for browser rerender gap + units.forEach((unit) => setTimeout(() => unit.remove(), 175)); } function updateHealth() { const damage = calcHostileCauseDamage(); if (damage && isAlive()) { setHealth(health() - damage); + set("crystal.health", health()); console.log("health: ", health()); } dealHostileUnderCrystal(); diff --git a/src/stage/objects/enemies/attacker.tsx b/src/stage/objects/enemies/attacker.tsx index 7307bfd..d758260 100644 --- a/src/stage/objects/enemies/attacker.tsx +++ b/src/stage/objects/enemies/attacker.tsx @@ -99,7 +99,7 @@ export default function Attacker(props: { transform: rotate(${facingAngle}deg); - transition-property: transform; + transition-property: transform, opacity; transition-timing-function: linear; transition-duration: 150ms; diff --git a/src/stage/providers/overview.tsx b/src/stage/providers/overview.tsx new file mode 100644 index 0000000..d0713d3 --- /dev/null +++ b/src/stage/providers/overview.tsx @@ -0,0 +1,36 @@ +import { createContext, createSignal, useContext } from "solid-js"; + +const OverviewContext = createContext(); + +export default function OverviewProvider(props: any) { + const [stats, setStats] = createSignal<{ [id: string]: any }>({ + "crystal.health": 100, + "crystal.maxHealth": 100, + }); + + const store = [ + stats, + { + set(id: string, value: any) { + const original = structuredClone(stats()); + original[id] = value; + setStats(original); + }, + unset(id: string) { + const original = structuredClone(stats()); + delete original[id]; + setStats(original); + }, + }, + ]; + + return ( + + {props.children} + + ); +} + +export function useOverview(): any[2] { + return useContext(OverviewContext); +} diff --git a/src/stage/ui/overview.tsx b/src/stage/ui/overview.tsx new file mode 100644 index 0000000..e90fa15 --- /dev/null +++ b/src/stage/ui/overview.tsx @@ -0,0 +1,34 @@ +import { styled } from "solid-styled-components"; +import { useOverview } from "../providers/overview"; +import { createMemo } from "solid-js"; + +export default function OverviewUI() { + const [overview] = useOverview(); + + const crystalHealth = createMemo(() => overview()["crystal.health"]); + const crystalMaxHealth = createMemo(() => overview()["crystal.maxHealth"]); + const regenerationProgress = createMemo( + () => (crystalHealth() / crystalMaxHealth()) * 100 + ); + + const BottomSideContainer = styled("div")` + text-align: center; + position: absolute; + display: flex; + flex-direction: column; + gap: 10px; + + width: 100vw; + bottom: 0; + left: 0; + `; + + return ( + <> + + Crystal {crystalHealth()}/{crystalMaxHealth()} + + + > + ); +}