[로데시] 개발
[대학전쟁3] 양면빙고 웹 개발 03 - 타일 착수 (place) 본문
반응형
0️⃣ 지난 번까지..
대학전쟁에 나온 '양면빙고 (double sided bingo)' 게임을 보고 ☰ 양면빙고 (double-sided-bingo) 개발 과정
1️⃣ TileItem 정리
빙고판을 만들기 전에 앞서서, TileItem 코드를 정리하고자 한다.📌 SortableTileItem.js 코드
// 타일 내 이동 가능
const SortableTileItem = ({ tile, onFlip }) => {
const {
attributes, listeners, setNodeRef, transform, transition, isDragging,
} = useSortable({
id: tile.key,
data: {
type: "TILE",
tile,
},
});
const style = {
transform: CSS.Transform.toString(transform),
transition,
opacity: isDragging ? 0 : 1,
};
return (
<div ref={setNodeRef} style={style}>
<div {...attributes} {...listeners}>
<TileItem
tileId = {tile.id}
isFlipped = {tile.isFlipped}
onClick = {onFlip}
/>
</div>
</div>
);
};
export default SortableTileItem;
// 타일이 어떻게 보이는가
const TileItem = ({ tileId, isFlipped, onClick }) => {
return (
<div className="TileItem" onClick={onClick}>
<img
className="tile-img"
src={getTileImgById(tileId)}
alt=""
draggable={false}
/>
{isFlipped}
</div>
);
};
export default React.memo(TileItem);
2️⃣ 빙고판 만들기
이제 이름만 '빙고'가 아닌 드디어 '빙고'라 부를 수 있는 빙고판을 만들 차례이다.// 빙고 칸을 담당
const BingoCell = ({ id, tile }) => {
const { setNodeRef } = useDroppable({
id,
data: { type: "BINGO_CELL" },
});
return (
<div ref={setNodeRef} className="BingoCell">
{tile && <TileItem tileId={tile.id} isFlipped />}
</div>
);
};
export default BingoCell;
// 빙고 판을 담당
const BingoBoard = ({ boardTiles }) => {
const cells = Array.from({ length: 16 }, (_, i) => i);
return (
<div className="BingoBoard">
{cells.map((cellId) => (
<BingoCell
key={cellId}
id={cellId}
tile={boardTiles[cellId]}
/>
))}
</div>
);
};
export default React.memo(BingoBoard);
3️⃣ 착수
타일 list 내 이동 & 타일 list에서 빙고판으로 착수(place)는 모두 동일 동작이므로📌 App.js 코드
const handleDragStart = (event) => {
const { active } = event;
const tile = tiles.find((t) => t.key === active.id);
setActiveTile(tile);
};
// 이동 끝
const handleDragEnd = (event) => {
const { active, over } = event;
// TileList 내부 이동
if (over?.data?.current?.type === "TILE") {
setTiles((prev) => {
const oldIndex = prev.findIndex(t => t.key === active.id);
const newIndex = prev.findIndex(t => t.key === over.id);
return arrayMove(prev, oldIndex, newIndex);
});
}
// BingoBoard 착수
if (over?.data?.current?.type === "BINGO_CELL") {
setBoardTiles((prev) => ({
...prev,
[over.id]: active.data.current.tile,
}));
setTiles((prev) => prev.filter(t => t.key !== active.id));
}
setActiveTile(null);
};
4️⃣ 문제 & 해결
❓ 문제 - 이동중인 타일이 보이지 않음<DndContext></DndContext>
<DragOverlay></DragOverlay>
<DndContext>
<DragOverlay></DragOverlay>
</DndContext>
src={getTileImgById(tileId)}
src={getTileImgById(isFlipped ? getPairedTileId(tileId) : tileId)}
{tile && <TileItem tileId={tile.id} isFlipped/>}
{tile && <TileItem tileId={tile.id} isFlipped={tile.isFlipped} />}
💡 App.js 코드
const handleDragEnd = (event) => {
const { active, over } = event;
setActiveTile(null);
if (!over) return;
const activeTile = tiles.find(t => t.key === active.id);
if (!activeTile) return;
// TileList 내부 이동
if (over.data.current?.type === "TILE") {
const oldIndex = tiles.findIndex(t => t.key === active.id);
const newIndex = tiles.findIndex(t => t.key === over.id);
if (oldIndex !== newIndex) {
setTiles(prev => arrayMove(prev, oldIndex, newIndex));
}
}
// BingoBoard 착수
if (over.data.current?.type === "BINGO_CELL") {
const cellId = over.id;
// 이미 착수된 타일이 있다 -> 다시 타일 리스트로
if (boardTiles[cellId]) {
return;
}
// 빈칸일 때만 착수
setBoardTiles(prev => {
const next = [...prev];
next[cellId] = activeTile;
return next;
});
setTiles(prev => prev.filter(t => t.key !== active.id));
return;
}
setActiveTile(null);
};
5️⃣ 앞으로...
이제 양면빙고의 주기능 중 하나인 '착수(place)'를 끝냈다.

반응형
'개인 개발 > 대학전쟁' 카테고리의 다른 글
| [대학전쟁] 양면빙고 웹 개발 05 - 빙고 판단, player 2명 (0) | 2026.01.20 |
|---|---|
| [대학전쟁] 양면빙고 웹 개발 04 - 타일 뒤집기 (flip), 이동 (move) (1) | 2026.01.18 |
| [대학전쟁3] 양면빙고 웹 개발 02 - 타일 list 내 이동 (0) | 2026.01.14 |
| [대학전쟁3] 양면빙고 웹 개발 01 - 타일 list, 타일 뒤집기 (0) | 2026.01.12 |
| [JAVA] 123을 도레미로 변환해서 헌트릭스의 골든 Golden 악보 만들기 (무료) (0) | 2025.11.08 |