ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

3步把Tiled地图搬进Flame游戏:从TMX文件到动态画面

3步把Tiled地图搬进Flame游戏:从TMX文件到动态画面 3步把Tiled地图搬进Flame游戏从TMX文件到动态画面【免费下载链接】flameA Flutter based game engine.项目地址: https://gitcode.com/GitHub_Trending/fl/flame平台跳跃游戏里关卡几乎都是在Tiled编辑器里画出来的。导出后我们得到一个TMX文件而Flame引擎的桥接包flame_tiled负责解析这份XML并用整层SpriteBatch把地图画到屏幕上。整个过程三行Dart就能让一张40×40的瓦片地图出现在画面里。TMX、图层与SpriteBatchFlame瓦片地图渲染的底层逻辑写代码之前先弄清中间发生了什么。flame_tiled本质上是站在Tiled与Flame之间的翻译器TMX文件Tiled编辑器的导出格式一份XML记录每行每列放了哪个瓦片、有哪些图层、标注对象在哪里。Tileset瓦片集瓦片共享的那张大图仓库示例里用的是两张512×320的图各装下640个16×16的瓦片。Layer图层地图按层绘制天空、地面、装饰各占一层绘制顺序固定互不干扰。TileAtlasflame_tiled会把同一张图用到的所有瓦片集拼进一张大图集整层瓦片因此可以用一次drawAtlas调用画完这是大地图不卡的关键原因。ObjectGroup对象层不渲染的标注层只记录道具、出生点的像素坐标供运行时生成组件用。数据与渲染分两层也解释了一件事运行时改地图比如挖掉一块地面改的是解析后的TiledMap对象而不是TMX文件本身。这正是后面所有动态技巧能成立的基础。加载第一张Tiled地图依赖声明与十二行游戏流程很直白装依赖、声明素材、load、add。仓库里的示例项目packages/flame_tiled/example是最直接的参照物这里就照着它走。先在pubspec.yaml做两处修改版本号直接取自示例项目dependencies: flame: ^1.38.0 # 引擎本体 flame_tiled: ^3.1.2 # Tiled桥接包 flutter: assets: - assets/tiles/map.tmx # 地图文件 - assets/images/level_standard_tileset.png # 地图引用的瓦片集图然后是能跑起来的最小游戏需要的import是flame_tiled、flame/game.dart、flame/components.dartclass MyGame extends FlameGame { override Futurevoid onLoad() async { // 第二个参数是瓦片上屏尺寸16px源图放大一倍渲染 final map await TiledComponent.load( assets/tiles/map.tmx, Vector2.all(32), ); add(map); // 挂进组件树后每帧都会参与渲染 } }这里有个容易忽略的点destTileSize并不是对图片做缩放只是告诉Flame每个瓦片在屏幕上占多少像素组件自身的size则由地图方向正交、等距、六边形各有各的算法推导出来所以换成等距或六边形地图时不需要额外处理尺寸。场景驱动TileStack瓦片震动与对象层生成金币让地图的一列瓦片抖起来想让地图里某块地面做成会震动的陷阱关键是tileStack它从地图里挑出一列瓦片组成一个可独立运动的组件移除这个stack也不会改动原地图数据——效果是罩在地图之上而不是修改地图本身。final map await TiledComponent.load( assets/tiles/map.tmx, Vector2.all(32), ); add(map); // 挑出第(4,0)列中名为 floor_under 的瓦片 final stack map.tileMap.tileStack(4, 0, named: {floor_under}); stack.add( SequenceEffect([ MoveEffect.by( Vector2(6, 0), NoiseEffectController(duration: 1, frequency: 20), // 噪声产生不规则抖动 ), MoveEffect.by(Vector2.zero(), LinearEffectController(1)), // 匀速复位 ]), ); map.add(stack); // stack是组件必须挂进地图下才生效用噪声控制器而不是线性控制器是因为线性移动看起来像平移噪声位移才有震动的手感。另外注意TileStack目前只支持位置类效果想对它做缩放或旋转动画是不行的。从对象层读坐标生成旋转金币如果在Tiled的对象层里用椭圆标出金币在哪运行时就能直接读出坐标、在对应位置生成组件。示例项目里的AnimatedCoins就是这么做的// 按图层名读取对象层不存在时返回null final coins map.tileMap.getLayerObjectGroup(AnimatedCoins); final coinImg await Flame.images.load(assets/images/coins.png); for (final obj in coins!.objects) { world.add( SpriteAnimationComponent( position: Vector2(obj.x, obj.y), // 对象层直接给出像素坐标 size: Vector2.all(20), animation: SpriteAnimation.fromFrameData( coinImg, SpriteAnimationData.sequenced( amount: 8, // 8帧翻转动画 stepTime: 0.15, textureSize: Vector2.all(20), ), ), ), ); }Flame瓦片地图性能优化四个高频坑与对应修法实际项目里大概率会碰到下面这些情况都可以按现象 → 原因 → 修法来判断瓦片之间出现发丝细的裂纹。原因浮点精度误差相邻两块瓦片的边缘对不齐零点零几像素。修法给地图位置整体偏移0.5像素或者加载时传atlasPackingSpacingX/Y在图集打包阶段就留出间隙。⚠️用了瓦片翻转后掉帧。原因翻转瓦片会破坏drawAtlas的批量绘制回退到逐张imageRect绘制翻转越多、纹理越大掉得越厉害。修法地图确实不需要翻转时给TiledComponent.load传ignoreFlip: true。多瓦片集的大地图卡顿或崩。原因瓦片集塞不进默认的图集上限Web平台4096×4096其他平台8192×8192拆分图集后Draw Call变多。修法用atlasMaxX/atlasMaxY调整图集尺寸或把超大瓦片集拆小。切换地图后内存不回收。原因Flame.images与TiledAtlas各持有一份缓存清一个不够。修法两个clearCache()一起调用。final map await TiledComponent.load( assets/tiles/map.tmx, Vector2.all(32), ignoreFlip: true, // 地图无翻转瓦片省掉翻转的批量回退 atlasMaxX: 4096, // 按目标平台的纹理上限控制图集尺寸 atlasMaxY: 4096, ); // 切到完全不同的一套地图时同时释放两份缓存 Flame.images.clearCache(); TiledAtlas.clearCache();六步拼出一个能玩的小地图把完整流程过一遍目标是让有背景、有地面、有三枚翻转金币的地图跑起来打开Tiled新建一张40×40、瓦片16×16的正交地图。添加地面、装饰两个瓦片集画出底部地面和几块平台。加一个图片层作为天空背景勾选水平重复。新建对象层AnimatedCoins在金币位置放3到5个椭圆。把map.tmx和全部瓦片集图片放进assets在pubspec.yaml里逐条声明。参照示例项目跑起来验证地图可见、金币翻转不对就先查assets声明和地图路径。复盘这条流程load、图层、对象组、TileStack、图集参数flame_tiled的主干API到这里全部出现过。最终产物对应的核心代码压缩版class TiledGame extends FlameGame { TiledGame() : super(camera: CameraComponent.withFixedResolution(width: 640, height: 384)); override Futurevoid onLoad() async { // 1.加载地图 2.挂进world 3.从对象层生成金币 final map await TiledComponent.load(assets/tiles/map.tmx, Vector2.all(32)); world.add(map); final coins map.tileMap.getLayerObjectGroup(AnimatedCoins); for (final o in coins!.objects) { world.add(PositionComponent(position: Vector2(o.x, o.y), size: Vector2.all(20))); } } }画布上的地图动起来之后flame_tiled这座桥的工作就结束了。想继续深入可以看三处flame_tiled API文档TileStack、TileAtlas与排障细节的完整说明Tiled概念说明TMX文件结构与支持的地图类型flame_tiled示例源码带相机平移和金币动画的完整最小工程【免费下载链接】flameA Flutter based game engine.项目地址: https://gitcode.com/GitHub_Trending/fl/flame创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表