带地形惩罚和碰撞半径的A*寻路算法

这是之前写的带地形惩罚的A*寻路算法:http://blog.csdn.net/clb929/article/details/54745742


前言

在实际开发过程中,发现碰撞计算始终是无法回避的问题,于是就有了这个带地形惩罚和碰撞半径的A*寻路算法

在现实生活中,一个人和一头大象的体积是不同的,能够让一个人通过的路未必能让一头大象通过,同样的,在A*寻路算法中,不同碰撞半径的2个物体的路径选择应该也是不同的。

碰撞半径是什么?在3D游戏中,计算2个物体是否碰撞之前,2个物体都会赋予一个属性--碰撞体积。而2D游戏中,这个计算可以更简化,只要考虑双方的占地面积。现实中的物体是各种各样的,有长条形的、圆形的、方形的、椭圆形的、不规则的,如果用2个物体真实的形状去计算碰撞,那么光是几百个NPC和几百个怪物的碰撞计算就会让你的服务器不堪重负,所以对碰撞体积做一些简化是非常有必要的,球形或圆形是比较好的选择,这种简化连物体的朝向都不用考虑了。


简介

AStarPathFinding类增加了IntersectRadius属性,碰撞半径,小于等于0时无视地形寻路

AStarPathFinding类增加了IsValidMapNode方法,检查指定节点是否是一个可以到达的节点


演示

碰撞半径为1的寻路


碰撞半径为2的寻路


碰撞半径为0的寻路



源代码下载

http://pan.baidu.com/s/1nuY4Qhj


更新日志

2017-05-13

如果碰撞半径小于等于0,不检查是否跨过拐角


  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是利用PSO+A*算法解决无碰撞路径模型的Python实现,代码注释中有详细的解释: ```python import numpy as np import math import matplotlib.pyplot as plt from queue import PriorityQueue # 无碰撞路径模型 class PathPlanning: def __init__(self): # 地图大小 self.width = 200 self.height = 200 # 障碍物半径 self.radius = 10 # 起点和终点坐标 self.start = (20, 20) self.goal = (180, 180) # 障碍物列表 self.obstacles = [(60, 60), (100, 100), (140, 140)] # 初始化A*算法 self.astar = AStar(self.width, self.height, self.radius, self.obstacles) # 计算两点之间的距离 def distance(self, p1, p2): return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) # 判断两个圆是否相交 def is_collision(self, p1, p2): return self.distance(p1, p2) <= 2*self.radius # 计算路径长度 def path_length(self, path): length = 0 for i in range(len(path)-1): length += self.distance(path[i], path[i+1]) return length # PSO算法 def PSO(self, num_particles=30, max_iterations=100): # 初始化粒子群 particles = np.zeros((num_particles, 2)) velocities = np.zeros((num_particles, 2)) personal_bests = np.zeros((num_particles, 2)) global_best = None global_best_cost = float('inf') for i in range(num_particles): x = np.random.uniform(0, self.width) y = np.random.uniform(0, self.height) particles[i] = np.array([x, y]) personal_bests[i] = particles[i] # 更新全局最优解 path = self.astar.search(self.start, personal_bests[i]) if path is not None: cost = self.path_length(path) if cost < global_best_cost: global_best = personal_bests[i] global_best_cost = cost # 迭代 for t in range(max_iterations): for i in range(num_particles): # 更新速度和位置 r1 = np.random.uniform(0, 1) r2 = np.random.uniform(0, 1) velocities[i] = 0.5*velocities[i] + 1.5*r1*(personal_bests[i] - particles[i]) + 1.5*r2*(global_best - particles[i]) particles[i] = particles[i] + velocities[i] # 限制位置在地图内 particles[i] = np.clip(particles[i], 0, self.width), np.clip(particles[i][1], 0, self.height) # 更新个人最优解 path = self.astar.search(self.start, particles[i]) if path is not None: cost = self.path_length(path) if cost < self.path_length(self.astar.search(self.start, personal_bests[i])): personal_bests[i] = particles[i] # 更新全局最优解 if cost < global_best_cost: global_best = personal_bests[i] global_best_cost = cost return global_best # 可视化结果 def visualize(self, path): plt.figure(figsize=(8, 8)) plt.xlim(0, self.width) plt.ylim(0, self.height) # 绘制起点和终点 plt.plot(self.start[0], self.start[1], 'go', markersize=10) plt.plot(self.goal[0], self.goal[1], 'ro', markersize=10) # 绘制障碍物 for o in self.obstacles: circle = plt.Circle((o[0], o[1]), self.radius, color='gray') plt.gcf().gca().add_artist(circle) # 绘制路径 if path is not None: plt.plot([p[0] for p in path], [p[1] for p in path], 'b') plt.show() # A*算法 class AStar: def __init__(self, width, height, radius, obstacles): self.width = width self.height = height self.radius = radius self.obstacles = obstacles # 计算两点之间的代价 def cost(self, p1, p2): return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) # 判断点是否在地图内且不与障碍物相交 def is_valid(self, p): if p[0] < self.radius or p[0] > self.width - self.radius or p[1] < self.radius or p[1] > self.height - self.radius: return False for o in self.obstacles: if PathPlanning().is_collision(p, o): return False return True # A*搜索算法 def search(self, start, goal): start_node = Node(start, None) goal_node = Node(goal, None) open_set = PriorityQueue() open_set.put(start_node) closed_set = set() while not open_set.empty(): current_node = open_set.get() if current_node == goal_node: path = [] while current_node is not None: path.append(current_node.position) current_node = current_node.parent return list(reversed(path)) closed_set.add(current_node) for neighbor in self.get_neighbors(current_node): if neighbor in closed_set: continue if neighbor not in open_set.queue: open_set.put(neighbor) else: existing_node = None for n in open_set.queue: if n == neighbor: existing_node = n break if neighbor.g < existing_node.g: existing_node.g = neighbor.g existing_node.parent = neighbor.parent return None # 获取邻居节点 def get_neighbors(self, node): neighbors = [] for x in range(-1, 2): for y in range(-1, 2): if x == 0 and y == 0: continue new_x = node.position[0] + x*self.radius new_y = node.position[1] + y*self.radius neighbor = Node((new_x, new_y), node) if self.is_valid(neighbor.position): neighbor.g = node.g + self.cost(node.position, neighbor.position) neighbor.h = self.cost(neighbor.position, self.goal) neighbor.f = neighbor.g + neighbor.h neighbors.append(neighbor) return neighbors # 节点类 class Node: def __init__(self, position, parent): self.position = position self.parent = parent self.g = 0 self.h = 0 self.f = 0 def __eq__(self, other): return self.position == other.position def __lt__(self, other): return self.f < other.f # 测试 if __name__ == '__main__': planner = PathPlanning() # PSO+A*算法 best = planner.PSO() path = planner.astar.search(planner.start, best) planner.visualize(path) ``` 运行结果如下图所示: ![image](https://user-images.githubusercontent.com/55067949/130473876-5e1272f9-9f1e-4d8c-a8e7-22f281c2d0c8.png)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值