4.1.beta2
给不规则的 TileMap 划分子区域块部分代码
## 生成房间内部数据
func generate_room_inside_data():
GLog.info("生成房间内部数据")
# 划分房间的各个矩形块
for room_coords in room_coords_to_data:
var room_data = room_coords_to_data[room_coords] as Dictionary
var edge_coords_set = room_data["edge_coords_set"] as HashSet
# 获取外部的空白点,用于排除筛选出内部空白点
var outer_empty_coords_set = room_data["outer_empty_coords_set"] as HashSet
# 找到内部第一个空白起始点
var start_coords = null
var edge_coors_list = edge_coords_set.to_array()
edge_coors_list.shuffle()
for edge_coords in edge_coors_list:
for direction in FOUR_DIRECTIONS:
var tmp_coords = edge_coords + direction
if (not edge_coords_set.has(tmp_coords)
and not outer_empty_coords_set.has(tmp_coords)
and tile_map.get_cell_source_id(TILE_LAYER.WALL, tmp_coords) == SOURCE_ID.NONE
):
start_coords = tmp_coords
break
if typeof(start_coords) == TYPE_VECTOR2I:
break
assert(typeof(start_coords) == TYPE_VECTOR2I, "没有找到可用的点,代码逻辑有误!")
# 广度搜索所有内部通路
var inside_empty_coords_set = HashSet.new()
var room_rect = room_data["rect"] as Rect2i
var visited = {}
var tmp_coords
var last_coords_list = [start_coords]
while not last_coords_list.is_empty():
var next_coords_list = []
for coords in last_coords_list:
for direction in FOUR_DIRECTIONS:
tmp_coords = coords + direction
if (
not visited.has(tmp_coords)
and room_rect.has_point(tmp_coords)
and tile_map.get_cell_source_id(TILE_LAYER.WALL, tmp_coords) == SOURCE_ID.NONE
):
visited[tmp_coords] = null
next_coords_list.append(tmp_coords)
inside_empty_coords_set.append(tmp_coords)
last_coords_list = next_coords_list
next_coords_list = []
# 记录内部空白瓦片数据
room_data["inside_empty_coords_set"] = inside_empty_coords_set
# 根据内部空白点,获取每个拐角处的整个矩形
var inside_empty_corner_coords_list = Array()
for coords in inside_empty_coords_set:
if is_empty_corners(coords, tile_map):
inside_empty_corner_coords_list.append(coords)
# 对房间进行局部矩形细分
var added_coords_set = HashSet.new()
var block_rect_list = []
for empty_coords in inside_empty_corner_coords_list:
# TEST 测试显示角落点
#tile_map.set_cell(TILE_LAYER.TEST, coords, 0, Vector2i(0,0), ALTERNATIVE_TILE_ID.ASTAR_PATH)
# 添加过这个小块矩形四个点包含这个坐标时则跳过
if added_coords_set.has(empty_coords):
# FIXME 会有两边都有形,但中间有个障碍物,导致左右坐标全部被占
# 进而导致另外两个矩形无法生成出来
continue
# 拐角只有两个方向
var empty_coords_directions = get_around_empty_coords_directions(empty_coords, tile_map)
for dir_idx in empty_coords_directions.size():
# 朝这个拐角的另一方向移动,直到对面墙角,作为矩形一边的线
var direction = empty_coords_directions[dir_idx]
var moved_line_coords_list = [empty_coords]
var current_coords = empty_coords
while true:
current_coords = current_coords + direction
if (tile_map.get_cell_source_id(TILE_LAYER.WALL, current_coords) == SOURCE_ID.NONE
and tile_map.get_cell_source_id(TILE_LAYER.ENV, current_coords) == SOURCE_ID.NONE
):
moved_line_coords_list.append(current_coords)
else:
break
# 超过这个移动步数长度才认为是矩形
const MAX_STEP = 2
if moved_line_coords_list.size() >= MAX_STEP:
# 矩形左上角的坐标点
var move_start_coords = moved_line_coords_list[0]
var arrive_coords
# 使用移动的路径线的点,进行平移推进,找到这个局部的矩形
var move_direction = empty_coords_directions[1 if dir_idx == 0 else 0]
while true:
MathUtil.offset_origin_array(moved_line_coords_list, move_direction)
for line_coords in moved_line_coords_list:
# 如果移动到的位置有点不是空白区域点,则到达一个墙壁
if not inside_empty_coords_set.has(line_coords):
arrive_coords = moved_line_coords_list[moved_line_coords_list.size() - 1]
# 回退一步
arrive_coords -= move_direction
break
if arrive_coords is Vector2i:
break
# 这个小块区域大小
var size = (arrive_coords - move_start_coords).abs()
# 获取左上角位置
var left_top_coords = move_start_coords
if left_top_coords.x > arrive_coords.x:
left_top_coords.x = arrive_coords.x
if left_top_coords.y > arrive_coords.y:
left_top_coords.y = arrive_coords.y
var block_rect = Rect2i(left_top_coords, size)
# 必须超过步数大小(大小为 0 代表只有一行或一列)
if size.x >= MAX_STEP-1 and size.y >= MAX_STEP-1:
block_rect_list.append(block_rect)
# 记录小块区域的四周坐标点,后续不再对其进行这个操作
added_coords_set.append(block_rect.position) # 左上角
added_coords_set.append(block_rect.end) # 右下角
added_coords_set.append(Vector2i(block_rect.position.x, block_rect.end.y)) # 左下角
added_coords_set.append(Vector2i(block_rect.end.x, block_rect.position.y)) # 右上角
room_data["block_rect_list"] = block_rect_list
# TEST 测试显示小块划分区域的矩形
#for block_rect in block_rect_list:
#FuncUtil.for_rect_around(block_rect, func(coords: Vector2i):
#tile_map.set_cell(TILE_LAYER.TEST, coords, 0, Vector2i(0,0), ALTERNATIVE_TILE_ID.ASTAR_PATH)
#)
## 获取周围白点坐标方向。如果是拐角( is_empty_corners 返回 true )时,则只有个方向
func get_around_empty_coords_directions(coords: Vector2i, tile_map: TileMap) -> Array:
var dirs = []
for direction in FOUR_DIRECTIONS:
if tile_map.get_cell_source_id(TILE_LAYER.WALL, coords + direction) == SOURCE_ID.NONE:
dirs.append(direction)
return dirs