如何为Python简易2D网格游戏实现视野判定函数?
网格游戏视野函数实现思路
我正在用Python开发一款无图形界面的简易网格游戏来练手,核心设定如下:
- 最大10×10的2D网格,角色处于其中某个方块
- 网格内每个方块的任意侧边可设置墙体,角色无法穿过或透视墙体
- 当前用嵌套字典存储方块数据(示例见下方),也可改为列表嵌套等更易用的结构
需要实现一个视野函数:根据角色坐标与周边方块的墙体信息,返回其他方块的完全可见、部分可见(约一半区域可见,视线被墙体阻挡)或不可见状态。
方块数据结构示例(原嵌套字典)
{"square 1": {"items": [], "description": "This square has walls on the west and south sides", "coordinates": [0, 0], "walls": ["west", "south"]}}
推荐数据结构优化(可选)
把嵌套字典改成二维列表,直接通过坐标索引访问方块,效率更高:
# 10x10网格,grid[y][x]对应坐标(x,y)的方块 grid = [[ {"walls": {"west", "south"}, "items": [], "description": "This square has walls on the west and south sides"} for _ in range(10) ] for _ in range(10)]
核心实现思路
1. 基于网格步进的视线检测
不用复杂的浮点射线,用简化的方块角落视线追踪:
- 把每个方块的四个角落作为视线检测的终点(比如坐标(x,y)的方块,四个角落虚拟坐标为
(x-0.5, y-0.5)、(x+0.5, y-0.5)、(x-0.5, y+0.5)、(x+0.5, y+0.5)) - 从角色所在方块的中心,向目标方块的四个角落分别发射"视线",每进入一个新方块,就检查与前一个方块之间是否有墙体阻挡
2. 辅助函数:墙体检测
先写一个判断相邻方块间是否有墙体的函数:
def has_wall_between(coord1, coord2, grid): """ coord1: 元组(x1, y1),coord2: 元组(x2, y2),必须是相邻坐标 返回两个方块之间是否存在墙体 """ x1, y1 = coord1 x2, y2 = coord2 # 东边相邻(x1+1 = x2,y1=y2) if x2 == x1 + 1 and y1 == y2: return 'east' in grid[y1][x1]['walls'] or 'west' in grid[y2][x2]['walls'] # 西边相邻(x1-1 = x2,y1=y2) elif x2 == x1 - 1 and y1 == y2: return 'west' in grid[y1][x1]['walls'] or 'east' in grid[y2][x2]['walls'] # 南边相邻(y1+1 = y2,x1=x2) elif y2 == y1 + 1 and x1 == x2: return 'south' in grid[y1][x1]['walls'] or 'north' in grid[y2][x2]['walls'] # 北边相邻(y1-1 = y2,x1=x2) elif y2 == y1 - 1 and x1 == x2: return 'north' in grid[y1][x1]['walls'] or 'south' in grid[y2][x2]['walls'] return False
3. 视线可达性判断
写一个函数,判断从角色坐标到目标角落的视线是否被阻挡:
def is_sight_clear(role_coord, target_corner, grid): """ role_coord: 角色所在方块坐标(x, y) target_corner: 目标方块的角落虚拟坐标(比如(0.5, 0.5)) 返回视线是否清晰无阻挡 """ rx, ry = role_coord # 角色位置转为中心虚拟坐标 start_x, start_y = rx + 0.5, ry + 0.5 tx, ty = target_corner # 计算步进方向 dx = 1 if tx > start_x else -1 if tx < start_x else 0 dy = 1 if ty > start_y else -1 if ty < start_y else 0 current_x, current_y = start_x, start_y current_grid_x, current_grid_y = rx, ry while True: # 计算到下一个网格边界的距离 step_x = float('inf') if dx != 0: next_x = current_grid_x + dx step_x = (next_x + 0.5 - current_x) if dx > 0 else (current_x - (next_x + 0.5)) step_y = float('inf') if dy != 0: next_y = current_grid_y + dy step_y = (next_y + 0.5 - current_y) if dy > 0 else (current_y - (next_y + 0.5)) # 先碰到x或y边界,检查对应方向的墙体 if step_x <= step_y: if has_wall_between((current_grid_x, current_grid_y), (next_x, current_grid_y), grid): return False current_x += step_x * dx current_grid_x = next_x else: if has_wall_between((current_grid_x, current_grid_y), (current_grid_x, next_y), grid): return False current_y += step_y * dy current_grid_y = next_y # 到达目标方块区域 if current_grid_x == int(tx) and current_grid_y == int(ty): return True
4. 计算方块可见状态
遍历所有方块,统计能到达的角落数量,标记状态:
def calculate_vision(role_coord, grid): vision_status = {} rx, ry = role_coord grid_size = 10 for y in range(grid_size): for x in range(grid_size): if (x, y) == (rx, ry): continue # 跳过自身方块 # 当前方块的四个角落虚拟坐标 corners = [ (x - 0.5, y - 0.5), (x + 0.5, y - 0.5), (x - 0.5, y + 0.5), (x + 0.5, y + 0.5) ] clear_count = 0 for corner in corners: if is_sight_clear((rx, ry), corner, grid): clear_count += 1 # 根据可见角落数量判定状态 if clear_count == 4: vision_status[(x, y)] = '完全可见' elif 1 <= clear_count <= 3: vision_status[(x, y)] = '部分可见' else: vision_status[(x, y)] = '不可见' return vision_status
补充说明
- 相邻方块特殊处理:如果和角色方块共用墙体,视线只能到达部分角落,会被标记为部分可见;无墙体则完全可见
- 可根据需求调整部分可见的判定阈值(比如改为2个及以上角落可见才算部分可见)
内容的提问来源于stack exchange,提问作者chester
相关产品推荐
相关产品推荐

