当前位置: 首页 > 工具软件 > KorGE > 使用案例 >

在KorGE中使用Tiled1.7编辑瓦片地图

葛胜泫
2023-12-01

不使用KorGE插件自带编辑器的原因

使用idea上自带的korge插件看tmx文件时切换代码与可视化会导致ieda卡死,所以从Tiled官网下载了最新版(v1.7)的编辑器来编辑瓦片地图。

实现地图与资源分开存储

我的打算是把资源文件与地图文件分开保存,但korge官方自带的Tiled地图解析类貌似只支持把所有文件放在同一个文件夹下,因此需要以官方的类为基础自己修改一部分内容才可以达到想要的效果:

官方解析瓦片地图的函数

suspend fun VfsFile.readTiledMap(
	hasTransparentColor: Boolean = false,
	transparentColor: RGBA = Colors.FUCHSIA,
	createBorder: Int = 1
): TiledMap {
	val folder = this.parent.jail()
	val data = readTiledMapData()

	val tiledTilesets = arrayListOf<TiledTileset>()

	data.tilesets.fastForEach { tileset ->
		tiledTilesets += tileset.toTiledSet(folder, hasTransparentColor, transparentColor, createBorder)
	}

	return TiledMap(data, tiledTilesets)
}

如果不作任何修改的话启动程序会在 readTiledMapData() 处报错,因此这个函数中肯定有需要修改的地方。

官方的readTiledMapData函数

suspend fun VfsFile.readTiledMapData(): TiledMapData {
	/*其他代码*/
	elements.fastForEach { element ->
		when (element.nameLC) {
			"tileset" -> {
				tilemapLog.trace { "tileset" }
				val firstgid = element.int("firstgid", 1)
				val sourcePath = element.getString("source")
				val tileset = if (sourcePath != null) folder[sourcePath].readXml() else element
				tiledMap.tilesets += parseTileSetData(tileset, firstgid, sourcePath)
			}
			/*其他代码*/
		}
	}
	/*其他代码*/
}

通过调试可以知道 folder[sourcePath] 总是会从当前文件夹下去寻找资源,所以可以通过把这一句修改成官方另一种获取资源的方法 resourcesVfs[sourcePath] 来实现从其他文件夹读取资源的效果。

修改后的readTiledMapData函数

suspend fun VfsFile.myReadTiledMapData(): TiledMapData {
	/*其他代码*/
	elements.fastForEach { element ->
		elements.fastForEach { element ->
        when (element.nameLC) {
            "tileset" -> {
                tilemapLog.trace { "tileset" }
                val firstgid = element.int("firstgid", 1)
                val sourcePath = element.getString("source")?.substring(3)
                val tileset = if (sourcePath != null) resourcesVfs[sourcePath].readXml() else element
                tiledMap.tilesets += parseTileSetData(tileset, firstgid, sourcePath)
            }
			/*其他代码*/
		}
	}
	/*其他代码*/
}

修改之后这个函数可以在地图与资源文件夹不同的情况下正常运行了,但 tileset.toTiledSet(folder, hasTransparentColor, transparentColor, createBorder) 这一个函数中还会有其他的问题。

官方的toTiledSet函数

suspend fun TileSetData.toTiledSet(
	folder: VfsFile,
	hasTransparentColor: Boolean = false,
	transparentColor: RGBA = Colors.FUCHSIA,
	createBorder: Int = 1
): TiledTileset {
	val tileset = this
	var bmp = try {
		when (tileset.image) {
			is Image.Embedded -> TODO()
			is Image.External -> folder[tileset.image.source].readBitmapOptimized()
			null -> Bitmap32(0, 0)
		}
	} catch (e: Throwable) {
		e.printStackTrace()
		Bitmap32(tileset.width, tileset.height)
	}
	/*其他代码*/
}

可以看到很眼熟的 folder[tileset.image.source] ,这里官方也用到了从同文件夹下获取文件。但是这个地方我有点难以修改,因为在这里 tileset.image.source得到的只有文件名而没有资源文件的父目录,所以应该要通过其他办法来获取父目录,目前还没有想到就硬编码了一个characters文件夹,以后应该还会对这个地方做修改。

修改后的toTiledSet函数

suspend fun TileSetData.toTiledSet(
	folder: VfsFile,
	hasTransparentColor: Boolean = false,
	transparentColor: RGBA = Colors.FUCHSIA,
	createBorder: Int = 1
): TiledTileset {
	val tileset = this
	var bmp = try {
		when (tileset.image) {
			is Image.Embedded -> TODO()
			is TiledMap.Image.External -> resourcesVfs["characters/"+(tileset.image as TiledMap.Image.External).source].readBitmapOptimized()
            null -> Bitmap32(0, 0)
		}
	} catch (e: Throwable) {
		e.printStackTrace()
		Bitmap32(tileset.width, tileset.height)
	}
	/*其他代码*/
}

解决事件向下偏移

做完这些步骤之后游戏就可以启动了,但是会有地图事件层中的所有图形都往下偏移的情况,因此还需要做修改。在游戏中显示瓦片地图时会调用一个叫 createView 的函数。

fun TiledMap.createView() = TiledMapView(this)

官方的TiledMapView函数

class TiledMapView(tiledMap: TiledMap, showShapes: Boolean = true, smoothing: Boolean = true) : Container() {
    val tileset = tiledMap.tilesets.toTileSet()
	init {
		tiledMap.allLayers.fastForEachWithIndex { index, layer ->
            val view: View = when (layer) {
                is TiledMap.Layer.Tiles -> tileMap(layer.map, tileset, smoothing = smoothing)
                is TiledMap.Layer.Objects -> {
                    container {
                        for (obj in layer.objects) {
                            val bounds = obj.bounds
                            val gid = obj.gid
                            var shouldShow = showShapes
                            val view: View = when (val type = obj.objectType) {
                                /*其他代码*/
                                is TiledMap.Object.Type.Rectangle -> {
                                    if (gid != null) {
                                        val tileTex = tileset[gid] ?: Bitmaps.transparent
                                        //println("tileTex[gid=$gid]: $tileTex!")
                                        shouldShow = true
                                        image(tileTex)
                                    } else {
                                        solidRect(bounds.width, bounds.height, Colors.WHITE)
                                    }
                                }
                                /*其他代码*/
                            }
                            /*其他代码*/
                        }
                    }
                }
                else -> dummyView()
            }
            /*其他代码*/
		}
	}
}

通过查阅资料可以得知向下偏移的原因,因此我们只需要把所有事件的y坐标减掉一个事件的height属性就可以得到正确的y坐标了。

修改后的TiledMapView函数

class TiledMapView(tiledMap: TiledMap, showShapes: Boolean = true, smoothing: Boolean = true) : Container() {
    val tileset = tiledMap.tilesets.toTileSet()
	init {
		tiledMap.allLayers.fastForEachWithIndex { index, layer ->
            val view: View = when (layer) {
                is TiledMap.Layer.Tiles -> tileMap(layer.map, tileset, smoothing = smoothing)
                is TiledMap.Layer.Objects -> {
                    container {
                        for (obj in layer.objects) {
                            val bounds = obj.bounds
                            val gid = obj.gid
                            var shouldShow = showShapes
                            val view: View = when (val type = obj.objectType) {
                                /*其他代码*/
                                is TiledMap.Object.Type.Rectangle -> {
                                    bounds.y -= bounds.height //减去自身的height
                                    if (gid != null) {
                                        val tileTex = tileset[gid] ?: Bitmaps.transparent
                                        //println("tileTex[gid=$gid]: $tileTex!")
                                        shouldShow = true
                                        image(tileTex)
                                    } else {
                                        solidRect(bounds.width, bounds.height, Colors.WHITE)
                                    }
                                }
                                /*其他代码*/
                            }
                            /*其他代码*/
                        }
                    }
                }
                else -> dummyView()
            }
            /*其他代码*/
		}
	}
}

总结

改完以上几点之后就可以在korge中很舒服地显示Tiled1.7编辑的地图了,目前也没有遇到其他问题,虽然解决的过程中有一些不足但是当前的目的是能用就行,以后可以再做修改。

 类似资料: