Skip to content

Commit

Permalink
Animate menu
Browse files Browse the repository at this point in the history
  • Loading branch information
Half-Shot committed Dec 11, 2024
1 parent 2ac2443 commit d5848eb
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 53 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@dimforge/rapier2d-compat": "^0.14.0",
"@pixi/sound": "^6.0.1",
"matrix-js-sdk": "^34.8.0",
"motion": "^11.13.5",
"pixi-viewport": "^5.0.3",
"pixi.js": "^8.5.1",
"preact": "^10.24.3",
Expand Down
14 changes: 14 additions & 0 deletions src/components/gameui/weapon-select.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,19 @@
margin-top: 1em;
width: 16px;
}

&:hover,
&.selected {
background: rgba(63, 55, 55, 0.8);
}
}
}

.weaponText {
text-align: center;
left: 50%;
position: relative;
top: 50%;
transform-origin: 50% 50%;
transform: translate(-50%, -50%);
}
91 changes: 64 additions & 27 deletions src/components/gameui/weapon-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,76 @@ import { FunctionalComponent } from "preact";
import { IWeaponCode, IWeaponDefiniton } from "../../weapons/weapon";
import styles from "./weapon-select.module.css";
import { pointOnRadius } from "../../utils";
import { motion } from "motion/react";
import { useEffect, useState } from "preact/hooks";

export const WeaponSelector: FunctionalComponent<{
weapons: IWeaponDefiniton[];
weapons: IWeaponDefiniton[] | null;
onWeaponPicked: (code: IWeaponCode) => void;
}> = ({ weapons, onWeaponPicked }) => {
const radiansPerItem = (2 * Math.PI) / weapons.length;
const visible = !!weapons;

const [selectedWeapon, setSelectedWeapon] = useState<number>(-1);
const [weaponSet, setWeaponSet] = useState<IWeaponDefiniton[]>([]);
useEffect(() => {
if (weapons) {
setSelectedWeapon(-1);
setWeaponSet(weapons);
}
}, [weapons]);

const radiansPerItem = weaponSet.length
? (2 * Math.PI) / weaponSet.length
: 0;
// No animation initally.
return (
<div className={styles.root}>
<ul>
{weapons.map((weapon, i) => {
const point = pointOnRadius(-250, 250, radiansPerItem * i, 250);
return (
<li
className={styles.weaponOption}
style={{ top: -point.x, left: point.y }}
key={weapon.code}
>
<button
onClick={() => {
onWeaponPicked(weapon.code);
}}
<motion.div
transition={{
duration: (weapons?.length ?? 0) + weaponSet.length ? 0.075 : 0,
delay: 0,
ease: "linear",
}}
animate={{ opacity: visible ? 1 : 0 }}
exit={{ opacity: 0 }}
>
<div
className={styles.root}
onMouseLeave={() => {
setSelectedWeapon(-1);
}}
>
<ul>
{weaponSet.map((weapon, i) => {
const point = pointOnRadius(-250, 250, radiansPerItem * i, 250);
return (
<li
className={styles.weaponOption}
style={{ top: -point.x, left: point.y }}
key={i}
>
{weapon.name}
<img
src={weapon.icon}
style={{ width: `${weapon.iconWidth}px` }}
></img>
</button>
</li>
);
})}
</ul>
</div>
<button
onClick={() => {
setSelectedWeapon(i);
onWeaponPicked(weapon.code);
}}
onMouseOver={() => {
setSelectedWeapon(i);
}}
className={selectedWeapon === i ? styles.selected : ""}
>
<img
src={weapon.icon}
style={{ width: `${weapon.iconWidth}px` }}
></img>
</button>
</li>
);
})}
<p className={styles.weaponText}>
{weaponSet[selectedWeapon]?.name || "Select a weapon"}
</p>
</ul>
</div>
</motion.div>
);
};
16 changes: 7 additions & 9 deletions src/components/ingame-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,13 @@ export function IngameView({
return (
<>
<div id="overlay" className={styles.overlay}>
{weaponMenu && (
<WeaponSelector
weapons={weaponMenu}
onWeaponPicked={(code) => {
gameReactChannel.weaponMenuSelect(code);
setWeaponMenu(null);
}}
/>
)}
<WeaponSelector
weapons={weaponMenu}
onWeaponPicked={(code) => {
gameReactChannel.weaponMenuSelect(code);
setWeaponMenu(null);
}}
/>
</div>
<div ref={ref} />
</>
Expand Down
32 changes: 16 additions & 16 deletions src/components/menus/overlaytest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@ import { useState } from "preact/hooks";
import { WeaponSelector } from "../gameui/weapon-select";
import { WeaponBazooka, WeaponGrenade, WeaponShotgun } from "../../weapons";

const wepList = [
WeaponBazooka,
WeaponGrenade,
WeaponShotgun,
WeaponGrenade,
WeaponShotgun,
WeaponGrenade,
WeaponShotgun,
];

export const OverlayTest: FunctionalComponent = () => {
const [weaponMenuOpen, setWeaponMenuOpen] = useState(false);
const [weaponMenu, setWeaponMenu] = useState<typeof wepList | null>(null);
return (
<main>
<button onClick={() => setWeaponMenuOpen(true)}>Open Weapon Menu</button>
{weaponMenuOpen && (
<WeaponSelector
weapons={[
WeaponBazooka,
WeaponGrenade,
WeaponShotgun,
WeaponGrenade,
WeaponShotgun,
WeaponGrenade,
WeaponShotgun,
]}
onWeaponPicked={() => setWeaponMenuOpen(false)}
/>
)}
<button onClick={() => setWeaponMenu(wepList)}>Open Weapon Menu</button>
<WeaponSelector
weapons={weaponMenu}
onWeaponPicked={() => setWeaponMenu(null)}
/>
</main>
);
};
3 changes: 3 additions & 0 deletions src/scenarios/testingGround.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ export default async function runScenario(game: Game) {
});
weaponText.position.set(20, 50);
staticController.on("inputEnd", (kind: InputKind) => {
if (currentWorm?.currentState !== WormState.Idle) {
return;
}
if (kind === InputKind.WeaponMenu) {
game.gameReactChannel.openWeaponMenu(weapons);
}
Expand Down
29 changes: 28 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2222,6 +2222,15 @@ flatted@^3.2.9:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==

framer-motion@^11.13.5:
version "11.13.5"
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-11.13.5.tgz#2cec307d2395ba6924a683abd79a517ec1f318f5"
integrity sha512-rArI0zPU9VkpS3Wt0J7dmRxAFUWtzPWoSofNQAP0UO276CmJ+Xlf5xN19GMw3w2QsdrS2sU+0+Q2vtuz4IEZaw==
dependencies:
motion-dom "^11.13.0"
motion-utils "^11.13.0"
tslib "^2.4.0"

fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
Expand Down Expand Up @@ -3094,6 +3103,24 @@ minimatch@^9.0.4:
dependencies:
brace-expansion "^2.0.1"

motion-dom@^11.13.0:
version "11.13.0"
resolved "https://registry.yarnpkg.com/motion-dom/-/motion-dom-11.13.0.tgz#a8f86b3aedb55598a8e3dd4114f1c3347153baf2"
integrity sha512-Oc1MLGJQ6nrvXccXA89lXtOqFyBmvHtaDcTRGT66o8Czl7nuA8BeHAd9MQV1pQKX0d2RHFBFaw5g3k23hQJt0w==

motion-utils@^11.13.0:
version "11.13.0"
resolved "https://registry.yarnpkg.com/motion-utils/-/motion-utils-11.13.0.tgz#e65fab5e26a1da3b18b4b4d1f3d0067977ccfd4a"
integrity sha512-lq6TzXkH5c/ysJQBxgLXgM01qwBH1b4goTPh57VvZWJbVJZF/0SB31UWEn4EIqbVPf3au88n2rvK17SpDTja1A==

motion@^11.13.5:
version "11.13.5"
resolved "https://registry.yarnpkg.com/motion/-/motion-11.13.5.tgz#607edfda672f16c0eb306f4879f5b10d4acea8dc"
integrity sha512-zmX/dz60w1ZtQB5NP9xYkLcCKwX9gc+pnHp4/mFhD9YW8wUe2ZmT8OPOtrTtq26/huxElSDu3hB7BMTSJa5iIQ==
dependencies:
framer-motion "^11.13.5"
tslib "^2.4.0"

[email protected]:
version "2.1.2"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
Expand Down Expand Up @@ -3663,7 +3690,7 @@ ts-jest@^29.2.5:
semver "^7.6.3"
yargs-parser "^21.1.1"

tslib@^2.1.0:
tslib@^2.1.0, tslib@^2.4.0:
version "2.8.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
Expand Down

0 comments on commit d5848eb

Please sign in to comment.