You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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,减少不必要的计算。

之前黑屏的常见原因

  1. 误将角色所在tile判断为墙体,导致没有初始可见tile。
  2. 路径检查逻辑错误,比如只要遇到墙体就终止所有遍历,而非仅终止当前路径。
  3. 光照范围计算错误,比如用像素距离直接对比tile半径,导致没有tile符合条件。

内容的提问来源于stack exchange,提问作者Dyl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 06:30:13