如何在calculate_visible_tiles函数中实现光线被1型tile阻挡?
解决光线遇墙体停止的可见tile计算问题
原代码的核心问题是直接将光照圆形范围内的所有tile标记为可见,完全没有考虑视线遮挡逻辑。你之前尝试添加阻挡时黑屏,大概率是逻辑错误导致没有任何tile被加入可见集合(比如误判所有路径都被墙体阻挡,或者错误终止了所有遍历)。
正确的做法是用逐路径射线追踪(Bresenham算法),从角色所在tile出发,逐个方向检查路径上的tile,遇到墙体就停止该方向的检查,具体实现步骤如下:
1. 修正角色tile坐标计算
先把角色的像素坐标转换成准确的tile坐标,避免round带来的误差:
char_tile_x = character_x // tile_size char_tile_y = character_y // tile_size
2. 实现逐路径视线检查
遍历光照半径内的每个目标tile,用Bresenham算法生成从角色tile到目标tile的路径,逐格检查是否有墙体阻挡:
完整修改后的代码
def calculate_visible_tiles(character_x, character_y, light_radius, game_map, tile_size): visible_tiles = set() # 先把角色所在的tile加入可见集合 char_tile_x = character_x // tile_size char_tile_y = character_y // tile_size if 0 <= char_tile_x < len(game_map[0]) and 0 <= char_tile_y < len(game_map): visible_tiles.add((char_tile_x, char_tile_y)) # 遍历光照半径内的所有tile(以tile为单位的范围) max_tile_radius = light_radius // tile_size for dx in range(-max_tile_radius, max_tile_radius + 1): for dy in range(-max_tile_radius, max_tile_radius + 1): target_tile_x = char_tile_x + dx target_tile_y = char_tile_y + dy # 跳过超出地图范围的tile if target_tile_x < 0 or target_tile_x >= len(game_map[0]) or target_tile_y < 0 or target_tile_y >= len(game_map): continue # 计算角色到目标tile的距离(tile单位),超出光照范围则跳过 distance = (dx**2 + dy**2)**0.5 if distance > max_tile_radius: continue # 用Bresenham算法生成路径上的所有tile x0, y0 = char_tile_x, char_tile_y x1, y1 = target_tile_x, target_tile_y dx_path = abs(x1 - x0) dy_path = abs(y1 - y0) sx = 1 if x0 < x1 else -1 sy = 1 if y0 < y1 else -1 err = dx_path - dy_path current_x, current_y = x0, y0 blocked = False while True: # 检查当前tile是否是墙体 if game_map[current_y][current_x] == 1: blocked = True break # 到达目标tile,停止路径检查 if current_x == x1 and current_y == y1: break # 计算下一个路径tile e2 = 2 * err if e2 > -dy_path: err -= dy_path current_x += sx if e2 < dx_path: err += dx_path current_y += sy # 如果路径没有被阻挡,将目标tile加入可见集合 if not blocked: visible_tiles.add((target_tile_x, target_tile_y)) return visible_tiles
关键逻辑说明
- 角色tile优先加入:确保角色自身所在位置一定可见,避免黑屏。
- 以tile为单位的范围遍历:原代码用像素偏移计算tile容易出错,改为直接操作tile坐标的偏移。
- Bresenham路径追踪:逐格检查角色到目标tile的路径,一旦遇到墙体(值为1),就标记该路径被阻挡,目标tile不可见。
- 边界与距离判断:提前过滤超出地图和光照范围的tile,减少不必要的计算。
之前黑屏的常见原因
- 误将角色所在tile判断为墙体,导致没有初始可见tile。
- 路径检查逻辑错误,比如只要遇到墙体就终止所有遍历,而非仅终止当前路径。
- 光照范围计算错误,比如用像素距离直接对比tile半径,导致没有tile符合条件。
内容的提问来源于stack exchange,提问作者Dyl
相关产品推荐
相关产品推荐

