diff --git a/.env b/.env
index 7751623..b35bba8 100644
--- a/.env
+++ b/.env
@@ -1,5 +1,5 @@
VITE_ENVIRONMENT=dev
VITE_BACKEND_URL=https://skyjo-backend.voltvector.org
-#VITE_ENVIRONMENT=local
-#VITE_BACKEND_URL=http://localhost:3001
\ No newline at end of file
+VITE_ENVIRONMENT=local
+VITE_BACKEND_URL=http://localhost:3001
\ No newline at end of file
diff --git a/index.html b/index.html
index 05f0bce..994d2b6 100644
--- a/index.html
+++ b/index.html
@@ -7,9 +7,9 @@
rel="stylesheet"
as="style"
/>
-
+
-
Play Skyjo!
+ Play Skylo!
diff --git a/public/card-back.svg b/public/card-back.svg
new file mode 100644
index 0000000..c44421d
--- /dev/null
+++ b/public/card-back.svg
@@ -0,0 +1,1631 @@
+
\ No newline at end of file
diff --git a/src/App.tsx b/src/App.tsx
index 4a5475b..845c36b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -62,8 +62,6 @@ export default function App() {
};
}, []);
- console.log(messageDispaly);
-
return (
{!gameData && (
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
index 2509957..afaf92f 100644
--- a/src/components/Footer.tsx
+++ b/src/components/Footer.tsx
@@ -60,8 +60,8 @@ export const Footer: FC
- {gameData.players.map((player) => (
-
+ {gameData.players.map((player, index) => (
+
{player?.name} {player.socketId == socket.id && "👤"}{" "}
diff --git a/src/components/PlayArea.tsx b/src/components/PlayArea.tsx
index dac45a2..c66521c 100644
--- a/src/components/PlayArea.tsx
+++ b/src/components/PlayArea.tsx
@@ -1,6 +1,6 @@
import { FC } from "react";
-import PlayerCards from "../components/PlayerCards";
+import PlayerDecks from "./PlayerDecks";
import { Game } from "../types/gameTypes";
import CardStackStaple from "./CardStackStaple";
import DiscardPile from "./DiscardPile";
@@ -14,7 +14,7 @@ const PlayArea: FC = ({ gameData }) => {
return (
<>
-
+
>
diff --git a/src/components/PlayerCard.tsx b/src/components/PlayerCard.tsx
index 852af43..99ddbec 100644
--- a/src/components/PlayerCard.tsx
+++ b/src/components/PlayerCard.tsx
@@ -2,22 +2,25 @@ 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";
+import { PlayerVisualDeck } from "../types/gameTypes";
type PlayerCardProps = {
card: Object3D;
- index: number;
+ columnIndex: number;
+ cardIndex: number;
isCurrentPlayer: boolean;
- playerWithCards: PlayerWithVisualCards;
+ visualPlayerDeck: PlayerVisualDeck;
};
const PlayerCard: FC = ({
card,
- index,
+ columnIndex,
+ cardIndex,
isCurrentPlayer,
- playerWithCards,
+ visualPlayerDeck,
}) => {
- const isCardRevealed = playerWithCards.player.knownCardPositions[index];
+ const isCardRevealed =
+ visualPlayerDeck.player.knownCardPositions[columnIndex][cardIndex];
const [cardObject, setCardObject] =
useState>(card);
@@ -54,16 +57,15 @@ const PlayerCard: FC = ({
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);
- }*/
- });
+ socket.emit("click-card", [columnIndex, cardIndex]);
};
- return clickCard()} />;
+ return (
+ clickCard()}
+ />
+ );
};
export default PlayerCard;
diff --git a/src/components/PlayerCards.tsx b/src/components/PlayerCards.tsx
deleted file mode 100644
index b27403e..0000000
--- a/src/components/PlayerCards.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-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";
-import CardCache from "./CardCache";
-
-type PlayerCardsProps = {
- playersData: Player[];
-};
-
-const PlayerCards: FC = ({ playersData }) => {
- const [playersWithCards, setPlayersWithCards] = useState<
- PlayerWithVisualCards[]
- >([]);
-
- const updatePlayerCards = (playersData: Player[]) => {
- const playersWithCards: PlayerWithVisualCards[] = [];
- const currentPlayerWithCards: PlayerWithVisualCards[] = [];
- let nonCurrentPlayerIndex = 1;
- playersData.forEach((player) => {
- const positionOffset = 14;
- 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) => (
-
- ))}
-
- >
- ))}
- >
- );
-};
-
-export default PlayerCards;
-// ich (0) --> 4
-// andere (1) --> -8
diff --git a/src/components/PlayerDecks.tsx b/src/components/PlayerDecks.tsx
new file mode 100644
index 0000000..8eb89a6
--- /dev/null
+++ b/src/components/PlayerDecks.tsx
@@ -0,0 +1,86 @@
+import { FC, useState, useEffect } from "react";
+import { socket } from "../socket";
+import { Vector3 } from "three";
+
+import { createPlayerCards as createPlayerDeck } from "../objects/cards";
+import PlayerCard from "./PlayerCard";
+import { PlayerVisualDeck, Player } from "../types/gameTypes";
+import CardCache from "./CardCache";
+
+type PlayerDecksProps = {
+ playersData: Player[];
+};
+
+const PlayerDecks: FC = ({ playersData }) => {
+ const [visualPlayerDecks, setVisualPlayerDecks] = useState<
+ PlayerVisualDeck[]
+ >([]);
+
+ const updatePlayerCards = (playersData: Player[]) => {
+ const visualPlayerDecks: PlayerVisualDeck[] = [];
+ const currentVisualPlayerDeck: PlayerVisualDeck[] = [];
+ let nonCurrentPlayerIndex = 1;
+ playersData.forEach((player) => {
+ const positionOffset = 14;
+ const playerVisualDeck: PlayerVisualDeck = {
+ player,
+ visualDeck: [],
+ };
+ if (player.socketId === socket.id) {
+ playerVisualDeck.visualDeck = createPlayerDeck(
+ player.deck,
+ new Vector3(0, 20, positionOffset)
+ );
+ currentVisualPlayerDeck.push(playerVisualDeck);
+ } else {
+ const playerOffset = positionOffset + nonCurrentPlayerIndex * -20;
+ playerVisualDeck.visualDeck = createPlayerDeck(
+ player.deck,
+ new Vector3(0, 20, playerOffset)
+ );
+ visualPlayerDecks.push(playerVisualDeck);
+ nonCurrentPlayerIndex++;
+ }
+ });
+ setVisualPlayerDecks([...currentVisualPlayerDeck, ...visualPlayerDecks]);
+ };
+
+ useEffect(() => {
+ if (!playersData) return;
+ updatePlayerCards(playersData);
+ }, [playersData]);
+
+ if (!visualPlayerDecks) return null;
+
+ return (
+ <>
+ {visualPlayerDecks.map((visualPlayerDeck, playerIndex) => (
+ <>
+ {visualPlayerDeck.visualDeck.map((column, columnIndex) => (
+ <>
+ {column.map((card, cardIndex) => (
+
+ ))}
+ >
+ ))}
+
+ >
+ ))}
+ >
+ );
+};
+
+export default PlayerDecks;
+// ich (0) --> 4
+// andere (1) --> -8
diff --git a/src/components/SessionManager.tsx b/src/components/SessionManager.tsx
index 83ed160..5056c99 100644
--- a/src/components/SessionManager.tsx
+++ b/src/components/SessionManager.tsx
@@ -13,6 +13,8 @@ type SessionManagerProps = {
showStartGameButton: boolean;
};
+type SessionResponse = "success" | "error:full" | "error:running";
+
export const SessionManager: FC = ({
isConnected,
clientsInRoom,
@@ -25,9 +27,11 @@ export const SessionManager: FC = ({
function joinSession(event: React.FormEvent) {
event.preventDefault();
- socket.emit("join-session", sessionField);
- setSession(sessionField);
- setSessionField("");
+ socket.emit("join-session", sessionField, (response: SessionResponse) => {
+ if (response !== "success") return;
+ setSession(sessionField);
+ setSessionField("");
+ });
}
function leaveSession(sessionName: string) {
@@ -52,10 +56,10 @@ export const SessionManager: FC = ({
>
- Skyjo
+ Skylo
- Play Skyjo online with your friends!
+ Play Skylo online with your friends!
{!isActiveSession && (
@@ -64,7 +68,7 @@ export const SessionManager: FC
= ({
htmlFor="first_name"
className="block mb-2 text-sm font-medium text-white"
>
- Join Skyjo Session
+ Join Skylo Session
= ({ gameData }) => {
- const containerRef = useRef
(null);
- const cardsRef = useRef([]);
- const tableModel = useGLTF("/models/table.glb");
- const heightProportion = 1.25;
-
- function extractCurrentPlayer(gameData: Game | null): Player | undefined {
- if (!gameData) return undefined;
- return gameData.players.find((player) => player.socketId === socket.id);
- }
-
- function disposeMesh(mesh: THREE.Mesh) {
- if (mesh.material instanceof Material) {
- mesh.material.dispose();
- } else if (Array.isArray(mesh.material)) {
- for (const material of mesh.material) {
- material.dispose();
- }
- }
-
- mesh.geometry.dispose();
- }
-
- useEffect(() => {
- const container = containerRef.current;
- const scene = new Scene();
- const camera = new PerspectiveCamera(
- 75,
- window.innerWidth / (window.innerHeight / heightProportion),
- 0.1,
- 1000
- );
-
- const renderer = new WebGLRenderer();
-
- renderer.setSize(window.innerWidth, window.innerHeight / heightProportion);
- container && container.appendChild(renderer.domElement);
-
- // Objects
- const cubeCenter = createCube(new Vector3(1, 1, 1), 0x00ff00);
- cubeCenter.position.set(0, 20, 0);
-
- const cubeTL = createCube(new Vector3(1, 1, 1), 0x00ff00);
- cubeTL.position.set(-10, 20, -15);
-
- const cubeTR = createCube(new Vector3(1, 1, 1), 0x00ff00);
- cubeTR.position.set(10, 20, -15);
-
- const cubeBL = createCube(new Vector3(1, 1, 1), 0x00ff00);
- cubeBL.position.set(-10, 20, 15);
-
- const cubeBR = createCube(new Vector3(1, 1, 1), 0x00ff00);
- cubeBR.position.set(10, 20, 15);
-
- scene.add(cubeCenter, cubeBL, cubeBR, cubeTL, cubeTR);
-
- // Cards
- /*const initialCards: Card[] = [];
- for (let i = 1; i < 13; i++) {
- initialCards.push({ id: i, name: `${i} Card`, value: i as CardValue });
- }
-
- const playerCards = createPlayerCards(initialCards, new Vector3(0, 20, 0));
-
- scene.add(...playerCards);*/
-
- const currentPlayer = extractCurrentPlayer(gameData);
- if (currentPlayer && !cardsRef.current.length) {
- cardsRef.current = createPlayerCards(
- currentPlayer.cards,
- new Vector3(0, 20, 0)
- );
- scene.add(...cardsRef.current);
- }
-
- // Camera
- camera.position.set(0, 45, 10);
- camera.lookAt(0, 0, 0);
-
- // Orbit Controls
- const orbit = new OrbitControls(camera, renderer.domElement);
- orbit.update();
-
- // Lights
- const directionalLight = new DirectionalLight(0xffffff, 0.8);
- directionalLight.position.set(0, 50, 20);
- scene.add(directionalLight);
-
- directionalLight.castShadow = true;
- directionalLight.shadow.mapSize.width = 1024;
- directionalLight.shadow.mapSize.height = 1024;
-
- const ambientLight = new AmbientLight(0xa3a3a3, 0.3);
- scene.add(ambientLight);
-
- // Import models
- const table = tableModel.scene;
- scene.add(table);
- // table.rotateY(Math.PI / 2);
- table.scale.set(2, 2, 2);
- table.position.set(0, 1.8, 0);
-
- table.traverse(function (node: Object3D) {
- if (node instanceof Mesh) {
- // node.castShadow = true;
- node.receiveShadow = true;
- }
- });
-
- // Helpers
- const gridHelper = new GridHelper(100, 100);
- scene.add(gridHelper);
-
- const axesHelper = new AxesHelper(5);
- scene.add(axesHelper);
-
- const directionalLightHelper = new DirectionalLightHelper(
- directionalLight,
- 5
- );
- scene.add(directionalLightHelper);
-
- // Animation
- const animate = () => {
- requestAnimationFrame(animate);
- // cube.rotation.x += 0.01;
- // cube.rotation.y += 0.01;
- const currentPlayer = extractCurrentPlayer(gameData);
- if (currentPlayer) {
- if (cardsRef.current.length === 0) {
- cardsRef.current = createPlayerCards(
- currentPlayer.cards,
- new Vector3(0, 20, 0)
- );
- scene.add(...cardsRef.current);
- } else {
- cardsRef.current.forEach((card, index) => {
- if (card.name !== currentPlayer.cards[index]?.name) {
- disposeMesh(card);
- scene.remove(card);
- cardsRef.current[index] = createCard(
- currentPlayer.cards[index],
- card.position
- );
- scene.add(cardsRef.current[index]);
- }
- });
- }
- //const cards = createPlayerCards(currentPlayer.cards);
- //scene.add(...cards);
- }
-
- renderer.render(scene, camera);
- };
-
- console.log("Animate");
- animate();
-
- return () => {
- // Clean up on unmount
- renderer.dispose();
- // scene.dispose();
- // material.dispose();
- // geometry.dispose();
- container && container.removeChild(renderer.domElement);
- };
- }, [gameData]);
-
- return ;
-};
-
-export default ThreeScene;
diff --git a/src/objects/cards.ts b/src/objects/cards.ts
index 3bbe5b0..21fcc4c 100644
--- a/src/objects/cards.ts
+++ b/src/objects/cards.ts
@@ -6,9 +6,10 @@ import {
Vector3,
Mesh,
Object3DEventMap,
+ Object3D,
} from "three";
-import { Card } from "../types/gameTypes";
+import { Card, Deck, VisualColumn, VisualDeck } from "../types/gameTypes";
const textureLoader = new TextureLoader();
const cardSize = 5;
@@ -18,7 +19,7 @@ const cardGeometry = new BoxGeometry(
cardSize * 0.6
);
-const getCardTexture = (value: number | string) => {
+const getCardTexture = (value: number | null) => {
let cardTexture;
switch (value) {
case -2:
@@ -66,7 +67,7 @@ const getCardTexture = (value: number | string) => {
case 12:
cardTexture = textureLoader.load("/textures/card-12.png");
break;
- case "X":
+ case null:
cardTexture = textureLoader.load("/textures/card-back.png");
break;
default:
@@ -78,54 +79,53 @@ const getCardTexture = (value: number | string) => {
};
export const createCard = (
- cardData: Card,
+ card: Card,
position: Vector3,
faceUp: boolean = false
) => {
const cardMaterial = [
new MeshBasicMaterial(),
new MeshBasicMaterial(),
- new MeshBasicMaterial({ map: getCardTexture("X") }), // X = backside
- new MeshBasicMaterial({ map: getCardTexture(cardData.value) }),
+ new MeshBasicMaterial({ map: getCardTexture(null) }), // X = backside
+ new MeshBasicMaterial({ map: getCardTexture(card) }),
new MeshBasicMaterial(),
new MeshBasicMaterial(),
];
- const card = new Mesh(cardGeometry, cardMaterial);
- card.name = cardData.name;
- card.position.copy(position);
+ const visualCard = new Mesh(cardGeometry, cardMaterial);
+ visualCard.name = card !== null ? card.toString() : "Facedown card";
+ visualCard.position.copy(position);
if (faceUp) {
- card.rotation.x = Math.PI;
- console.log("faceUp");
+ visualCard.rotation.x = Math.PI;
}
- return card;
+ return visualCard;
};
-export const createPlayerCards = (
- cards: Card[],
- positionReference: Vector3
-) => {
- const playerCards: Mesh<
- BoxGeometry,
- MeshBasicMaterial[],
- Object3DEventMap
- >[] = [];
- cards.forEach((card, index) => {
- const cardPositionX = positionReference.x + (index % 4) * 4 - 6;
- const cardPositionY = positionReference.y;
- const cardPositionZ =
- positionReference.z + (Math.ceil((index + 1) / 4) - 1) * 4 - 8;
+export const createPlayerCards = (deck: Deck, positionReference: Vector3) => {
+ const playerDeck: Object3D[][] = [];
- const cardPosition = new Vector3(
- cardPositionX,
- cardPositionY,
- cardPositionZ
- );
- const playerCard = createCard(card, cardPosition);
- playerCards.push(playerCard);
+ let visualColumn: Object3D[] = [];
+ deck.forEach((column, columnIndex) => {
+ column.forEach((card, cardIndex) => {
+ const cardPositionX = positionReference.x + columnIndex * 4 - 6;
+ const cardPositionY = positionReference.y;
+ const cardPositionZ = positionReference.z + cardIndex * 4 - 8;
+
+ const cardPosition = new Vector3(
+ cardPositionX,
+ cardPositionY,
+ cardPositionZ
+ );
+ const playerCard = createCard(card, cardPosition);
+ visualColumn.push(playerCard);
+ if (cardIndex === 2) {
+ playerDeck.push(visualColumn as VisualColumn);
+ visualColumn = [];
+ }
+ });
});
- return playerCards;
+ return playerDeck as VisualDeck;
};
export const createCardStaple = (
diff --git a/src/objects/gameObjects.ts b/src/objects/gameObjects.ts
deleted file mode 100644
index e69de29..0000000
diff --git a/src/types/gameTypes.ts b/src/types/gameTypes.ts
index 8336f2c..71cb4bd 100644
--- a/src/types/gameTypes.ts
+++ b/src/types/gameTypes.ts
@@ -4,8 +4,8 @@ export type Player = {
id: number;
socketId: string;
name: string;
- cards: Card[];
- knownCardPositions: boolean[];
+ deck: Deck;
+ knownCardPositions: KnownCardsColumn[];
playersTurn: boolean;
cardCache: Card | null;
tookDispiledCard: boolean;
@@ -15,12 +15,21 @@ export type Player = {
place: number;
};
-export type PlayerWithVisualCards = {
+export type PlayerVisualDeck = {
player: Player;
- cards: Object3D[];
+ visualDeck: VisualDeck;
};
-export type CardValue =
+export type VisualColumn = [Object3D, Object3D, Object3D];
+
+export type VisualDeck = VisualColumn[];
+
+export type Column = [Card, Card, Card];
+export type KnownCardsColumn = [boolean, boolean, boolean];
+
+export type Deck = Column[];
+
+export type Card =
| -2
| -1
| 0
@@ -36,13 +45,7 @@ export type CardValue =
| 10
| 11
| 12
- | "X";
-
-export type Card = {
- id: number;
- name: string;
- value: CardValue;
-};
+ | null;
export type CardStack = {
cards: Card[];