wip
This commit is contained in:
parent
f5d58c1541
commit
1e549de4fb
15 changed files with 479 additions and 32 deletions
79
src/App.tsx
79
src/App.tsx
|
|
@ -1,15 +1,19 @@
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { socket } from "./socket";
|
import { socket } from "./socket";
|
||||||
import ThreeScene from "./components/ThreeScene";
|
import { Object3D, Mesh } from "three";
|
||||||
|
import { Canvas } from "@react-three/fiber";
|
||||||
|
import { OrbitControls, useGLTF, PerspectiveCamera } from "@react-three/drei";
|
||||||
import { ConnectionState } from "./components/ConnectionState";
|
import { ConnectionState } from "./components/ConnectionState";
|
||||||
import { ConnectionManager } from "./components/ConnectionManager";
|
import { ConnectionManager } from "./components/ConnectionManager";
|
||||||
import { JoinSession } from "./components/JoinSession";
|
import { JoinSession } from "./components/JoinSession";
|
||||||
import { Events } from "./components/Events";
|
import { Events } from "./components/Events";
|
||||||
import { Game } from "./types/gameTypes";
|
import { Game } from "./types/gameTypes";
|
||||||
import Action from "./components/Action";
|
import Action from "./components/Action";
|
||||||
import CardStack from "./components/CardStack";
|
import CardStack from "./components/CardStackOld";
|
||||||
import DepositCards from "./components/DepositCards";
|
import DepositCards from "./components/DepositCardsOld";
|
||||||
import CardCache from "./components/CardCache";
|
import CardCache from "./components/CardCacheOld";
|
||||||
|
import { extractCurrentPlayer } from "./helpers";
|
||||||
|
import PlayArea from "./components/PlayArea";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [isConnected, setIsConnected] = useState(socket.connected);
|
const [isConnected, setIsConnected] = useState(socket.connected);
|
||||||
|
|
@ -22,7 +26,7 @@ export default function App() {
|
||||||
const showStartGameButton = session !== "" && clientsInRoom >= 2;
|
const showStartGameButton = session !== "" && clientsInRoom >= 2;
|
||||||
const showNextGameButton = gameData?.phase === "new round";
|
const showNextGameButton = gameData?.phase === "new round";
|
||||||
|
|
||||||
const playersData = extractMyData(gameData);
|
const playersData = extractCurrentPlayer(gameData);
|
||||||
|
|
||||||
function startGame() {
|
function startGame() {
|
||||||
socket.emit("new-game", { sessionId: session });
|
socket.emit("new-game", { sessionId: session });
|
||||||
|
|
@ -37,11 +41,6 @@ export default function App() {
|
||||||
socket.emit("click-card", cardPosition);
|
socket.emit("click-card", cardPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractMyData(gameData: Game | null) {
|
|
||||||
if (!gameData) return undefined;
|
|
||||||
return gameData.players.find((player) => player.socketId === socket.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setTempMessage(message: string) {
|
function setTempMessage(message: string) {
|
||||||
setMessageDisplay(message);
|
setMessageDisplay(message);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
@ -49,16 +48,6 @@ export default function App() {
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (gameData?.phase === "game-over") {
|
|
||||||
setTempMessage("Game Over");
|
|
||||||
} else if (gameData?.phase === "game-started") {
|
|
||||||
setTempMessage("Game Started");
|
|
||||||
} else if (gameData?.phase === "waiting-for-players") {
|
|
||||||
setTempMessage("Waiting for players");
|
|
||||||
}
|
|
||||||
}, [gameData]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function onConnect() {
|
function onConnect() {
|
||||||
setIsConnected(true);
|
setIsConnected(true);
|
||||||
|
|
@ -96,9 +85,57 @@ export default function App() {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Three-Fiber
|
||||||
|
const tableModel = useGLTF("/models/table.glb");
|
||||||
|
const heightProportion = 1.25;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<ThreeScene gameData={gameData} />
|
<div
|
||||||
|
style={{
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight / heightProportion,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Canvas>
|
||||||
|
<PerspectiveCamera
|
||||||
|
makeDefault
|
||||||
|
manual
|
||||||
|
fov={75}
|
||||||
|
aspect={window.innerWidth / (window.innerHeight / heightProportion)}
|
||||||
|
near={0.1}
|
||||||
|
far={1000}
|
||||||
|
position={[0, 45, 10]}
|
||||||
|
// lookAt={() => new Vector3(0, 0, 0)}
|
||||||
|
/>
|
||||||
|
<ambientLight color={0xa3a3a3} intensity={0.1} />
|
||||||
|
<directionalLight
|
||||||
|
color={0xffffff}
|
||||||
|
position={[0, 50, 20]}
|
||||||
|
castShadow
|
||||||
|
shadow-mapSize={[1024, 1024]}
|
||||||
|
/>
|
||||||
|
<mesh>
|
||||||
|
<boxGeometry args={[2, 2, 2]} />
|
||||||
|
<meshStandardMaterial color={0x00ff00} />
|
||||||
|
</mesh>
|
||||||
|
<primitive
|
||||||
|
object={tableModel.scene}
|
||||||
|
position={[0, 1.8, 0]}
|
||||||
|
scale={[2, 2, 2]}
|
||||||
|
traverse={(node: Object3D) => {
|
||||||
|
if (node instanceof Mesh) {
|
||||||
|
// node.castShadow = true;
|
||||||
|
node.receiveShadow = true;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<gridHelper args={[100, 100]} />
|
||||||
|
<axesHelper args={[5]} />
|
||||||
|
<OrbitControls />
|
||||||
|
<PlayArea gameData={gameData} />
|
||||||
|
</Canvas>
|
||||||
|
</div>
|
||||||
<ConnectionState
|
<ConnectionState
|
||||||
isConnected={isConnected}
|
isConnected={isConnected}
|
||||||
session={session}
|
session={session}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,42 @@
|
||||||
import { FC } from "react";
|
import { FC, useEffect, useState } from "react";
|
||||||
|
import { Vector3, Object3D } from "three";
|
||||||
|
import { socket } from "../socket";
|
||||||
|
|
||||||
|
import { createCard } from "../objects/cards";
|
||||||
import { Player } from "../types/gameTypes";
|
import { Player } from "../types/gameTypes";
|
||||||
|
|
||||||
type CardCacheProps = {
|
type CardCacheProps = {
|
||||||
playersData: Player | undefined;
|
playersData: Player[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const CardCache: FC<CardCacheProps> = ({ playersData }) => {
|
const CardCache: FC<CardCacheProps> = ({ playersData }) => {
|
||||||
if (!playersData?.cardCache) {
|
const [cardCacheCard, setCardCacheCard] = useState<Object3D | null>(null);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
const updateCardCache = (playerData: Player) => {
|
||||||
<div>
|
if (playerData.cardCache == null) {
|
||||||
<p>Card Cache: {playersData.cardCache.value}</p>
|
setCardCacheCard(null);
|
||||||
</div>
|
return;
|
||||||
|
}
|
||||||
|
const showFaceUp = true;
|
||||||
|
const card = createCard(
|
||||||
|
playerData.cardCache,
|
||||||
|
new Vector3(9, 20, 4),
|
||||||
|
showFaceUp
|
||||||
);
|
);
|
||||||
|
setCardCacheCard(card);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const playerData = playersData.find(
|
||||||
|
(player) => player.socketId === socket.id
|
||||||
|
);
|
||||||
|
if (!playerData) return;
|
||||||
|
updateCardCache(playerData);
|
||||||
|
}, [playersData]);
|
||||||
|
|
||||||
|
if (!cardCacheCard) return null;
|
||||||
|
|
||||||
|
return <primitive object={cardCacheCard} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CardCache;
|
export default CardCache;
|
||||||
|
|
|
||||||
21
src/components/CardCacheOld.tsx
Normal file
21
src/components/CardCacheOld.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
|
||||||
|
import { Player } from "../types/gameTypes";
|
||||||
|
|
||||||
|
type CardCacheProps = {
|
||||||
|
playersData: Player | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CardCache: FC<CardCacheProps> = ({ playersData }) => {
|
||||||
|
if (!playersData?.cardCache) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Card Cache: {playersData.cardCache.value}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CardCache;
|
||||||
27
src/components/CardStackCard.tsx
Normal file
27
src/components/CardStackCard.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { FC, useState, useEffect } from "react";
|
||||||
|
import { Object3D, Object3DEventMap } from "three";
|
||||||
|
import { socket } from "../socket";
|
||||||
|
|
||||||
|
type CardStackCardProps = {
|
||||||
|
card: Object3D<Object3DEventMap>;
|
||||||
|
isUppermostCard: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CardStackCard: FC<CardStackCardProps> = ({ card, isUppermostCard }) => {
|
||||||
|
const [cardObject, setCardObject] =
|
||||||
|
useState<Object3D<Object3DEventMap>>(card);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (cardObject.name === card.name) return;
|
||||||
|
setCardObject(card);
|
||||||
|
}, [card, cardObject]);
|
||||||
|
|
||||||
|
const clickCard = () => {
|
||||||
|
if (!isUppermostCard) return;
|
||||||
|
console.log("Draw card");
|
||||||
|
socket.emit("draw-from-card-stack", "draw card");
|
||||||
|
};
|
||||||
|
return <primitive object={cardObject} onClick={() => clickCard()} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CardStackCard;
|
||||||
45
src/components/CardStackStaple.tsx
Normal file
45
src/components/CardStackStaple.tsx
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { FC, useEffect, useState } from "react";
|
||||||
|
import { Vector3, Object3D } from "three";
|
||||||
|
import { CardStack } from "../types/gameTypes";
|
||||||
|
import { createCardStaple } from "../objects/cards";
|
||||||
|
import CardStackCard from "./CardStackCard";
|
||||||
|
|
||||||
|
type CardStackProps = {
|
||||||
|
cardStackData: CardStack | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CardStackStaple: FC<CardStackProps> = ({ cardStackData }) => {
|
||||||
|
const [cardStack, setCardStack] = useState<Object3D[]>([]);
|
||||||
|
|
||||||
|
const updateCardStack = (cardStackData: CardStack) => {
|
||||||
|
const stack = createCardStaple(
|
||||||
|
cardStackData.cards,
|
||||||
|
new Vector3(-1.2, 20, 0)
|
||||||
|
);
|
||||||
|
setCardStack(stack);
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkIfUppermostCard = (index: number) => {
|
||||||
|
return index === cardStack.length - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!cardStackData) return;
|
||||||
|
updateCardStack(cardStackData);
|
||||||
|
}, [cardStackData]);
|
||||||
|
if (!cardStackData) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{cardStack.map((card, index) => (
|
||||||
|
<CardStackCard
|
||||||
|
key={index}
|
||||||
|
card={card}
|
||||||
|
isUppermostCard={checkIfUppermostCard(index)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CardStackStaple;
|
||||||
48
src/components/DiscardPile.tsx
Normal file
48
src/components/DiscardPile.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { FC, useState, useEffect } from "react";
|
||||||
|
import { Vector3, Object3D } from "three";
|
||||||
|
|
||||||
|
import { Card } from "../types/gameTypes";
|
||||||
|
import { createCardStaple } from "../objects/cards";
|
||||||
|
import DiscardPileCard from "./DiscardPileCard";
|
||||||
|
|
||||||
|
type DiscardPileProps = {
|
||||||
|
discardPileData: Card[] | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DiscardPile: FC<DiscardPileProps> = ({ discardPileData }) => {
|
||||||
|
const [discardPile, setDiscardPile] = useState<Object3D[]>([]);
|
||||||
|
|
||||||
|
const updateDiscardPile = (discardPileData: Card[]) => {
|
||||||
|
const showFaceUp = true;
|
||||||
|
const pile = createCardStaple(
|
||||||
|
discardPileData,
|
||||||
|
new Vector3(1.2, 20, 0),
|
||||||
|
showFaceUp
|
||||||
|
);
|
||||||
|
setDiscardPile(pile);
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkIfUppermostCard = (index: number) => {
|
||||||
|
return index === discardPile.length - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!discardPileData) return;
|
||||||
|
updateDiscardPile(discardPileData);
|
||||||
|
}, [discardPileData]);
|
||||||
|
|
||||||
|
if (!discardPile) return null;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{discardPile.map((card, index) => (
|
||||||
|
<DiscardPileCard
|
||||||
|
key={index}
|
||||||
|
card={card}
|
||||||
|
isUppermostCard={checkIfUppermostCard(index)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DiscardPile;
|
||||||
30
src/components/DiscardPileCard.tsx
Normal file
30
src/components/DiscardPileCard.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { FC, useState, useEffect } from "react";
|
||||||
|
import { Object3D, Object3DEventMap } from "three";
|
||||||
|
import { socket } from "../socket";
|
||||||
|
|
||||||
|
type DiscardPileCardProps = {
|
||||||
|
card: Object3D<Object3DEventMap>;
|
||||||
|
isUppermostCard: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DiscardPileCard: FC<DiscardPileCardProps> = ({
|
||||||
|
card,
|
||||||
|
isUppermostCard,
|
||||||
|
}) => {
|
||||||
|
const [cardObject, setCardObject] =
|
||||||
|
useState<Object3D<Object3DEventMap>>(card);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (cardObject.name === card.name) return;
|
||||||
|
setCardObject(card);
|
||||||
|
}, [card, cardObject]);
|
||||||
|
|
||||||
|
const clickCard = () => {
|
||||||
|
if (!isUppermostCard) return;
|
||||||
|
console.log("Draw card");
|
||||||
|
socket.emit("draw-from-card-stack", "draw card");
|
||||||
|
};
|
||||||
|
return <primitive object={cardObject} onClick={() => clickCard()} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DiscardPileCard;
|
||||||
26
src/components/PlayArea.tsx
Normal file
26
src/components/PlayArea.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
|
||||||
|
import PlayerCards from "../components/PlayerCards";
|
||||||
|
import { Game } from "../types/gameTypes";
|
||||||
|
import CardStackStaple from "./CardStackStaple";
|
||||||
|
import DiscardPile from "./DiscardPile";
|
||||||
|
import CardCache from "./CardCache";
|
||||||
|
|
||||||
|
type PlayAreaProps = {
|
||||||
|
gameData: Game | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const PlayArea: FC<PlayAreaProps> = ({ gameData }) => {
|
||||||
|
if (!gameData) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<PlayerCards playersData={gameData.players} />
|
||||||
|
<CardStackStaple cardStackData={gameData.cardStack} />
|
||||||
|
<DiscardPile discardPileData={gameData.discardPile} />
|
||||||
|
<CardCache playersData={gameData.players} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PlayArea;
|
||||||
69
src/components/PlayerCard.tsx
Normal file
69
src/components/PlayerCard.tsx
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { FC, useState, useEffect } from "react";
|
||||||
|
import { Object3D, Object3DEventMap } from "three";
|
||||||
|
// import { useFrame } from "@react-three/fiber";
|
||||||
|
import { socket } from "../socket";
|
||||||
|
import { PlayerWithVisualCards } from "../types/gameTypes";
|
||||||
|
|
||||||
|
type PlayerCardProps = {
|
||||||
|
card: Object3D<Object3DEventMap>;
|
||||||
|
index: number;
|
||||||
|
isCurrentPlayer: boolean;
|
||||||
|
playerWithCards: PlayerWithVisualCards;
|
||||||
|
};
|
||||||
|
|
||||||
|
const PlayerCard: FC<PlayerCardProps> = ({
|
||||||
|
card,
|
||||||
|
index,
|
||||||
|
isCurrentPlayer,
|
||||||
|
playerWithCards,
|
||||||
|
}) => {
|
||||||
|
const isCardRevealed = playerWithCards.player.knownCardPositions[index];
|
||||||
|
const [cardObject, setCardObject] =
|
||||||
|
useState<Object3D<Object3DEventMap>>(card);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (cardObject.name === card.name) return;
|
||||||
|
setCardObject(card);
|
||||||
|
}, [card, cardObject]);
|
||||||
|
|
||||||
|
// TODO: Fix stuttering card rotation
|
||||||
|
/*const [rotationGoal, setRotationGoal] = useState(0);
|
||||||
|
const rotationSpeed = 0.05; // Adjust for faster/slower flip
|
||||||
|
const currentRotation = useRef<number>(0);
|
||||||
|
|
||||||
|
useFrame(() => {
|
||||||
|
if (currentRotation.current < rotationGoal) {
|
||||||
|
card.rotation.x += rotationSpeed;
|
||||||
|
currentRotation.current += rotationSpeed;
|
||||||
|
if (currentRotation.current >= rotationGoal) {
|
||||||
|
card.rotation.x = rotationGoal;
|
||||||
|
}
|
||||||
|
} else if (currentRotation.current > rotationGoal) {
|
||||||
|
card.rotation.x -= rotationSpeed;
|
||||||
|
currentRotation.current -= rotationSpeed;
|
||||||
|
if (currentRotation.current <= rotationGoal) {
|
||||||
|
card.rotation.x = rotationGoal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});*/
|
||||||
|
|
||||||
|
if (isCardRevealed) {
|
||||||
|
card.rotation.x = Math.PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
const clickCard = () => {
|
||||||
|
if (!isCurrentPlayer) return;
|
||||||
|
console.log("Clicked on one of my cards");
|
||||||
|
socket.emit("click-card", index, (response: string) => {
|
||||||
|
console.log("Response:", response);
|
||||||
|
/*if (rotationGoal === 0) {
|
||||||
|
setRotationGoal(Math.PI);
|
||||||
|
} else {
|
||||||
|
setRotationGoal(0);
|
||||||
|
}*/
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return <primitive object={cardObject} onClick={() => clickCard()} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PlayerCard;
|
||||||
73
src/components/PlayerCards.tsx
Normal file
73
src/components/PlayerCards.tsx
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
import { FC, useState, useEffect } from "react";
|
||||||
|
import { socket } from "../socket";
|
||||||
|
import { Vector3 } from "three";
|
||||||
|
|
||||||
|
import { createPlayerCards } from "../objects/cards";
|
||||||
|
import PlayerCard from "./PlayerCard";
|
||||||
|
import { PlayerWithVisualCards, Player } from "../types/gameTypes";
|
||||||
|
|
||||||
|
type PlayerCardsProps = {
|
||||||
|
playersData: Player[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const PlayerCards: FC<PlayerCardsProps> = ({ playersData }) => {
|
||||||
|
const [playersWithCards, setPlayersWithCards] = useState<
|
||||||
|
PlayerWithVisualCards[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
const updatePlayerCards = (playersData: Player[]) => {
|
||||||
|
const playersWithCards: PlayerWithVisualCards[] = [];
|
||||||
|
const currentPlayerWithCards: PlayerWithVisualCards[] = [];
|
||||||
|
let nonCurrentPlayerIndex = 1;
|
||||||
|
playersData.forEach((player) => {
|
||||||
|
const positionOffset = 12;
|
||||||
|
const playerWithCards: PlayerWithVisualCards = {
|
||||||
|
player,
|
||||||
|
cards: [],
|
||||||
|
};
|
||||||
|
if (player.socketId === socket.id) {
|
||||||
|
playerWithCards.cards = createPlayerCards(
|
||||||
|
player.cards,
|
||||||
|
new Vector3(0, 20, positionOffset)
|
||||||
|
);
|
||||||
|
currentPlayerWithCards.push(playerWithCards);
|
||||||
|
} else {
|
||||||
|
const playerOffset = positionOffset + nonCurrentPlayerIndex * -20;
|
||||||
|
playerWithCards.cards = createPlayerCards(
|
||||||
|
player.cards,
|
||||||
|
new Vector3(0, 20, playerOffset)
|
||||||
|
);
|
||||||
|
playersWithCards.push(playerWithCards);
|
||||||
|
nonCurrentPlayerIndex++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setPlayersWithCards([...currentPlayerWithCards, ...playersWithCards]);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!playersData) return;
|
||||||
|
updatePlayerCards(playersData);
|
||||||
|
}, [playersData]);
|
||||||
|
|
||||||
|
if (!playersWithCards) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{playersWithCards.map((playerWithCards, playerIndex) => (
|
||||||
|
<>
|
||||||
|
{playerWithCards.cards.map((card, index) => (
|
||||||
|
<PlayerCard
|
||||||
|
key={index}
|
||||||
|
card={card}
|
||||||
|
playerWithCards={playerWithCards}
|
||||||
|
index={index}
|
||||||
|
isCurrentPlayer={playerIndex === 0}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PlayerCards;
|
||||||
7
src/helpers.ts
Normal file
7
src/helpers.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { Game } from "./types/gameTypes";
|
||||||
|
import { socket } from "./socket";
|
||||||
|
|
||||||
|
export function extractCurrentPlayer(gameData: Game | null) {
|
||||||
|
if (!gameData) return undefined;
|
||||||
|
return gameData.players.find((player) => player.socketId === socket.id);
|
||||||
|
}
|
||||||
|
|
@ -77,7 +77,11 @@ const getCardTexture = (value: number | string) => {
|
||||||
return cardTexture;
|
return cardTexture;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createCard = (cardData: Card, position: Vector3) => {
|
export const createCard = (
|
||||||
|
cardData: Card,
|
||||||
|
position: Vector3,
|
||||||
|
faceUp: boolean = false
|
||||||
|
) => {
|
||||||
const cardMaterial = [
|
const cardMaterial = [
|
||||||
new MeshBasicMaterial(),
|
new MeshBasicMaterial(),
|
||||||
new MeshBasicMaterial(),
|
new MeshBasicMaterial(),
|
||||||
|
|
@ -89,6 +93,12 @@ export const createCard = (cardData: Card, position: Vector3) => {
|
||||||
const card = new Mesh(cardGeometry, cardMaterial);
|
const card = new Mesh(cardGeometry, cardMaterial);
|
||||||
card.name = cardData.name;
|
card.name = cardData.name;
|
||||||
card.position.copy(position);
|
card.position.copy(position);
|
||||||
|
|
||||||
|
if (faceUp) {
|
||||||
|
card.rotation.x = Math.PI;
|
||||||
|
console.log("faceUp");
|
||||||
|
}
|
||||||
|
|
||||||
return card;
|
return card;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -117,3 +127,29 @@ export const createPlayerCards = (
|
||||||
});
|
});
|
||||||
return playerCards;
|
return playerCards;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createCardStaple = (
|
||||||
|
cards: Card[],
|
||||||
|
positionReference: Vector3,
|
||||||
|
faceUp: boolean = false
|
||||||
|
) => {
|
||||||
|
const cardStackCards: Mesh<
|
||||||
|
BoxGeometry,
|
||||||
|
MeshBasicMaterial[],
|
||||||
|
Object3DEventMap
|
||||||
|
>[] = [];
|
||||||
|
cards.forEach((card: Card, index: number) => {
|
||||||
|
const cardPositionX = positionReference.x;
|
||||||
|
const cardPositionY = positionReference.y + index * 0.01;
|
||||||
|
const cardPositionZ = positionReference.z;
|
||||||
|
|
||||||
|
const cardPosition = new Vector3(
|
||||||
|
cardPositionX,
|
||||||
|
cardPositionY,
|
||||||
|
cardPositionZ
|
||||||
|
);
|
||||||
|
const cardStackCard = createCard(card, cardPosition, faceUp);
|
||||||
|
cardStackCards.push(cardStackCard);
|
||||||
|
});
|
||||||
|
return cardStackCards;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Object3D } from "three";
|
||||||
|
|
||||||
export type Player = {
|
export type Player = {
|
||||||
id: number;
|
id: number;
|
||||||
socketId: string;
|
socketId: string;
|
||||||
|
|
@ -12,6 +14,11 @@ export type Player = {
|
||||||
closedRound: boolean;
|
closedRound: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PlayerWithVisualCards = {
|
||||||
|
player: Player;
|
||||||
|
cards: Object3D[];
|
||||||
|
};
|
||||||
|
|
||||||
export type CardValue =
|
export type CardValue =
|
||||||
| -2
|
| -2
|
||||||
| -1
|
| -1
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue