working keyboard and plugin for better tilemaps
This commit is contained in:
194
addons/TileMapDual/TerrainDual.gd
Normal file
194
addons/TileMapDual/TerrainDual.gd
Normal file
@@ -0,0 +1,194 @@
|
||||
##[br] Reads a TileSet and dictates which tiles in the display map
|
||||
##[br] match up with its neighbors in the world map
|
||||
class_name TerrainDual
|
||||
extends Resource
|
||||
|
||||
|
||||
# Functions are ordered top to bottom in the transformation pipeline
|
||||
|
||||
## Maps a TileSet to a Neighborhood.
|
||||
static func tileset_neighborhood(tile_set: TileSet) -> Neighborhood:
|
||||
return GRID_NEIGHBORHOODS[Display.tileset_gridshape(tile_set)]
|
||||
|
||||
|
||||
## Maps a GridShape to a Neighborhood.
|
||||
const GRID_NEIGHBORHOODS = {
|
||||
Display.GridShape.SQUARE: Neighborhood.SQUARE,
|
||||
Display.GridShape.ISO: Neighborhood.ISOMETRIC,
|
||||
Display.GridShape.HALF_OFF_HORI: Neighborhood.TRIANGLE_HORIZONTAL,
|
||||
Display.GridShape.HALF_OFF_VERT: Neighborhood.TRIANGLE_VERTICAL,
|
||||
Display.GridShape.HEX_HORI: Neighborhood.TRIANGLE_HORIZONTAL,
|
||||
Display.GridShape.HEX_VERT: Neighborhood.TRIANGLE_VERTICAL,
|
||||
}
|
||||
|
||||
|
||||
## A specific neighborhood that the Display tiles will look at.
|
||||
enum Neighborhood {
|
||||
SQUARE,
|
||||
ISOMETRIC,
|
||||
TRIANGLE_HORIZONTAL,
|
||||
TRIANGLE_VERTICAL,
|
||||
}
|
||||
|
||||
|
||||
## Maps a Neighborhood to a set of atlas terrain neighbors.
|
||||
const NEIGHBORHOOD_LAYERS := {
|
||||
Neighborhood.SQUARE: [
|
||||
{ # []
|
||||
'terrain_neighborhood': [
|
||||
TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER,
|
||||
],
|
||||
'display_to_world_neighborhood': [
|
||||
[TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER],
|
||||
[TileSet.CELL_NEIGHBOR_TOP_SIDE],
|
||||
[TileSet.CELL_NEIGHBOR_LEFT_SIDE],
|
||||
[],
|
||||
],
|
||||
},
|
||||
],
|
||||
Neighborhood.ISOMETRIC: [
|
||||
{ # <>
|
||||
'terrain_neighborhood': [
|
||||
TileSet.CELL_NEIGHBOR_TOP_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_RIGHT_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_LEFT_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_BOTTOM_CORNER,
|
||||
],
|
||||
'display_to_world_neighborhood': [
|
||||
[TileSet.CELL_NEIGHBOR_TOP_CORNER],
|
||||
[TileSet.CELL_NEIGHBOR_TOP_RIGHT_SIDE],
|
||||
[TileSet.CELL_NEIGHBOR_TOP_LEFT_SIDE],
|
||||
[],
|
||||
],
|
||||
},
|
||||
],
|
||||
Neighborhood.TRIANGLE_HORIZONTAL: [
|
||||
{ # v
|
||||
'terrain_neighborhood': [
|
||||
TileSet.CELL_NEIGHBOR_BOTTOM_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER,
|
||||
],
|
||||
'display_to_world_neighborhood': [
|
||||
[],
|
||||
[TileSet.CELL_NEIGHBOR_TOP_LEFT_SIDE],
|
||||
[TileSet.CELL_NEIGHBOR_TOP_RIGHT_SIDE],
|
||||
],
|
||||
},
|
||||
{ # ^
|
||||
'terrain_neighborhood': [
|
||||
TileSet.CELL_NEIGHBOR_TOP_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER,
|
||||
],
|
||||
'display_to_world_neighborhood': [
|
||||
[TileSet.CELL_NEIGHBOR_TOP_LEFT_SIDE],
|
||||
[TileSet.CELL_NEIGHBOR_LEFT_SIDE],
|
||||
[],
|
||||
],
|
||||
},
|
||||
],
|
||||
# TODO: this is just TRIANGLE_HORIZONTAL but transposed. this can be refactored.
|
||||
Neighborhood.TRIANGLE_VERTICAL: [
|
||||
{ # >
|
||||
'terrain_neighborhood': [
|
||||
TileSet.CELL_NEIGHBOR_RIGHT_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER,
|
||||
],
|
||||
'display_to_world_neighborhood': [
|
||||
[],
|
||||
[TileSet.CELL_NEIGHBOR_TOP_LEFT_SIDE],
|
||||
[TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_SIDE],
|
||||
],
|
||||
},
|
||||
{ # <
|
||||
'terrain_neighborhood': [
|
||||
TileSet.CELL_NEIGHBOR_LEFT_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER,
|
||||
TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER,
|
||||
],
|
||||
'display_to_world_neighborhood': [
|
||||
[TileSet.CELL_NEIGHBOR_TOP_LEFT_SIDE],
|
||||
[TileSet.CELL_NEIGHBOR_TOP_SIDE],
|
||||
[],
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
## The Neighborhood type of this TerrainDual.
|
||||
var neighborhood: Neighborhood
|
||||
|
||||
## Maps a terrain type to its sprite as registered in the TerrainDual.
|
||||
var terrains: Dictionary
|
||||
|
||||
## The TerrainLayers for this TerrainDual.
|
||||
var layers: Array
|
||||
var _tileset_watcher: TileSetWatcher
|
||||
func _init(tileset_watcher: TileSetWatcher) -> void:
|
||||
_tileset_watcher = tileset_watcher
|
||||
_tileset_watcher.terrains_changed.connect(_changed, 1)
|
||||
_changed()
|
||||
|
||||
|
||||
##[br] Emitted when any of the terrains change.
|
||||
##[br] NOTE: Prefer connecting to TerrainDual.changed instead of TileSetWatcher.terrains_changed.
|
||||
func _changed() -> void:
|
||||
#print('SIGNAL EMITTED: changed(%s)' % {})
|
||||
read_tileset(_tileset_watcher.tile_set)
|
||||
emit_changed()
|
||||
|
||||
|
||||
## Create rules for every atlas in a TileSet.
|
||||
func read_tileset(tile_set: TileSet) -> void:
|
||||
terrains = {}
|
||||
layers = []
|
||||
neighborhood = Neighborhood.SQUARE # default
|
||||
if tile_set == null:
|
||||
return
|
||||
neighborhood = tileset_neighborhood(tile_set)
|
||||
layers = NEIGHBORHOOD_LAYERS[neighborhood].map(TerrainLayer.new)
|
||||
for i in tile_set.get_source_count():
|
||||
var sid := tile_set.get_source_id(i)
|
||||
var src := tile_set.get_source(sid)
|
||||
if src is not TileSetAtlasSource:
|
||||
continue
|
||||
read_atlas(src, sid)
|
||||
|
||||
|
||||
## Create rules for every tile in an atlas.
|
||||
func read_atlas(atlas: TileSetAtlasSource, sid: int) -> void:
|
||||
var size = atlas.get_atlas_grid_size()
|
||||
for y in size.y:
|
||||
for x in size.x:
|
||||
var tile := Vector2i(x, y)
|
||||
# Take only existing tiles
|
||||
if not atlas.has_tile(tile):
|
||||
continue
|
||||
read_tile(atlas, sid, tile)
|
||||
|
||||
|
||||
## Add a new rule for a specific tile in an atlas.
|
||||
func read_tile(atlas: TileSetAtlasSource, sid: int, tile: Vector2i) -> void:
|
||||
var data := atlas.get_tile_data(tile, 0)
|
||||
var mapping := {'sid': sid, 'tile': tile}
|
||||
var terrain_set := data.terrain_set
|
||||
if terrain_set != 0:
|
||||
push_warning(
|
||||
"The tile at %s has a terrain set of %d. Only terrain set 0 is supported." % [mapping, terrain_set]
|
||||
)
|
||||
return
|
||||
var terrain := data.terrain
|
||||
if terrain != -1:
|
||||
if not terrain in terrains:
|
||||
terrains[terrain] = mapping
|
||||
|
||||
var filters = NEIGHBORHOOD_LAYERS[neighborhood]
|
||||
for i in layers.size():
|
||||
var layer: TerrainLayer = layers[i]
|
||||
layer._register_tile(data, mapping)
|
||||
Reference in New Issue
Block a user