You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flame框架中如何从TiledComponent获取瓦片数据及添加对象?

问题解决:Flame中获取Tiled瓦片数据与向ObjectGroup添加对象

一、获取点击位置的瓦片数据

要获取点击位置对应的瓦片数据,需将屏幕点击坐标转换为地图的瓦片网格坐标,具体步骤如下:

  1. 将点击的全局坐标转换为世界坐标(消除相机偏移的影响)
  2. 将世界坐标转换为瓦片网格的(x,y)索引
  3. 通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 21:47:07