주사위판 배치 그리기 일부 구현.

This commit is contained in:
kimyu
2026-08-29 12:58:43 +09:00
parent d3000598c6
commit 7608b166b3
4 changed files with 105 additions and 11 deletions

77
app/game/diceplane.tsx Normal file
View File

@@ -0,0 +1,77 @@
'use client';
import { useState } from 'react';
type PlaneCell = { id: number; x: number; y: number; type: string };
const PLANE_SIZE = { width: 9, height: 7 } as const;
const CELL_TYPES = ['한잔', '안주', '모두한잔', '두잔', '벌칙1', '벌칙2'] as const;
function randomType() {
return CELL_TYPES[Math.floor(Math.random() * CELL_TYPES.length)];
}
/** 시계방향 둘레 칸. 모서리는 한 번만 넣어서 9x7 기준 28칸이 된다. */
function buildPerimeter(width: number, height: number): PlaneCell[] {
const cells: PlaneCell[] = [];
let id = 0;
for (let x = 0; x < width; x++) {
cells.push({ id: id++, x, y: 0, type: randomType() });
}
for (let y = 1; y < height; y++) {
cells.push({ id: id++, x: width - 1, y, type: randomType() });
}
for (let x = width - 2; x >= 0; x--) {
cells.push({ id: id++, x, y: height - 1, type: randomType() });
}
for (let y = height - 2; y >= 1; y--) {
cells.push({ id: id++, x: 0, y, type: randomType() });
}
return cells;
}
export default function DicePlane() {
const [dicePlaneArray] = useState(() =>
buildPerimeter(PLANE_SIZE.width, PLANE_SIZE.height),
);
return (
<div
style={{
display: 'grid',
gridTemplateColumns: `repeat(${PLANE_SIZE.width}, minmax(0, 1fr))`,
gridTemplateRows: `repeat(${PLANE_SIZE.height}, minmax(0, 1fr))`,
gap: 'clamp(6px, 1vw, 12px)',
padding: 'clamp(8px, 1.2vw, 16px)',
width: '100%',
height: '100%',
boxSizing: 'border-box',
}}
>
{dicePlaneArray.map((plane) => (
<div
key={plane.id}
style={{
gridColumn: plane.x + 1,
gridRow: plane.y + 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#e11d48',
color: 'white',
borderRadius: 8,
fontSize: 'clamp(11px, 1.6vw, 16px)',
fontWeight: 600,
textAlign: 'center',
padding: 4,
}}
>
{plane.type}
</div>
))}
</div>
);
}

12
app/game/page.tsx Normal file
View File

@@ -0,0 +1,12 @@
import DicePlane from './diceplane';
export default function GamePage() {
return (
<div className="relative h-screen w-screen overflow-hidden">
<DicePlane />
<h1 className="pointer-events-none absolute inset-0 flex items-center justify-center text-4xl font-bold">
Game
</h1>
</div>
);
}

View File

@@ -1,11 +0,0 @@
import React from 'react';
export default function Home() {
return (
<div>
<h1>Home</h1>
</div>
);
}

16
app/main/page.tsx Normal file
View File

@@ -0,0 +1,16 @@
import React from 'react';
import { useRouter } from 'next/navigation';
export default function MainPage() {
const router = useRouter();
return (
<div className="flex flex-col items-center justify-center h-screen">
<h1 className="text-4xl font-bold">주루마블!</h1>
<button className="bg-blue-500 text-white px-4 py-2 rounded-md" onClick={() => {
router.push('/game/page');
}}>시작하기</button>
</div>
);
}