Files
SerpentRace/SerpentRace_Frontend/src/pages/Game/GameScreen.jsx
T
2025-10-21 15:08:28 +02:00

261 lines
11 KiB
React

import React, { useState } from "react"
import { getVerticalOffset } from "../../utils/randomUtils"
import Dice from "../../utils/dice/Dice"
const GameScreen = () => {
const boardRows = 5
const boardCols = 20
const totalCells = boardRows * boardCols
const cellSize = 40
const cellMargin = 2.5
const rowSpacing = 70 // Extra spacing between rows
const topOffset = rowSpacing * 0.5 // Increase topOffset for more spacing
const bottomOffset = rowSpacing * 0.5 // Increase bottomOffset for more spacing
const boardWidthPx = boardCols * (cellSize + cellMargin * 2)
const boardHeightPx =
boardRows * (cellSize + cellMargin * 2 + rowSpacing) + topOffset + bottomOffset - rowSpacing
// Generate a snake-like path with vertical spacing and vertical offsets
const generateWindingPath = () => {
const path = []
let currentNum = 1
for (let row = 0; row < boardRows && currentNum <= totalCells; row++) {
// Calculate the y position with extra row spacing
const baseYPosition = topOffset + row * (cellSize + cellMargin * 2 + rowSpacing)
// If row number is even, go right; if odd, go left
if (row % 2 === 0) {
// Left to right
for (let col = 0; col < boardCols && currentNum <= totalCells; col++) {
path.push({
number: currentNum++,
x: col * (cellSize + cellMargin * 2),
y: baseYPosition + getVerticalOffset(currentNum - 1),
type: getFieldType(currentNum - 1),
})
}
} else {
// Right to left
for (let col = boardCols - 1; col >= 0 && currentNum <= totalCells; col--) {
path.push({
number: currentNum++,
x: col * (cellSize + cellMargin * 2),
y: baseYPosition + getVerticalOffset(currentNum - 1),
type: getFieldType(currentNum - 1),
})
}
}
}
return path
}
const getFieldType = (count) => {
if (count % 17 === 0) return "clover"
if (count % 13 === 0) return "bad"
if ((count + 5) % 13 === 0) return "good"
return "regular"
}
const [path, setPath] = useState(generateWindingPath())
const [players, setPlayers] = useState([
{ id: 1, name: "Béla", position: 34, score: 25, color: "bg-blue-600", emoji: "🐍" },
{ id: 2, name: "Juci", position: 50, score: 30, color: "bg-green-600", emoji: "🐢" },
{ id: 3, name: "Kati", position: 70, score: 15, color: "bg-purple-600", emoji: "🐇" },
{ id: 3, name: "Fürtös", position: 68, score: 14, color: "bg-yellow-600", emoji: "😂" },
])
// New: selected dice value from dropdown (null = none)
const [selectedDice, setSelectedDice] = useState(null)
// Sort players by position in descending order
const sortedPlayers = [...players].sort((a, b) => b.position - a.position)
// Handle dice roll completion
const handleDiceRoll = (value) => {
console.log("Rolled:", value)
// reset dropdown selection after roll
setSelectedDice(null)
// You can add logic here to move the current player based on the dice value
}
console.log("Generated path length:", path.length)
const getFieldStyle = (type) => {
switch (type) {
case "clover":
return "bg-teal-700 border-teal-500 shadow-teal-800"
case "bad":
return "bg-red-800 border-red-600 shadow-red-900"
case "good":
return "bg-blue-800 border-blue-600 shadow-blue-900"
default:
return "bg-gray-800 border-gray-600 shadow-gray-900"
}
}
const getPlayerPosition = (playerPosition) => {
const field = path.find((p) => p.number === playerPosition)
return field ? { top: `${field.y}px`, left: `${field.x}px` } : { top: 0, left: 0 }
}
// Function to get medal style based on rank
const getMedalStyle = (rank) => {
switch (rank) {
case 1:
return "bg-yellow-400 text-yellow-900 border-yellow-500 shadow-yellow-600"
case 2:
return "bg-gray-400 text-gray-900 border-gray-500 shadow-gray-600"
case 3:
return "bg-orange-500 text-orange-900 border-orange-600 shadow-orange-700"
default:
return "bg-gray-700 text-gray-300 border-gray-600 shadow-gray-800"
}
}
return (
<div className="p-4 bg-gradient-to-br from-gray-900 via-gray-800 to-teal-900 min-h-screen flex items-center justify-center">
<div className="w-full">
<div className="flex flex-col md:flex-row gap-6 justify-center">
{/* Game Board */}
<div className="relative bg-gray-800 p-6 rounded-2xl shadow-xl border border-teal-700 flex flex-col items-center justify-center overflow-hidden">
{/* Háttér */}
<div className="absolute w-full h-full opacity-10 pointer-events-none overflow-hidden">
{[...Array(35)].map((_, i) => (
<div
key={i}
className="absolute rounded-full bg-teal-600 animate-pulse8"
style={{
width: Math.random() * 120 + 40 + "px",
height: Math.random() * 120 + 40 + "px",
top: Math.random() * 100 + "%",
left: Math.random() * 100 + "%",
transform: "translate(-50%, -50%)",
}}
></div>
))}
</div>
<div className="relative" style={{ height: `${boardHeightPx}px`, width: `${boardWidthPx}px` }}>
{/* Mezők */}
{path.map((field) => (
<div
key={field.number}
className={`absolute w-10 h-10 border-2 flex items-center justify-center transition-all shadow-md hover:scale-110 ${getFieldStyle(
field.type
)}`}
style={{
top: `${field.y}px`,
left: `${field.x}px`,
width: `${cellSize}px`,
height: `${cellSize}px`,
margin: `${cellMargin}px`,
}}
>
<span className="text-gray-300 text-sm font-bold">{field.number}</span>
</div>
))}
{/* Player tokens */}
{players.map((player) => (
<div
key={player.id}
className={`absolute w-6 h-6 ${player.color} rounded-full border-2 border-white shadow-lg flex items-center justify-center text-white text-xs font-bold z-10 animate-bounce`}
style={{
...getPlayerPosition(player.position),
transform: "translate(18px, 18px)",
}}
>
{player.emoji}
</div>
))}
</div>
{/* Game information */}
{/* <div className="bg-white rounded-xl p-2 shadow-lg border border-indigo-100 max-w-3xl mx-auto mt-4 z-10">
<p className="text-gray-600 text-sm text-center">
<span className="inline-flex items-center mx-2"><span className="w-3 h-3 bg-white border border-gray-300 rounded-full mr-1"></span> Sima</span>
<span className="inline-flex items-center mx-2"><span className="w-3 h-3 bg-green-200 border border-green-500 rounded-full mr-1"></span> Lóhere</span>
<span className="inline-flex items-center mx-2"><span className="w-3 h-3 bg-red-200 border border-red-500 rounded-full mr-1"></span> Rossz</span>
<span className="inline-flex items-center mx-2"><span className="w-3 h-3 bg-blue-200 border border-blue-500 rounded-full mr-1"></span> Jó</span>
</p>
</div> */}
</div>
{/* Right sidebar */}
<div className="flex-1 max-w-md">
<div className="bg-gray-800 rounded-xl p-4 shadow-lg mb-4 border border-teal-700">
<h2 className="text-xl font-semibold mb-3 text-teal-300">Játékosok</h2>
{sortedPlayers.map((player, index) => (
<div
key={player.id}
className="flex items-center mb-3 p-2 bg-gray-900 rounded-lg hover:bg-gray-700 transition-colors"
>
<div
className={`w-8 h-8 ${player.color} rounded-full mr-3 flex items-center justify-center text-white text-sm font-bold shadow-md`}
>
{player.emoji}
</div>
<div className="flex-1">
<div className="font-medium text-sm text-gray-300 flex items-center">
{player.name}
<span
className={`ml-2 px-2 py-1 rounded-full border text-xs font-bold shadow-md ${getMedalStyle(
index + 1
)}`}
>
{index + 1 === 1
? "🥇 1st"
: index + 1 === 2
? "🥈 2nd"
: index + 1 === 3
? "🥉 3rd"
: `${index + 1}th`}
</span>
</div>
<div className="text-xs text-gray-500">
Pozíció: {player.position} Pontszám: {player.score}
</div>
</div>
</div>
))}
</div>
{/* Dice Container */}
<div className="bg-gray-800 rounded-xl p-4 shadow-lg border border-teal-700 text-center">
<h2 className="text-xl font-semibold mb-3 text-teal-300">Dobókocka</h2>
<p className="text-gray-300 text-sm mb-4">
Kattints a kockára dobáshoz vagy válassz egy számot az alábbiból!
</p>
{/* Dropdown to select number 1-6 (triggers animated roll to that number) */}
<div className="mb-3">
<select
value={selectedDice ?? ""}
onChange={(e) => {
const v = e.target.value ? Number(e.target.value) : null
setSelectedDice(v)
}}
className="bg-gray-900 text-gray-200 rounded-md p-2 border border-gray-700"
>
<option value="">Válassz számot...</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</select>
</div>
<Dice onRoll={handleDiceRoll} selectedValue={selectedDice} />
</div>
</div>
</div>
</div>
</div>
)
}
export default GameScreen