Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animations #213

Merged
merged 75 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
5776aac
wip
supreme2580 Dec 21, 2024
bd83f40
wip
supreme2580 Dec 21, 2024
940ecc1
wip
supreme2580 Dec 21, 2024
11577d1
wip
supreme2580 Dec 21, 2024
fddeb85
wip
supreme2580 Dec 21, 2024
f0b7732
wip
supreme2580 Dec 21, 2024
64ee0d9
wip
supreme2580 Dec 21, 2024
ee52083
wip
supreme2580 Dec 21, 2024
4a7d3d5
wip
supreme2580 Dec 21, 2024
bc0f8f7
wip
supreme2580 Dec 21, 2024
9e99538
wip
supreme2580 Dec 21, 2024
5ec5023
wip
supreme2580 Dec 21, 2024
fa315df
wip
supreme2580 Dec 21, 2024
0804974
wip
supreme2580 Dec 21, 2024
15b5ca0
wip
supreme2580 Dec 21, 2024
9c911d0
WIP
supreme2580 Dec 21, 2024
5c45205
merged with develop
supreme2580 Dec 21, 2024
60170e3
fix contracts
supreme2580 Dec 21, 2024
7669780
Merge branch 'fix-contracts' into animations
supreme2580 Dec 22, 2024
a282743
update
supreme2580 Dec 22, 2024
8790ffc
update
supreme2580 Dec 22, 2024
ab1a966
merged with develop
supreme2580 Dec 24, 2024
d6b148f
t to dev issue fix
supreme2580 Dec 24, 2024
a2af649
rign in progress
supreme2580 Dec 24, 2024
2b47df7
rign in progress
supreme2580 Dec 24, 2024
0daa328
rign in progress
supreme2580 Dec 24, 2024
88c2890
side seeds in progress
supreme2580 Dec 24, 2024
fae8991
side seeds in progress
supreme2580 Dec 24, 2024
05b3b20
side seeds in progress
supreme2580 Dec 24, 2024
11c8087
side seeds in progress
supreme2580 Dec 24, 2024
f99ea5b
side seeds in progress
supreme2580 Dec 24, 2024
1fe5540
side seeds in progress
supreme2580 Dec 24, 2024
5f6ba1f
side seeds in progress
supreme2580 Dec 24, 2024
f9342a9
side seeds in progress
supreme2580 Dec 24, 2024
e52b9c0
updated scores
supreme2580 Dec 24, 2024
0ca124c
fixed score board
supreme2580 Dec 24, 2024
637b25d
added extra checks
supreme2580 Dec 24, 2024
5880086
fixed spectate
supreme2580 Dec 24, 2024
39ce2a5
removed seeds numbering
supreme2580 Dec 25, 2024
d50cab8
removed seeds numbering
supreme2580 Dec 25, 2024
7a7fea5
code cleanup
supreme2580 Dec 25, 2024
7cb9f36
prettier
supreme2580 Dec 25, 2024
978e130
wip
supreme2580 Dec 28, 2024
8329ab9
wip
supreme2580 Dec 28, 2024
45efc29
wip
supreme2580 Dec 28, 2024
2d28f70
wip
supreme2580 Dec 28, 2024
c1db6d0
sequentially animate seeds
supreme2580 Dec 28, 2024
4ee2fec
removed cursor pointer from top pit
supreme2580 Dec 28, 2024
aa95285
wip
supreme2580 Dec 28, 2024
aeb013e
animations done
supreme2580 Dec 28, 2024
05cef24
wip
supreme2580 Dec 29, 2024
f0956ec
wip
supreme2580 Dec 29, 2024
53409f9
wip
supreme2580 Dec 29, 2024
7567e41
curved wip
supreme2580 Dec 29, 2024
037692b
wip
supreme2580 Dec 29, 2024
51615d2
wip
supreme2580 Dec 29, 2024
f80b6dd
wip
supreme2580 Dec 29, 2024
de92c48
wip
supreme2580 Dec 29, 2024
3ff7f44
wip
supreme2580 Dec 29, 2024
16693a2
wip
supreme2580 Dec 29, 2024
91996aa
wip
supreme2580 Dec 29, 2024
6236623
wip
supreme2580 Dec 29, 2024
bc68b64
wip
supreme2580 Dec 29, 2024
4a9fe62
wip
supreme2580 Dec 29, 2024
ea35377
wip
supreme2580 Dec 29, 2024
9c4163a
save positions
supreme2580 Dec 29, 2024
2161b1f
wip
supreme2580 Dec 29, 2024
141b321
wip
supreme2580 Dec 29, 2024
ede6401
wip
supreme2580 Dec 30, 2024
1b7e9f3
wip
supreme2580 Dec 30, 2024
c4e0f8c
wip
supreme2580 Dec 30, 2024
d411670
wip
supreme2580 Dec 30, 2024
9415c0f
moved scores
supreme2580 Dec 30, 2024
3b516b2
fixed catridge controller
supreme2580 Dec 30, 2024
c346e26
fix: added validation for last pit player
okhaimie-dev Jan 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
},
"dependencies": {
"@apollo/client": "^3.11.4",
"@cartridge/connector": "^0.5.6",
"@cartridge/controller": "^0.5.6",
"@cartridge/connector": "^0.5.7",
"@cartridge/controller": "^0.5.7",
"@dojoengine/core": "1.0.4-alpha.3.1.2",
"@dojoengine/create-burner": "1.0.4-alpha.3.1.2",
"@dojoengine/react": "1.0.4-alpha.3.1.2",
Expand Down
4 changes: 2 additions & 2 deletions client/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 9 additions & 9 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import ControllerConnector from "@cartridge/connector/controller";
import { ControllerOptions } from "@cartridge/controller";
import { Chain, sepolia } from "@starknet-react/chains";
import { sepolia } from "@starknet-react/chains";
import {
Connector,
StarknetConfig,
jsonRpcProvider,
voyager,
} from "@starknet-react/core";
import { Provider as JotaiProvider } from "jotai";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { Route, BrowserRouter as Router, Routes } from "react-router-dom";
import Gameplay from "./pages/games/Gameplay";
import Home from "./pages/Home";
Expand All @@ -22,12 +23,6 @@ const options: ControllerOptions = {
policies: POLICIES,
};

function rpc(_chain: Chain) {
return {
nodeUrl: SLOT_RPC_URL,
};
}

const SmallScreenWarning = () => (
<div className="fixed inset-0 z-50 flex items-center justify-center text-white bg-black bg-opacity-75 backdrop-blur-sm">
<div className="p-4 text-center">
Expand All @@ -54,12 +49,17 @@ export default function App() {

const connectors = [new ControllerConnector(options) as never as Connector];

const rpc = useCallback(() => {
return { nodeUrl: SLOT_RPC_URL };
}, []);

return (
<StarknetConfig
autoConnect={true}
chains={[sepolia]}
provider={jsonRpcProvider({ rpc })}
connectors={connectors}
explorer={voyager}
autoConnect
>
<JotaiProvider>
<Router>
Expand Down
224 changes: 115 additions & 109 deletions client/src/components/gameplay/game-board.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from "react";
import { BottomPit, TopPit } from "@/components/pits";
import { Dispatch, SetStateAction } from "react";
import clsx from "clsx";
import { useQuery } from "@apollo/client";
import { MancalaSeedQuery } from "@/lib/constants";
import Seed from "../seed";
Expand Down Expand Up @@ -29,23 +28,59 @@ const GameBoard: React.FC<GameBoardProps> = ({
variables: { gameId: gameId },
});
startPolling(1000);

const seeds = React.useMemo(() => {
if (!data?.mancalaDevSeedModels?.edges) return [];
const uniqueSeeds = new Map();

// Sort edges by timestamp in descending order (newest first)
const sortedEdges = [...data.mancalaDevSeedModels.edges].sort((a, b) => {
const timeA = new Date(a.node.entity.updatedAt).getTime();
const timeB = new Date(b.node.entity.updatedAt).getTime();
return timeB - timeA; // Descending order
});

sortedEdges.forEach((seed: any) => {
const seedId = seed?.node.seed_id;
if (seedId && !uniqueSeeds.has(seedId)) {
uniqueSeeds.set(seedId, seed.node);
}
});

return Array.from(uniqueSeeds.values());
}, [data]);

const getSeed = (seedId: string | number) => {
const hexSeedId =
typeof seedId === "number" ? `0x${seedId.toString(16)}` : seedId;
const seed = seeds.find((seed) => seed.seed_id === hexSeedId);
if (!seed) return null;

const seedNumber = parseInt(seed.seed_id, 16);
const isNative =
(seed.player === game_node?.player_one &&
seedNumber >= 1 &&
seedNumber <= 24) ||
(seed.player === game_node?.player_two &&
seedNumber >= 25 &&
seedNumber <= 48);

return { ...seed, isNative };
};

const involved = game_players?.mancalaDevPlayerModels.edges.some(
(item: any) => item?.node.address === account.account?.address,
(item: any) =>
item?.node.address ===
(account.account?.address || game_node?.player_one),
);
const player_position = involved
? game_players?.mancalaDevPlayerModels.edges.findIndex(
(item: any) => item?.node.address === account.account?.address,
(item: any) =>
item?.node.address ===
(account.account?.address || game_node?.player_one),
)
: 0;
const opponent_position = player_position === 0 ? 1 : 0;
const opposition_length = data?.mancalaDevSeedModels.edges
.filter(
(item: any) =>
item?.node.player ===
game_players?.mancalaDevPlayerModels.edges[opponent_position]?.node
.address,
)
.filter((item: any) => item?.node.pit_number === 7).length;
const player_pot_seed_count =
game_players?.mancalaDevPitModels.edges
.filter(
Expand Down Expand Up @@ -92,11 +127,12 @@ const GameBoard: React.FC<GameBoardProps> = ({
return "170px";
}
};

return (
<div className="w-full h-[400px] flex flex-col items-center justify-center mt-24">
<div className="w-[1170px] h-[400px] flex flex-row items-center justify-between space-x-5 relative bg-[url('./assets/game_board.png')] bg-contain bg-center bg-no-repeat">
<div className="w-fit h-[220px] mt-14 relative">
{/* Player 1 pot */}
{/* Player 1 pot (opponent) */}
<div
className={
"w-fit max-w-14 h-fit max-h-40 flex flex-col flex-wrap -mt-2.5"
Expand All @@ -105,44 +141,39 @@ const GameBoard: React.FC<GameBoardProps> = ({
marginLeft: getOpponentMarginLeft(),
}}
>
{// involved && data?.mancalaSeedModels.edges.filter((item: any) => item?.node.player === game_players?.mancalaPlayerModels.edges[opponent_position]?.node.address)
data?.mancalaDevSeedModels.edges
.filter(
(item: any) =>
item?.node.player ===
game_players?.mancalaDevPlayerModels.edges[opponent_position]
?.node.address,
)
.filter((item: any) => item?.node.pit_number === 7)
.slice(0, opponent_pot_seed_count)
.map((seed: any, index: number) => (
<div
key={index}
style={{
width: opposition_length > 30 ? "8px" : "auto",
}}
>
<Seed
color={seed?.node.color || "Blue"}
length={opponent_pot_seed_count}
type="opponent"
id={parseInt(seed.node.seed_id, 16)}
/>
</div>
))}
{Array.from({ length: 24 }, (_, i) => {
if (account.account?.address) {
return game_node?.player_one === account.account?.address
? i + 25
: i + 1;
} else {
return i + 25;
}
}).map((seedNumber) => {
const seedDetails = getSeed(seedNumber);
if (!seedDetails) return null;

const isPlayerSeed = account.account?.address
? seedDetails.player === account.account?.address
: seedDetails.player === game_node?.player_one;

return (
<Seed
key={seedNumber}
color={seedDetails?.color || "Blue"}
length={isPlayerSeed ? player_pot_seed_count : opponent_pot_seed_count}
type={isPlayerSeed ? "player" : "opponent"}
seed_id={parseInt(seedDetails?.seed_id, 16)}
pit_number={seedDetails?.pit_number}
seed_number={seedDetails?.seed_number}
isNative={seedDetails.isNative}
/>
);
})}
</div>
<div className="absolute inset-y-0 self-center left-32 ml-1.5 mb-20">
<div className="h-[160px] flex flex-col items-center justify-center" style={{marginLeft: opponent_pot_seed_count > 24 ? "128px" : opponent_pot_seed_count > 10 ? "113px" : "100px"}}>
<p className="text-white text-center">
{
data?.mancalaDevSeedModels.edges
.filter(
(item: any) =>
item?.node.player ===
game_players?.mancalaDevPlayerModels.edges[opponent_position]
?.node.address,
)
.filter((item: any) => item?.node.pit_number === 7).length
}
{opponent_pot_seed_count}
</p>
</div>
</div>
Expand All @@ -154,38 +185,14 @@ const GameBoard: React.FC<GameBoardProps> = ({
.filter(
(item: any) =>
item?.node.player ===
game_players?.mancalaDevPlayerModels.edges[opponent_position]
?.node.address,
game_players?.mancalaDevPlayerModels.edges[
opponent_position
]?.node.address,
)
.filter((item: any) => item?.node.pit_number !== 7) // Exclude the scoring pit
.sort((a: any, b: any) => b.node.pit_number - a.node.pit_number) // Sort in descending order
.map((pit: any, i: number) => (
<TopPit
key={i}
amount={pit.node.seed_count}
address={pit.node.player}
pit={pit.node.pit_number}
system={system}
userAccount={account}
game_id={gameId}
message={setMoveMessage}
status={game_node?.status}
winner={game_node?.winner}
seed_count={pit.node.seed_count}
seeds={data?.mancalaDevSeedModels.edges
.filter(
(seed: any) => seed?.node.player === pit.node.player,
)
.filter(
(seed: any) =>
seed?.node.pit_number === pit.node.pit_number,
)}
setTimeRemaining={setTimeRemaining}
max_block_between_move={parseInt(
game_node?.max_block_between_move,
16,
)}
/>
<TopPit key={i} amount={pit.node.seed_count} />
))}
</div>
</div>
Expand All @@ -202,15 +209,6 @@ const GameBoard: React.FC<GameBoardProps> = ({
.filter((item: any) => item?.node.pit_number !== 7)
.sort((a: any, b: any) => a.node.pit_number - b.node.pit_number)
.map((pit: any, i: number) => {
// Filter seeds for this specific pit number (1-6)
const pitSeeds = data?.mancalaDevSeedModels.edges.filter(
(seed: any) =>
seed?.node.player === pit.node.player &&
seed?.node.pit_number === pit.node.pit_number &&
pit.node.pit_number >= 1 &&
pit.node.pit_number <= 6,
);

return (
<BottomPit
key={i}
Expand All @@ -223,8 +221,6 @@ const GameBoard: React.FC<GameBoardProps> = ({
message={setMoveMessage}
status={game_node?.status}
winner={game_node?.winner}
seed_count={pit.node.seed_count}
seeds={pitSeeds}
setTimeRemaining={setTimeRemaining}
max_block_between_move={parseInt(
game_node?.max_block_between_move,
Expand All @@ -237,7 +233,7 @@ const GameBoard: React.FC<GameBoardProps> = ({
</div>
</div>
<div className="w-fit h-[220px] mt-14 relative">
{/* Player 2 pot */}
{/* Player 2 pot (player) */}
<div
className={
"w-fit max-w-14 h-fit max-h-40 flex flex-col flex-wrap -mt-2.5"
Expand All @@ -246,27 +242,37 @@ const GameBoard: React.FC<GameBoardProps> = ({
marginRight: getPlayerMarginRight(),
}}
>
{data?.mancalaDevSeedModels.edges
.filter(
(item: any) =>
item?.node.player ===
game_players?.mancalaDevPlayerModels.edges[player_position]?.node
.address,
)
.filter((item: any) => item?.node.pit_number === 7)
.slice(0, player_pot_seed_count)
.map((seed: any, index: number) => (
<div key={index}>
<Seed
color={seed?.node.color || "Blue"}
length={player_pot_seed_count}
type="player"
id={parseInt(seed.node.seed_id, 16)}
/>
</div>
))}
{Array.from({ length: 24 }, (_, i) => {
if (account.account?.address) {
return game_node?.player_one === account.account?.address
? i + 1
: i + 25;
} else {
return i + 1;
}
}).map((seedNumber) => {
const seedDetails = getSeed(seedNumber);
if (!seedDetails) return null;

const isPlayerSeed = account.account?.address
? seedDetails.player === account.account?.address
: seedDetails.player === game_node?.player_one;

return (
<Seed
key={seedNumber}
color={seedDetails?.color || "Blue"}
length={isPlayerSeed ? player_pot_seed_count : opponent_pot_seed_count}
type={isPlayerSeed ? "player" : "opponent"}
seed_id={parseInt(seedDetails?.seed_id, 16)}
pit_number={seedDetails?.pit_number}
seed_number={seedDetails?.seed_number}
isNative={seedDetails.isNative}
/>
);
})}
</div>
<div className="absolute inset-y-0 self-center right-32 bottom-20 w-7 h-12">
<div className="h-[160px] flex flex-col items-center justify-center" style={{marginRight: player_pot_seed_count > 24 ? "120px" : player_pot_seed_count > 10 ? "113px" : "100px"}}>
<p className="text-white text-center h-full flex flex-col items-center justify-center">
{player_pot_seed_count}
</p>
Expand All @@ -277,4 +283,4 @@ const GameBoard: React.FC<GameBoardProps> = ({
);
};

export default GameBoard;
export default GameBoard;
Loading