Flame框架中如何从TiledComponent获取瓦片数据及添加对象?
问题解决:Flame中获取Tiled瓦片数据与向ObjectGroup添加对象
一、获取点击位置的瓦片数据
要获取点击位置对应的瓦片数据,需将屏幕点击坐标转换为地图的瓦片网格坐标,具体步骤如下:
- 将点击的全局坐标转换为世界坐标(消除相机偏移的影响)
- 将世界坐标转换为瓦片网格的(x,y)索引
- 通过
tileMap.getTileData获取对应瓦片信息
修改你的onTapDown方法如下:
@override void onTapDown(TapDownInfo info) { // 1. 将全局点击坐标转换为世界坐标 final worldPos = camera.unproject(info.eventPosition.global); // 2. 计算瓦片网格坐标:世界坐标除以单个瓦片尺寸,取整数部分 final tileSize = Vector2(128, 64); final tileX = (worldPos.x / tileSize.x).floor(); final tileY = (worldPos.y / tileSize.y).floor(); // 3. 校验坐标是否在地图范围内,避免越界报错 if (tileX >= 0 && tileX < map.width && tileY >= 0 && tileY < map.height) { // 获取指定图层的瓦片数据(layerId为图层索引,从0开始) final tileData = mapComponent.tileMap.getTileData(layerId: 0, x: tileX, y: tileY); print('点击瓦片坐标:($tileX, $tileY)'); print('瓦片数据:$tileData'); // 读取瓦片自定义属性 if (tileData != null) { print('瓦片自定义属性:${tileData.properties}'); } } else { print('点击位置超出地图范围'); } }
二、向ObjectGroup图层添加怪物等新对象
Tiled的ObjectGroup支持动态添加对象,但需手动创建Tiled对象实例,且Flame不会自动渲染新增对象,需自行创建对应的Flame组件:
步骤1:获取目标ObjectGroup
从TileMap中获取你要操作的ObjectGroup图层(替换为你的图层名称):
// 在onLoad或需要的位置获取图层 final monsterLayer = mapComponent.tileMap.getLayer<ObjectGroup>('MonsterLayer'); if (monsterLayer == null) { print('未找到指定的ObjectGroup图层'); return; }
步骤2:创建并添加Tiled对象
创建Tiled对象(以矩形怪物为例),添加到ObjectGroup的objects列表:
// 创建矩形怪物对象,设置位置、尺寸与自定义属性 final monsterObject = RectangleObject( id: 1001, name: 'Goblin', x: 128 * 5, // 世界坐标x y: 64 * 5, // 世界坐标y width: 64, height: 64, properties: { 'hp': 100, 'attack': 10, }, ); // 添加到ObjectGroup monsterLayer.objects.add(monsterObject);
步骤3:创建Flame组件并渲染
若要在游戏中显示怪物,需创建对应的Flame组件(如SpriteComponent)并添加到world:
// 加载怪物精灵并创建组件 final monsterSprite = await loadSprite('goblin.png'); final monsterComponent = SpriteComponent( sprite: monsterSprite, position: Vector2(monsterObject.x, monsterObject.y), size: Vector2(monsterObject.width, monsterObject.height), ); world.add(monsterComponent);
完整修改后的示例代码
import 'package:flame/components.dart'; import 'package:flame/effects.dart'; import 'package:flame/flame.dart'; import 'package:flame/game.dart'; import 'package:flame_tiled/flame_tiled.dart'; import 'package:flutter/widgets.dart' hide Animation, Image; import 'package:flame/input.dart'; import 'package:flame/events.dart'; import 'package:tiled/tiled.dart'; // 导入tiled包用于创建对象 // Main void main() { runApp(GameWidget(game: TiledGame())); } // Tile and map Size tile = const Size(128, 64); Size map = const Size(30, 30); // TiledGame class TiledGame extends FlameGame with PanDetector, TapDetector { late TiledComponent mapComponent; ObjectGroup? monsterLayer; TiledGame() : super( camera: CameraComponent.withFixedResolution( width: map.width * tile.width, height: map.height * tile.height, ), ); @override Future<void> onLoad() async { debugMode = true; // 加载地图 mapComponent = await TiledComponent.load( 'test.tmx', Vector2(128, 64), prefix: 'assets/maps/' ); world.add(mapComponent); // 获取怪物图层 monsterLayer = mapComponent.tileMap.getLayer<ObjectGroup>('MonsterLayer'); if (monsterLayer != null) { // 初始化添加一个怪物 addMonsterToLayer(Vector2(128*5, 64*5)); } // 相机设置 camera.viewfinder.anchor = Anchor.center; camera.moveTo( Vector2( (map.width * tile.width) * 0.5, (map.height * tile.height) * 0.5 ) ); } // 封装添加怪物的方法 Future<void> addMonsterToLayer(Vector2 position) async { if (monsterLayer == null) return; // 创建Tiled对象 final monsterObject = RectangleObject( id: monsterLayer!.objects.length + 1, name: 'Goblin', x: position.x, y: position.y, width: 64, height: 64, properties: { 'hp': 100, 'attack': 10, }, ); monsterLayer!.objects.add(monsterObject); // 创建Flame渲染组件 final monsterSprite = await loadSprite('goblin.png'); // 替换为你的精灵路径 final monsterComponent = SpriteComponent( sprite: monsterSprite, position: position, size: Vector2(64, 64), ); world.add(monsterComponent); } @override void onTapDown(TapDownInfo info) { final worldPos = camera.unproject(info.eventPosition.global); final tileSize = Vector2(128, 64); final tileX = (worldPos.x / tileSize.x).floor(); final tileY = (worldPos.y / tileSize.y).floor(); if (tileX >= 0 && tileX < map.width && tileY >= 0 && tileY < map.height) { final tileData = mapComponent.tileMap.getTileData(layerId: 0, x: tileX, y: tileY); print('点击瓦片坐标:($tileX, $tileY)'); print('瓦片数据:$tileData'); if (tileData != null) { print('瓦片属性:${tileData.properties}'); } // 点击位置添加怪物 addMonsterToLayer(Vector2(tileX*128, tileY*64)); } else { print('点击位置超出地图'); } } @override void onPanUpdate(DragUpdateInfo info) { double offset = 3.3; Vector2 pos = Vector2((info.delta.global.x*offset)*-1, (info.delta.global.y*offset)*-1); camera.moveBy(pos); } }
内容的提问来源于stack exchange,提问作者Mythar
相关产品推荐
相关产品推荐

