Skip to content

Commit

Permalink
feat: add tutorial
Browse files Browse the repository at this point in the history
  • Loading branch information
noyyyy committed Oct 21, 2024
1 parent 9cd1e1d commit 376ae49
Show file tree
Hide file tree
Showing 17 changed files with 7,516 additions and 5,457 deletions.
1 change: 1 addition & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"react-countup": "^6.5.3",
"react-dom": "^18.2.0",
"react-hotkeys-hook": "^4.5.0",
"react-joyride": "^2.9.2",
"react-spinners": "^0.14.1",
"rxjs": "^7.8.1",
"simplex-noise": "^4.0.1",
Expand Down
14 changes: 12 additions & 2 deletions packages/client/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { createJSONStorage, persist } from "zustand/middleware";
import { createStore } from "zustand/vanilla";
import { NetworkLayer } from "./dojo/createNetworkLayer";
import { PhaserLayer } from "./phaser";
import { num } from "starknet";
import { battle } from "./phaser/systems/battle";

export type Store = {
networkLayer: NetworkLayer | null;
Expand All @@ -29,6 +27,7 @@ export enum ShowItem {
SynergyDetail,
Setting,
GameOverDialog,
GuidePage,
}

export type Volume = {
Expand All @@ -42,13 +41,18 @@ export type UIStore = {
shows: Map<ShowItem, boolean>;
getShow: (i: ShowItem) => boolean;
setShow: (i: ShowItem, shouldShow: boolean) => void;
guideIndex: number;
guideRun: boolean;
setField: <K extends keyof UIStore>(field: K, value: UIStore[K]) => void;
};

export type PersistUIStore = {
loggedIn: boolean;
setLoggedIn: (loggedIn: boolean) => void;
agreeTerm: boolean;
setAgreeTerm: (agreeTerm: boolean) => void;
skipGuide: boolean;
setSkipGuide: (skipGuide: boolean) => void;
soundVolumes: Volume;
setVolume: (v: Partial<Volume>) => void;
};
Expand All @@ -65,6 +69,8 @@ export const persistUIStore = createStore(
setLoggedIn: (loggedIn: boolean) => set(() => ({ loggedIn })),
agreeTerm: false,
setAgreeTerm: (agreeTerm: boolean) => set(() => ({ agreeTerm })),
skipGuide: false,
setSkipGuide: (skipGuide: boolean) => set(() => ({ skipGuide })),
soundVolumes: { music: 100, effect: 100 },
setVolume: (v: Partial<Volume>) =>
set(({ soundVolumes }) => ({
Expand Down Expand Up @@ -95,4 +101,8 @@ export const useUIStore = create<UIStore>()((set, get) => ({
return { shows: newMap };
});
},
guideRun: false,
guideIndex: 0,
setField: <K extends keyof UIStore>(field: K, value: UIStore[K]) =>
set({ [field]: value }),
}));
4 changes: 4 additions & 0 deletions packages/client/src/ui/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import { useCheckNetworkHealth } from "./hooks/useCheckNetworkHealth";
import { useEscCloseDialog } from "./hooks/useEscCloseDialog";
import { GameOverDialog } from "./features/gameover/GameOverDialog";
import { useControlGameEnd } from "./hooks/useControlGameEnd";
import { Guide } from "./features/guide/Guide";
import { GuidePage } from "./features/guide/GuidePage";

export function Main() {
const {
Expand All @@ -57,6 +59,7 @@ export function Main() {
}}
className="relative w-screen h-screen overflow-hidden select-none"
>
<GuidePage />
<TopBar />
<Debugger />
<PlayerList />
Expand All @@ -82,6 +85,7 @@ export function Main() {
<OptionMenu />
<Setting />
<GameOverDialog />
<Guide />
</div>
);
}
2 changes: 1 addition & 1 deletion packages/client/src/ui/components/CommitButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function CommitOperationButton({
}) {
return (
<button
className={`absolute left-1/2 transform -translate-x-1/2 top-[calc(13%+40rem)] bg-[url(/assets/ui/commit_btn.png)] pixelated bg-contain bg-no-repeat flex justify-center mt-0.5 ${visible} select-none w-60 h-10 font-dogica text-xs z-10`}
className={`guide-step-4 absolute left-1/2 transform -translate-x-1/2 top-[calc(13%+40rem)] bg-[url(/assets/ui/commit_btn.png)] pixelated bg-contain bg-no-repeat flex justify-center mt-0.5 ${visible} select-none w-60 h-10 font-dogica text-xs z-10`}
onClick={onClick}
>
<div className="self-center text-black">{text}</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/ui/features/board/PieceLimit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function PieceLimit() {

return (
<div
className={`relative flex justify-center -mt-[7.25rem] ${visible} select-none pointer-events-none z-10`}
className={`guide-step-6 absolute flex justify-center top-[26rem] left-1/2 -translate-x-1/2 ${visible} select-none pointer-events-none z-20 `}
>
<div className=" w-80 h-10 text-white/50 text-lg rounded-lg flex flex-col justify-center">
<div className="self-center text-[#F2A316] text-sm">
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/ui/features/exp/ExpButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function ExpButton() {
const { percentage, exp, level, expForNext } = usePlayerExpProgress();

return (
<div className="absolute flex flex-col left-20 bottom-[4%] select-none z-20">
<div className="guide-step-5 absolute flex flex-col left-20 bottom-[4%] select-none z-20">
<div className="mb-1 self-center text-sm font-bold transition-all">
EXP : <CountUp end={exp || 0} preserveValue={true} /> /
{expForNext}
Expand Down
230 changes: 230 additions & 0 deletions packages/client/src/ui/features/guide/Guide.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import Joyride, { Step } from "react-joyride";
import { useUIStore } from "../../../store";
import { logDebug } from "../../lib/utils";
import { getComponentValueStrict, updateComponent } from "@dojoengine/recs";
import { useDojo } from "../../hooks/useDojo";
import { zeroEntity } from "../../../utils";
import { useState } from "react";

export function Guide() {
const { setField, guideIndex, guideRun } = useUIStore();
const {
clientComponents: { GameStatus },
} = useDojo();
const [rightRound, setRightRound] = useState(1);
const [rightDanger, setRightDanger] = useState(false);
const steps: Step[] = [
{
target: ".guide-step-1",
content: (
<div className="text-sm">
Open the shop and buy a chess piece (beast).
</div>
),
disableBeacon: true,
// hideFooter: true,
disableOverlayClose: true,
spotlightClicks: true,
hideFooter: true,

styles: { buttonNext: { visibility: "hidden" } },
},
{
target: ".guide-step-2",
content: (
<div className="text-sm">
The "Traits" of the chess piece are displayed on it. Buy
chess pieces with the same "Traits" to unleash their more
powerful abilities. Click to buy.se a chess piece.
</div>
),
disableBeacon: true,
hideFooter: false,
disableOverlayClose: true,
spotlightClicks: true,
spotlightPadding: 10,
styles: {},
},
{
target: ".guide-step-3",
content: (
<div className="w-[33rem] text-sm">
Drag the chess pieces to the battlefield. You can adjust
their positions at any time before the battle begins.
</div>
),
disableBeacon: true,
hideFooter: false,
hideBackButton: true,
disableOverlayClose: true,
spotlightClicks: true,
spotlightPadding: 10,
},
{
target: ".guide-step-4",
content: <div className="text-sm">Click to start the battle</div>,
disableBeacon: true,
hideFooter: false,
hideBackButton: true,

disableOverlayClose: true,
spotlightClicks: true,
spotlightPadding: 10,
},
{
target: ".guide-step-5",
content: (
<div className="text-sm">
Consume 4 gold coins to buy experience points, and your
level will increase.
</div>
),
disableBeacon: true,
hideFooter: false,
disableOverlayClose: true,
spotlightClicks: true,
spotlightPadding: 10,
},
{
target: ".guide-step-6",
content: (
<div className="text-sm">
Due to the increase in level, you can deploy one more chess
piece on the field.
</div>
),
disableBeacon: true,
hideFooter: false,
disableOverlayClose: true,
spotlightClicks: true,
spotlightPadding: 10,
},

{
target: ".guide-step-7",
content: (
<div className="text-sm w-[40rem]">
Curse: Players will receive 10 Curse value at the beginning
of the 4 round. This value will affect how much Danger value
you get at the beginning of each round. <br />
<br /> Curse value = Danger value added at the start of each
round.
</div>
),
disableBeacon: true,
hideFooter: false,
disableOverlayClose: true,
spotlightClicks: true,
spotlightPadding: 10,
},

{
target: ".guide-step-8",
content: (
<div className="text-sm w-[40rem]">
Starting from Round 4, players will gain a Danger value
equal to the Curse value at the beginning of each round.
When the Danger value reaches 100, the Level(Round) will
mutate to Danger.
</div>
),
disableBeacon: true,
hideFooter: false,
disableOverlayClose: true,
spotlightClicks: true,
spotlightPadding: 10,
},

{
target: ".guide-step-9",
content: (
<div className="text-sm w-[40rem]">
Dangerous Stage: Higher difficulty, richer rewards.
</div>
),
disableBeacon: true,
hideFooter: false,
disableOverlayClose: true,
spotlightClicks: true,
spotlightPadding: 10,
},
];

return (
<div>
<Joyride
run={guideRun}
callback={(data) => {
const { lifecycle, index } = data;

if (index === 5 && lifecycle === "complete") {
const s = getComponentValueStrict(
GameStatus,
zeroEntity
);
updateComponent(GameStatus, zeroEntity, {
currentRound: Math.max(5, s.currentRound),
});
setRightRound(s.currentRound);
}

if (index === 7 && lifecycle === "complete") {
const s = getComponentValueStrict(
GameStatus,
zeroEntity
);
if (!s.dangerous) {
updateComponent(GameStatus, zeroEntity, {
dangerous: true,
});
setRightDanger(false);
}
}

if (
[1, 2, 3, 4, 5, 6, 7].indexOf(index) !== -1 &&
lifecycle === "complete"
) {
setField("guideIndex", guideIndex + 1);
}
if (index === steps.length - 1 && lifecycle == "complete") {
logDebug("Guide ended");
setField("guideRun", false);
updateComponent(GameStatus, zeroEntity, {
currentRound: rightRound,
dangerous: rightDanger,
});
}
}}
continuous
disableCloseOnEsc={true}
disableOverlayClose={true}
spotlightClicks={true}
hideCloseButton={true}
showProgress
steps={steps}
stepIndex={guideIndex}
hideBackButton
styles={{
options: {
arrowColor: "white",
backgroundColor: "transparent",
textColor: "white",
beaconSize: 14,
overlayColor: "rgba(0, 0, 0, 0.5)",
},
// tooltip: {
// border: "4px solid white",
// borderRadius: "0px",
// },
spotlight: {
border: "4px solid white",
boxShadow: "0 0 0 9999px rgba(0, 0, 0, 0.5)",
},
tooltipFooter: { backgroundColor: "transparent" },
buttonNext: { backgroundColor: "#03FF00", color: "black" },
}}
/>
</div>
);
}
43 changes: 43 additions & 0 deletions packages/client/src/ui/features/guide/GuidePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { ShowItem, usePersistUIStore, useUIStore } from "../../../store";
import { Dialog } from "../../components/Dialog";
import { GreenButton } from "../../components/GreenButton";
import { HomeBg } from "../../components/HomeBg";

export function GuidePage() {
const show = useUIStore((state) => state.getShow(ShowItem.GuidePage));
const setShow = useUIStore((state) => state.setShow);
const { setField } = useUIStore();

const { setSkipGuide } = usePersistUIStore((state) => state);

if (!show) {
return null;
}

return (
<HomeBg className="z-50">
<Dialog className="flex ">
<div className="text-3xl font-bold mt-24">Guide</div>
<div className="flex flex-col space-y-12 mt-12">
<GreenButton
onClick={() => {
setField("guideRun", true);
setField("guideIndex", 0);
setShow(ShowItem.GuidePage, false);
}}
>
Yes, I am a beginner
</GreenButton>
<GreenButton
onClick={() => {
setShow(ShowItem.GuidePage, false);
setSkipGuide(true);
}}
>
I'm experienced
</GreenButton>
</div>
</Dialog>
</HomeBg>
);
}
1 change: 1 addition & 0 deletions packages/client/src/ui/features/info/QuitConfirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function QuitConfirmation() {
onClick={() => {
exit(account).then(() => {
setShow(ShowItem.QuitConfirmation, false);
location.reload();
});
}}
>
Expand Down
Loading

0 comments on commit 376ae49

Please sign in to comment.