261 lines
11 KiB
React
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
|