status
date
slug
tags
category
type
password
icon
Paper:
 
  • JPS: Jump Point Search
A* vs. JPS
A*
JPS
JPS-Bit
JPS-BitPrune
JPS-BitPre
JPS-BitPrunePre
耗時
25.5ms
1.7ms
320us
230us
200us
95us
速度
1x
15x
81x
110x
130x
273x
基於 A* 的優化
JPS 基於當前節點 的方向,遵循”兩個定義,三個規則”決定 Forced Neighbour(FN)
  • 定義一 FN
    • 如果節點 的鄰居,並且節點 的鄰居有障礙物,並且從 , , 的路徑長度比其他任何從 且不經過 的路徑更短 ⇒ 則 的 FN, 的跳點。(圖1中, 的FN, 的跳點 )
  • 定義二 跳點
    • 如果節點 是起點或目標點,則 是跳點。(圖1中的 )
    • 如果 有 FN ⇒ 則 是跳點 (圖1中的 )
    • 如果 是對角線移動,並且 經過水平或垂直方向可以到達跳點 ⇒ 則 是跳點 (圖1中的 )
  • 規則一
    • 在搜尋跳點的過程中,優先搜尋直線方向,再搜尋對角線方向
  • 規則二
    • 如果從 是直線移動,且 的鄰居,若存在 的路徑不經過 且路徑長度小於等於 經過 的路徑,則走到 以後下一個點不會走到
    • 如果從 是對角線移動,且 的鄰居,若存在 的路徑不經過 且路徑長度小於 經過 的路徑,則走到 以後下一個點不會走到
  • 規則三
    • 只有跳點才會加入 openset,因為跳點會改變行走方向(非跳點無法改變方向),最後尋找出來的路徑點都是跳點
根據當前方向來決定下一個跳點
  • Case 1. 當前方向是直線
    • Case 1.1 目前左後方不可走且左方可走 ⇒ 沿左前方左方找不在 closedset 的跳點
    • Case 1.2 目前當前方向可走 ⇒ 沿著當前方向尋找不在 closedset 的跳點
    • Case 1.3 目前右後方不可走且右方可走 ⇒ 沿右前方右方找不在 closedset 的跳點
  • Case 2. 當前方向是對角線
    • Case 2.1 目前的水平分量可走 ⇒ 沿水平分量方向尋找不在 closedset 的跳點
    • Case 2.2 目前當前方向可走 ⇒ 沿著當前方向尋找不在 closedset 的跳點
    • Case 2.3 目前的垂直分量可走 ⇒ 沿垂直方量方向尋找不在 closedset 的跳點
JSP 的三種優化
  • Bit Operation
  • Preprocessing
  • Prune
算法流程圖
notion image
圖一
notion image
來看個例子
  • 圖請見圖一
  • 目標: 尋找從 的最短路徑,且不能經過黑色區域
  • 螢幕參考座標系(上下左右)、人物參考坐標系(前後左右)
  1. 加入 openset
  1. 從 openset 中取出 值最小的節點 ⇒
  1. 從 openset 中刪除,加入 closedset
  1. 當前方向為空,往八個方向擴散,三個選項為右、下、右下
    1. ⇒ 撞到牆
    2. ⇒ 撞到邊界
    3. 右下 ⇒ 根據定義二第三條, 為 S,右下是對角線移動,並且 透過垂直移動可以到達跳點 為跳點,將 加入 openset
  1. 從 openset 中取出 值最小的節點 ⇒
  1. 從 openset 中刪除,加入 closedset
  1. 當前方向( 看向 )為右下,往右、下、右下三個方向擴散(Case 2)
    1. ⇒ 撞到牆
    2. 右下 ⇒ 撞到牆
    3. ⇒ 根據定義二第二條,找到跳點 ,將 加入 openset
  1. 從 openset 中取出 值最小的節點 ⇒
  1. 當前方向( 看向 )為向,往右、右下(Case1.1中的左前)與(Case1.2)擴散
    1. ⇒ 撞到邊界
    2. 右下 ⇒ 撞到邊界
    3. ⇒ 根據定義二第二條,透過 FN 找到跳點 ,將 加入 openset
  1. 從 openset 中取出 值最小的節點 ⇒
  1. 當前方向( 看向牆壁)為向,往上、右上(Case 1.1)(Case 1.2)擴散
    1. ⇒ 撞到邊界
    2. 右上 ⇒ 撞到邊界
    3. ⇒ 根據定義二第一條,找到跳點 ,將 加入 openset
  1. 從 openset 中取出 值最小的節點 ⇒
  1. 找到目標點,尋路結束,路徑為
