# game-map **Repository Path**: xkpro/game-map ## Basic Information - **Project Name**: game-map - **Description**: 游戏地图 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-02 - **Last Updated**: 2026-05-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # GameMap 互动地图通用工具 GameMap 是一个基于 Leaflet 的互动地图通用工具库,支持瓦片地图和单图模式,提供标注管理、区域绘制、分类筛选、搜索定位等完整功能。 ## 项目结构 ```txt map/ ├── gamemap.js # 打包后的独立库文件(直接引入即可) ├── src/ # 模块化源码(开发用) │ ├── index.js # 主入口,GameMap 类 │ ├── config.js # 默认配置与合并工具 │ ├── constants.js # 调色板、图标映射、缩放级别 │ ├── data-builder.js # 数据转换模块 │ ├── map-core.js # 地图核心初始化 │ ├── markers.js # 标注管理模块 │ ├── regions.js # 区域管理模块 │ ├── sidebar.js # 侧边栏 UI 模块 │ ├── edit-mode.js # 编辑模式模块 │ └── utils.js # 工具函数 ├── data/ # 数据文件目录 │ ├── point-series.js # 分类系列数据 │ ├── points.js # 标注点数据 │ └── senses.js # 区域数据 ├── tiles/ # 瓦片图片目录 ├── index.html # 使用示例 ├── style.css # 样式文件 ├── app.js # 旧版单文件(已弃用) └── data.js # 旧版示例数据(已弃用) ``` --- ## 快速开始 ### 1. 引入依赖 在 HTML 中引入 Leaflet、Font Awesome 和 GameMap: ```html ``` ### 2. 准备 HTML 容器 ```html
...
...
...
``` ### 3. 创建地图实例 ```javascript var map = GameMap.create('map', { mode: 'tiles', mapWidth: 8192, mapHeight: 8192, tiles: { url: './tiles/{z}/{x}/{y}.png', tileSize: 256, maxZoom: 6, paddedWidth: 8192, paddedHeight: 8192, }, }, { series: mySeriesData, points: myPointsData, senses: mySensesData, }); ``` --- ## 配置参数 ### 完整配置项 ```javascript { mode: 'tiles', // 'tiles' 瓦片模式 | 'image' 单图模式 mapWidth: 8192, // 地图宽度(像素) mapHeight: 8192, // 地图高度(像素) image: { // image 模式配置 url: './map.jpg', // 底图文件路径 }, tiles: { // tiles 模式配置 url: './tiles/{z}/{x}/{y}.png', // 瓦片路径模板 tileSize: 256, // 瓦片尺寸 maxZoom: 6, // 最大缩放级别 paddedWidth: 8192, // 填充后宽度 paddedHeight: 8192, // 填充后高度 }, view: { // 视图配置 minZoom: 3, // 最小缩放 maxZoom: 6, // 最大缩放 defaultZoom: 1, // 默认缩放 zoomSnap: 0.25, // 缩放步进 zoomDelta: 0.5, // 缩放增量 wheelPxPerZoomLevel: 50, // 鼠标滚轮灵敏度 maxBoundsViscosity: 1.0, // 边界弹性 }, marker: { // 标注配置 flyToZoom: 4, // 飞行定位缩放级别 flyToDuration: 1.0, // 飞行动画时长(秒) popupDelay: 600, // 弹窗延迟(毫秒) }, sidebar: { // 侧边栏配置 position: 'right', // 'left' | 'right' }, title: '互动游戏地图', // 地图标题 } ``` ### image 模式 适用于小尺寸地图,直接加载单张图片: ```javascript GameMap.create('map', { mode: 'image', mapWidth: 5824, mapHeight: 3264, image: { url: './map.jpg' }, view: { minZoom: -1, maxZoom: 4, defaultZoom: 0 }, }, userData); ``` ### tiles 模式 适用于大尺寸地图,使用瓦片金字塔加载: ```javascript GameMap.create('map', { mode: 'tiles', mapWidth: 8192, mapHeight: 8192, tiles: { url: './tiles/{z}/{x}/{y}.png', tileSize: 256, maxZoom: 5, paddedWidth: 8192, paddedHeight: 8192, }, }, userData); ``` **关键约束**:`paddedWidth` 必须等于 `tileSize × 2^maxZoom` ### 切割瓦片 ```bash python tile_cutter.py map.png --pad-power2 --max-zoom 5 --output ./tiles ``` --- ## 数据格式 GameMap 支持两种数据传入方式: ### 方式一:原始数据格式(自动转换) 传入 `series`、`points`、`senses` 原始数据,GameMap 会自动转换为内部格式: ```javascript GameMap.create('map', config, { series: [ { seriesId: '1', seriesName: '传送点', defaultShow: true, children: [ { seriesId: '2', seriesName: '界碑', defaultShow: true }, { seriesId: '30', seriesName: '天涯客', defaultShow: false }, ], }, ], points: [ { pointId: '20101', name: '竹隐居', x: -2388.72, y: -2779.33, series: ['2'], layer: '0', }, ], senses: [ { name: '清河', x: -1297.01, y: -2989.88, children: [ { name: '百草野', x: -1918.72, y: -2808.29, children: [...] }, ], }, ], }); ``` #### series 数据结构 | 字段 | 类型 | 说明 | | -- | -- | -- | | seriesId | string | 分类组 ID | | seriesName | string | 分类组名称 | | defaultShow | boolean | 是否默认显示 | | children | array | 子分类列表 | | children[].seriesId | string | 子分类 ID | | children[].seriesName | string | 子分类名称 | | children[].posterUrl | string | 海报图片 URL(可选) | | children[].defaultShow | boolean | 子分类是否默认显示 | #### points 数据结构 | 字段 | 类型 | 说明 | | -- | -- | -- | | pointId | string | 点位唯一 ID | | name | string | 点位名称 | | x | number | X 坐标 | | y | number | Y 坐标 | | series | array | 所属分类 ID 列表 | | layer | string | 层级('0' 为默认层) | | icon | string | 自定义图标 URL(可选) | #### senses 数据结构 区域数据为树形结构,每个有 children 的节点会自动生成椭圆区域: | 字段 | 类型 | 说明 | | -- | -- | -- | | name | string | 区域名称 | | x | number | 中心 X 坐标 | | y | number | 中心 Y 坐标 | | children | array | 子区域列表 | ### 方式二:直接传入内部格式 跳过自动转换,直接传入处理好的数据: ```javascript GameMap.create('map', config, { categoryGroups: [ { id: 'landmark', label: '地标', icon: 'fa-landmark', children: ['city', 'village'], defaultShow: true, }, ], categories: { city: { label: '城镇', icon: 'fa-city', color: '#3b82f6', bgColor: 'rgba(59, 130, 246, 0.15)', group: 'landmark', }, }, locations: [ { id: 1, name: '星辰王都', type: 'city', x: 2900, y: 1630, description: '王都描述' }, ], regions: [ { name: '清河', coords: [[lat1, lng1], [lat2, lng2], ...], color: '#3b82f6' }, ], }); ``` #### categoryGroups 结构 | 字段 | 类型 | 说明 | | -- | -- | -- | | id | string | 分组 ID | | label | string | 分组显示名 | | icon | string | Font Awesome 图标类名 | | children | array | 子分类 ID 列表 | | defaultShow | boolean | 是否默认显示 | #### categories 结构 | 字段 | 类型 | 说明 | | -- | -- | -- | | label | string | 分类显示名 | | icon | string | Font Awesome 图标类名 | | color | string | 主题色(HEX) | | bgColor | string | 背景色(RGBA) | | group | string | 所属分组 ID | | defaultShow | boolean | 是否默认显示 | #### locations 结构 | 字段 | 类型 | 说明 | | -- | -- | -- | | id | number | 唯一 ID | | name | string | 地点名称 | | type | string | 分类 ID | | x | number | X 坐标 | | y | number | Y 坐标 | | description | string | 描述(可选) | | stats | object | 统计信息(可选) | | zoom | number | 自定义缩放级别(可选) | #### regions 结构 | 字段 | 类型 | 说明 | | -- | -- | -- | | name | string | 区域名称 | | coords | array | 多边形坐标 [[lat, lng], ...] | | color | string | 区域颜色 | --- ## API 接口 ### 创建实例 ```javascript var map = new GameMap(containerId, config, data); var map = GameMap.create(containerId, config, data); // 等价 ``` | 参数 | 类型 | 说明 | | -- | -- | -- | | containerId | string | 地图容器 DOM ID(通常为 'map') | | config | object | 配置参数(与默认配置合并) | | data | object | 地图数据 | ### 数据获取 | 方法 | 返回值 | 说明 | | -- | -- | -- | | `getMap()` | L.Map | Leaflet 地图实例 | | `getConfig()` | object | 当前配置 | | `getCategories()` | object | 分类定义 | | `getCategoryGroups()` | array | 分类组列表 | | `getLocations()` | array | 原始标注列表 | | `getRegions()` | array | 区域列表 | | `getCustomMarkers()` | array | 用户自定义标注 | | `getCustomRegions()` | array | 用户自定义区域 | ### 导航与交互 ```javascript map.flyTo(locationId); // 飞行定位到指定地点 map.search('关键词'); // 搜索地点 map.filterByType('city', true); // 按类型筛选(true=显示,false=隐藏) map.showAll(); // 显示所有分类 map.hideAll(); // 隐藏所有分类 ``` ### 编辑模式 ```javascript map.enterEditMode(); // 进入编辑模式 map.exitEditMode(); // 退出编辑模式 ``` 编辑模式下: - **点击地图**:添加标注点(弹出编辑表单) - **绘制区域**:点击工具栏"区域"按钮,依次点击添加顶点,双击完成 - **撤销顶点**:Ctrl+Z 撤销最后一个顶点 - **取消绘制**:按 Esc 取消当前绘制 ### 编程式添加数据 ```javascript map.addLocation({ name: '新标注', x: 1000, y: 2000, type: 'city', description: '描述文字', }); map.addRegion({ name: '新区域', coords: [[lat1, lng1], [lat2, lng2], [lat3, lng3]], color: '#3b82f6', }); map.clearCustomData(); // 清除所有自定义数据 ``` ### 销毁实例 ```javascript map.destroy(); // 销毁地图,释放资源 ``` --- ## 图标映射 GameMap 内置了常用分类的 Font Awesome 图标映射(`SERIES_ICONS`),未映射的分类默认使用 `fa-location-dot`。 自定义图标映射可在创建实例后通过修改 `categories` 实现: ```javascript var map = GameMap.create('map', config, { categories: { myType: { label: '自定义类型', icon: 'fa-star', // Font Awesome 图标 color: '#f59e0b', bgColor: 'rgba(245, 158, 11, 0.15)', group: 'custom', }, }, locations: [ { id: 1, name: '测试点', type: 'myType', x: 1000, y: 1000 }, ], }); ``` --- ## 缩放级别映射 不同类型的标注在飞行定位时会自动使用不同的缩放级别,由 `TYPE_ZOOM_TILES` 和 `TYPE_ZOOM_IMAGE` 控制。 也可为单个标注指定自定义缩放级别: ```javascript { id: 1, name: '大城堡', type: 'city', x: 2900, y: 1630, zoom: 3 } ``` --- ## 自定义数据持久化 用户在编辑模式下添加的标注和区域会自动保存到 `localStorage`(键名 `map_custom_data`),刷新页面后自动恢复。 --- ## 模块化开发 如需二次开发或扩展功能,可使用 `src/` 目录下的 ES 模块源码: ```javascript import { GameMap } from './src/index.js'; const map = new GameMap('map', config, data); ``` **注意**:ES 模块需要通过 HTTP 服务器访问,不能直接用 `file://` 协议打开。可使用以下方式启动本地服务器: ```bash # Python python -m http.server 8080 # Node.js npx serve . ``` ### 模块说明 | 模块 | 说明 | |------|------| | `config.js` | 默认配置定义与深度合并工具函数 | | `constants.js` | 调色板、图标映射表、缩放级别映射表 | | `utils.js` | 工具函数(颜色转换、Toast 通知、HTML 生成、样式注入) | | `data-builder.js` | 将 series/points/senses 原始数据转换为内部格式 | | `map-core.js` | Leaflet 地图初始化、CRS 构建、图层配置 | | `markers.js` | 标注管理器(空间索引、创建、可见性、弹窗) | | `regions.js` | 区域管理器(多边形添加、样式、交互) | | `sidebar.js` | 侧边栏管理器(搜索、筛选、列表渲染、导航) | | `edit-mode.js` | 编辑模式管理器(添加标注、绘制区域、自定义数据持久化) | | `index.js` | 主入口,GameMap 类,组合所有模块 | --- ## 完整示例 ### 瓦片地图 + 原始数据 ```html 我的游戏地图
``` ### 单图模式 + 直接数据 ```html ``` ### 编程式操作 ```javascript var map = GameMap.create('map', config, data); map.flyTo(1); // 飞行到 ID 为 1 的地点 map.search('王都'); // 搜索"王都" map.filterByType('city', false); // 隐藏城镇类型 map.showAll(); // 显示全部 map.enterEditMode(); // 进入编辑模式 map.addLocation({ // 编程式添加标注 name: '秘密洞穴', x: 1500, y: 800, type: 'dungeon', description: '隐藏的宝藏', }); map.exitEditMode(); // 退出编辑模式 var leafletMap = map.getMap(); // 获取 Leaflet 实例进行高级操作 ``` --- ## 版本历史 - **v2.0.0** - 模块化重构,支持两种数据格式,完善 API 接口 - **v1.0.0** - 初始版本,单文件架构