摘要
本文通过形象比喻和游戏应用,介绍了无向图、有向图、简单图、多重图和带权图的概念及其在游戏中的实际应用。无向图适用于双向关系,如好友关系;有向图适用于单向关系,如任务流程;简单图限制每对节点之间只有一条边;多重图允许多条边和自环;带权图则为每条边赋予权重,适用于寻路和资源分配。文章还通过Python代码示例,展示了带权有向图在游戏地图中的实现,并简要介绍了A*寻路算法和Dijkstra最短路径算法在游戏中的应用。这些图论概念和算法在游戏开发中具有广泛的应用价值。
1. 无向图(Undirected Graph)
形象解释
想象一群小朋友在操场上玩“牵手游戏”,每两个人之间可以牵手,牵手是相互的——你牵我,我也牵你,没有方向之分。
游戏中的应用
- 棋盘上的连线:比如五子棋、连连看,每个棋子/点之间的连线没有方向,谁先连上都可以。
- 社交网络:在多人在线游戏中,玩家之间的“好友关系”就是无向的——你是我的好友,我也是你的好友。
2. 有向图(Directed Graph)
形象解释
想象一群小朋友在玩“传话游戏”,每个人只能把话传给指定的下一个人,传话有方向:A传给B,B传给C,不能反过来。
游戏中的应用
- 任务流程:在RPG游戏中,主线任务必须按顺序完成,任务A完成后才能做任务B,这就是有向图。
- 技能树:有些游戏的技能解锁顺序是有方向的,必须先学会A技能,才能学B技能。
3. 简单图(Simple Graph)
形象解释
还是“牵手游戏”,规定每两个人之间最多只能牵一次手,自己不能和自己牵手。
游戏中的应用
- 普通地图:比如大富翁游戏,每两个城市之间最多只有一条路,自己不能回到自己。
4. 多重图(Multigraph)
形象解释
如果允许两个人之间牵多次手(比如左手牵一次,右手再牵一次),那就是多重图。也可以自己和自己牵手(自环)。
游戏中的应用
- 多条路线:在赛车游戏中,两个赛点之间可能有多条不同的赛道可以选择。
- 传送门:在某些迷宫游戏中,两个房间之间可能有多个传送门,甚至有的门直接回到自己原来的房间。
5. 带权图(Weighted Graph)
形象解释
每条“牵手”都可以有一个分数,比如牵手的距离、难度、花费的金币数等。这个分数就是“权重”。
游戏中的应用
- 地图寻路:在策略游戏或RPG中,不同道路有不同的长度、危险度或通行费用,玩家要选择“最短路径”或“最便宜的路线”。
- 资源分配:在塔防游戏中,不同路径的怪物数量或强度不同,权重可以表示难度。
6. 总结对比表
图类型 | 形象比喻 | 游戏应用举例 |
---|---|---|
无向图 | 牵手游戏 | 好友关系、棋盘连线 |
有向图 | 传话游戏 | 任务流程、技能树 |
简单图 | 只能牵一次手 | 普通地图、城市连线 |
多重图 | 多次牵手/自环 | 多条赛道、多个传送门 |
带权图 | 牵手有分数 | 地图寻路、资源分配、最短路径 |
7. 生活化+游戏化小结
- 无向图:你和我互为好友,关系是双向的。
- 有向图:我关注你,你不一定关注我,关系是单向的。
- 简单图:每对玩家之间最多一条关系线。
- 多重图:可以有多条关系线,甚至自己和自己连线。
- 带权图:每条线有“分数”,比如距离、花费、难度等。
下面我会图论在游戏中的实际应用:
- 用代码举例,演示“带权有向图”在游戏地图寻路中的实现。
- 介绍A*寻路算法,并给出简化版的Python代码。
- **说明最短路径算法(Dijkstra)**在游戏中的应用。
1. 带权有向图的游戏地图实现(Python示例)
假设你有一个游戏地图,城市A、B、C、D之间有不同的道路和距离。我们用带权有向图来表示:
# 用字典表示带权有向图
game_map = {
'A': {'B': 5, 'C': 10},
'B': {'C': 3, 'D': 7},
'C': {'D': 1},
'D': {}
}
# 打印所有从A出发的路线和距离
for dest, cost in game_map['A'].items():
print(f"从A到{dest}的距离是{cost}")
输出:
从A到B的距离是5
从A到C的距离是10
2. A*寻路算法简介与代码
A*算法简介
A*(A-star)是游戏中最常用的寻路算法,能在地图上找到从起点到终点的最短路径。它结合了“已走的距离”和“到终点的估算距离”(启发式函数),效率高,常用于迷宫、塔防、RPG等游戏。
简化版A*算法代码(适用于网格地图)
import heapq
def heuristic(a, b):
# 曼哈顿距离(适合上下左右移动的网格)
return abs(a[0] - b[0]) + abs(a[1] - b[1])
def astar(grid, start, goal):
rows, cols = len(grid), len(grid[0])
open_set = []
heapq.heappush(open_set, (0 + heuristic(start, goal), 0, start, [start]))
visited = set()
while open_set:
est_total, cost, current, path = heapq.heappop(open_set)
if current == goal:
return path
if current in visited:
continue
visited.add(current)
for dx, dy in [(-1,0),(1,0),(0,-1),(0,1)]:
nx, ny = current[0]+dx, current[1]+dy
if 0<=nx<rows and 0<=ny<cols and grid[nx][ny]==0:
next_node = (nx, ny)
heapq.heappush(open_set, (cost+1+heuristic(next_node, goal), cost+1, next_node, path+[next_node]))
return None
# 0表示可走,1表示障碍
grid = [
[0,0,0,0],
[1,1,0,1],
[0,0,0,0],
[0,1,1,0]
]
start = (0,0)
goal = (3,3)
path = astar(grid, start, goal)
print("A*寻路结果:", path)
输出示例:
A*寻路结果: [(0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 3), (3, 3)]
3. Dijkstra最短路径算法在游戏中的应用
应用场景
- 开放世界游戏:NPC自动寻路到目标点。
- 策略游戏:计算单位移动的最短消耗。
- 塔防游戏:怪物选择最短路径进攻。
简化版Dijkstra算法代码
import heapq
def dijkstra(graph, start):
heap = [(0, start)]
dist = {node: float('inf') for node in graph}
dist[start] = 0
prev = {node: None for node in graph}
while heap:
cost, u = heapq.heappop(heap)
for v in graph[u]:
alt = cost + graph[u][v]
if alt < dist[v]:
dist[v] = alt
prev[v] = u
heapq.heappush(heap, (alt, v))
return dist, prev
# 示例图
game_map = {
'A': {'B': 5, 'C': 10},
'B': {'C': 3, 'D': 7},
'C': {'D': 1},
'D': {}
}
dist, prev = dijkstra(game_map, 'A')
print("A到各点的最短距离:", dist)
输出:
A到各点的最短距离: {'A': 0, 'B': 5, 'C': 8, 'D': 9}
4. 总结
- 带权有向图:适合表示游戏地图、任务流程、技能树等。
- A*算法:高效寻路,常用于角色移动、怪物AI等。
- Dijkstra算法:适合所有边权为正的最短路径问题,常用于地图分析、资源分配等。