/** * Tile Set Selector Panel - Left panel for selecting tiles * 瓦片集选择面板 - 左侧面板用于选择瓦片 */ import React, { useState, useCallback, useMemo } from 'react'; import { Paintbrush, Eraser, PaintBucket, ChevronDown, Grid3x3, Search, Box, Square, BoxSelect } from 'lucide-react'; import { useTilemapEditorStore, type TilemapToolType } from '../../stores/TilemapEditorStore'; import { TilesetPreview } from '../TilesetPreview'; import { TileAnimationEditor } from './TileAnimationEditor'; import type { ITilesetData, ITileAnimation } from '@esengine/tilemap'; import '../../styles/TileSetSelectorPanel.css'; interface TilesetOption { name: string; path: string; } interface TileSetSelectorPanelProps { tilesets: TilesetOption[]; activeTilesetIndex: number; activeTileset?: ITilesetData; tilesetImage?: HTMLImageElement | null; onTilesetChange: (index: number) => void; onAddTileset: () => void; onTileAnimationChange?: (tileId: number, animation: ITileAnimation | null) => void; } export const TileSetSelectorPanel: React.FC = ({ tilesets, activeTilesetIndex, activeTileset, tilesetImage, onTilesetChange, onAddTileset, onTileAnimationChange }) => { const { currentTool, setCurrentTool, tilesetImageUrl, tileWidth, tileHeight, tilesetColumns, tilesetRows, selectedTiles, editingCollision, setEditingCollision } = useTilemapEditorStore(); const [showTilesetDropdown, setShowTilesetDropdown] = useState(false); const [previewZoom, _setPreviewZoom] = useState(1); const [editingAnimationTileId, setEditingAnimationTileId] = useState(null); // Get animated tile IDs from tileset const animatedTileIds = useMemo(() => { const ids = new Set(); if (activeTileset?.tiles) { for (const tile of activeTileset.tiles) { if (tile.animation && tile.animation.frames.length > 0) { ids.add(tile.id); } } } return ids; }, [activeTileset]); // Get current animation for editing tile const editingTileAnimation = useMemo(() => { if (editingAnimationTileId === null || !activeTileset?.tiles) return null; const tile = activeTileset.tiles.find(t => t.id === editingAnimationTileId); return tile?.animation ?? null; }, [editingAnimationTileId, activeTileset]); const handleEditAnimation = useCallback((tileId: number) => { setEditingAnimationTileId(tileId); }, []); const handleAnimationChange = useCallback((animation: ITileAnimation | null) => { if (editingAnimationTileId !== null && onTileAnimationChange) { onTileAnimationChange(editingAnimationTileId, animation); } }, [editingAnimationTileId, onTileAnimationChange]); const handleCloseAnimationEditor = useCallback(() => { setEditingAnimationTileId(null); }, []); const handleToolChange = useCallback((tool: TilemapToolType) => { setCurrentTool(tool); }, [setCurrentTool]); const { setShowCollision } = useTilemapEditorStore(); const handleToggleCollisionMode = useCallback((enabled: boolean) => { setEditingCollision(enabled); // 启用碰撞编辑时自动显示碰撞 if (enabled) { setShowCollision(true); } }, [setEditingCollision, setShowCollision]); const activeTilesetOption = tilesets[activeTilesetIndex]; return (
{/* Mode toggle */}
{/* Tool buttons */}
{/* Active Tile Set selector */}
{showTilesetDropdown && (
{tilesets.map((tileset, index) => ( ))}
)}
{/* Zoom and title header */}
缩放{previewZoom}:1 瓦片集选择器
{/* Tile preview area */}
{editingCollision ? (
碰撞编辑模式 使用画笔绘制碰撞区域 使用橡皮擦清除碰撞
) : tilesetImageUrl ? ( ) : (
)}
{/* Selection info */} {selectedTiles && (
已选择: {selectedTiles.width}×{selectedTiles.height}
)} {/* Animation Editor */} {editingAnimationTileId !== null && activeTileset && tilesetImage && ( )}
); }; export default TileSetSelectorPanel;