MongoDB存储1000x1000游戏瓦片地图的2x2空闲区域查询咨询
结论
MongoDB的地理空间查询完全可以适配这个2D瓦片地图的城堡放置场景,不存在能力不匹配的问题,只要调整下存储结构、用对查询操作符就能实现需求。
具体实现步骤
调整空间字段存储格式
你现在的location字段是裸嵌套数组,不符合MongoDB地理空间索引识别的GeoJSON规范,需要改成标准Polygon结构,注意GeoJSON要求面的环坐标必须首尾闭合:{ "_id": ObjectId("62ad13e2a4658cfa758956d4"), "data": { "player_id": "asdfadsf-asdfasdfas-fasdfsdaf-asdffds" }, "location": { "type": "Polygon", "coordinates": [[ [0, 0], [0, 1], [1, 1], [1, 0], [0, 0] ]] } }调整完成后给
location字段创建2dsphere索引:db.castles.createIndex({ location: "2dsphere" })不用纠结2dsphere是给经纬度设计的问题,平面游戏坐标用它完全没问题,整数瓦片坐标不会有精度损耗,性能比旧版2d索引更好。
空闲方格查询逻辑
MongoDB的空间查询是基于库中已存在的几何对象做关系判断,没法直接查出"不存在的空闲区域",所以用随机生成候选+碰撞检测的方案最直接:- 先划定你要搜索空位的坐标范围,在范围内随机生成一个2x2方格的左下角坐标
(randX, randY),拼成和上面结构一致的GeoJSON正方形面对象 - 用
$geoIntersects操作符查询是否有已存城堡和这个候选方格相交:const candidate = { type: "Polygon", coordinates: [[ [randX, randY], [randX, randY+1], [randX+1, randY+1], [randX+1, randY], [randX, randY] ]] } const overlapCount = await db.castles.countDocuments({ location: { $geoIntersects: { $geometry: candidate } } }) - 如果
overlapCount为0,说明这个候选方格和所有已有城堡完全不重叠,就是符合要求的放置位。
- 先划定你要搜索空位的坐标范围,在范围内随机生成一个2x2方格的左下角坐标
性能优化建议
- 大地图场景下不要全范围随机生成候选点,可以把地图拆成固定大小的区块,单独维护每个区块的已占用瓦片数,优先在占用率低的区块生成候选,能大幅减少碰撞重试的次数,百万级城堡数据下单次查询可以稳定在毫秒级。
- 如果是尺寸固定的有限地图,可以提前预生成所有合法的2x2放置位存在单独的集合中,每次取点位时直接标记占用,完全省去碰撞检测的开销,适合单局地图规模不大的游戏。
- 不要用手动写坐标范围判断的逻辑,2dsphere索引对空间相交查询的优化远好于自行实现的遍历判断,数据量上来之后性能差距会非常明显。
内容的提问来源于stack exchange,提问作者shreder
相关产品推荐
相关产品推荐