JPS 快在哪
  • A* 在從 時,會將 加入到 openset 中,才能走出 或是
  • JPS 只用到
  • 對 heap 來說,插入與刪除節點(更新openset與closedset)的複雜度為
JPS-Bit
  • 使用 bit operation 來優化
  • 使用 0 表示可走的節點,1表示不可走的節點
圖二
notion image
  • __builtin_clz(B): 返回前導 0 的個數
  • 尋找當前的跳點: __builtin_clz(((B->>1) && !B-) || ((B+>>1) && !B+))
  • 本例中__builtin_clz(((00000000) && 11111111) || ((00011000) && (11001111))) = 00001000 = 4,從 往當前方向(向右)數四格的 即為下一個跳點
JPS-BitPrune
  • 基於 JPS-Bit 之上進行剪枝,刪除不必要的中間跳點,尋訪到完整路徑之後以拐點替代
  • 增加拐點
    • 假設節點 座標為
    • 如果 在同一個直線上 ⇒ 走直線就好,不用加拐點
    • 如果 在對角線方向上 ⇒ 直線到達即可,不用加拐點
    • 除此之外的情況,說明兩個點不在同一個對角線上,並且中間可能存在障礙物,需要加上一個中間跳點作為拐點
    • 選擇拐點的策略: 離 點最近的中間跳點(從 沿對角線走 步的點)
再看個例子
notion image
  • 起點: ,目標:
  • 節點 是為了到達結點 或結點 的中間跳點
  • 節點 是為了達到節點 的中間跳點
  1. 開始尋找跳點 ⇒
  1. 的直線方向找到跳點 ,將兩個跳點的父跳點設為
  1. 繼續從 的對角線找跳點 ⇒
  1. 的直線方向找到跳點 ,將跳點 的父跳點設為
  1. 繼續從 的對角線找跳點 ⇒
  1. 的直線方向找到跳點 ,將跳點 的父跳點設為
  1. 得到路徑 ,因兩者無法走直線及對角線 ⇒ 需要加入中間拐點
  1. 往對角線走 3 步,將節點 設為中間拐點
  1. 最終路徑為
  • 未剪枝 vs. 剪枝
    • 未剪枝:
    • 剪枝:
JPS-BitPre
  • 不支援動態阻擋
  • 空間換取時間
  • 前處理的內容: 每個點儲存八個方向分別可以走幾步
最後一個例子
notion image
  1. 取出節點
  1. 取出八個方向最多走幾步,將該方向最遠可抵達的節點找出來
  1. 滿足定義二第三條,加入 openset
  1. 滿足定義二第二條,加入 openset
  1. 剩下的節點中,因為終點 位於 左下方,因此只考慮方向同為左下角的
  1. 的對角線走 步,即節點 ,加入 openset
  1. 從 openset 中取出 值最小的節點 ,垂直方向找到跳點 ,加入 openset
  1. 從 openset 中取出 值最小的節點 ,搜索結束
  1. 路徑為
Ref
 
無職轉生2024 日本畢旅
Loading...
Zixu
Zixu
Welcome to my webstie.
Analytics
Post Count:
224
Latest posts
還好我退了 部隊篇
2025/08/08
泡泡
2025/08/05
還好我退了 新訓篇
2025/08/02
大學畢業心得
2025/07/12
AP325 隨筆
2025/06/07
Lycoris Recoil 莉可麗絲
2025/05/04