我們可以預知,該方法在個體總數較小的時候效率較高,一旦個體數突破上百個,就很容易造成極大的cpu開銷,所以此處我們需要研究出另外的索引方案來得到鄰居。
空間劃分的方案主流的有很多,例如四叉樹,八叉樹,bsp樹,四叉樹主要用於資料庫的底層方案,它會將二維的點轉化為一條有規律的曲線;八叉樹是四叉樹的3d版;bsp樹是三維的空間二分;這幾種主流演算法對於我這款遊戲都不合適,此處我們介紹兩個不是很常見的演算法,cell space和geo hash。
我們想象如下的場景:很常見的情況,我們注意到,當我們不知道地理位置的時候,我們會查詢「標誌性建築」,cell_space_partition(以下簡稱csp)就是引用了這樣一種思路:通過hash(索引)來減少遍歷的難度或者廣度。(筆者最近在思考有沒有可能性直接用一種關聯啟發演算法,來實現這種多對多的劃分邏輯)y君上了計程車
y:「師傅,到xx小區。」
計程車司機:「xx小區在哪兒啊?」
y:」就在電視塔附近。「
這種空間劃分是將二維空間劃分為小方格仔,然後每個小方格存放個體指標的集合,我們在查詢個體鄰居的時候就只需要遍歷小方格裡的個體集合。
#pragma once
#include"baseentity.h"
#include
#include"cocos2d.h"
using
namespace cocos2d;
struct cell
};class cellspacepartition
;cellspacepartition::cellspacepartition(rect spacesize, int cellnumx, int cellnumy) :
_spacerect(spacesize),
_cellnumx(cellnumx),
_cellnumy(cellnumy)
}}void cellspacepartition::addentity(baseentity* entity)
int cellspacepartition::positiontoindex(const vec2 position)const
void cellspacepartition::updateentity(baseentity* entity, vec2 old_position)
}std::vector
cellspacepartition::getneighbors(vec2 position,double radius)
});//end for each
}}//end for
return neighbors;
}
大家可以看到,很簡單的**,此處我們將空間劃分的方格數目固定,當然也可以用固定大小的方格。
在面對運動的個體時,我們需要在物體產生位移的同時更新它的所屬方塊。
如果你開發過基於lbs+的地圖程式,你應該對這個演算法很熟悉了,但是應用在遊戲上還是大姑娘上轎——頭一回!真令人興奮,我們每當做出一小步創新,人類的科技就會有乙個大的進步。
我在此就不班門弄斧介紹這種演算法了,我講一下我的實現。
難點有幾個:
- c++內部對2進製變數的處理比較糟糕
- 我們需要寫乙個base32編碼的方法,而且要盡量高效,一旦該方法不高效,那反而會比空間劃分以前更慢
- 我們需要寫乙個資料庫查詢的like演算法,其實也就是基本模糊查詢,筆者的資料庫知識非常尷尬:),這一塊在找做資料庫的朋友幫忙講解一下
基本步驟:
- 1·為位址結構新增string型別儲存hash值
- 2·傳入乙個地理資訊point(x,y),對其x和y值做如下操作
- 3·將其不斷二分,此處我們使用遞迴方案,屬於左區間值為0或者1,右區間與之相反
- 4·小於設定精度後,結束二分(此處的精度需要根據你的hash字串長度和整個地圖大小來計算)
- 5·我們將x,y值復合,偶數字為x或者y,奇數字為另乙個
- 6·我們這時得到一串二進位製碼,對其進行base32編碼
- 7·得到geohash值
關於base32編碼,就是把二進位制數轉換為32進製數,5位代表乙個32進製數,此處的編碼表為約定版本,詳情見**關於like方法,由於對效率至關重要,所以筆者不敢妄下定論,大家有好的方案可以m我
class geohash
protected://convert to base32 code
string base32encoding(string);
public:
static
string getindex(vec2);//get geohash code
static
bool like(string,string);
std::vector
getneighbors(vec2, std::vector
);};
char geohash::base32_encode = ;
string geohash::base32encoding(string bitstr)
int refer = 0;
for (int j = 0; j < 5; j++)
outputstr.push_back(base32_encode[refer]);
}if (bitstr.length > count * 5)//push '0' to fill the rest
int refer = 0;
for (int j = 0; j < 5; j++)
outputstr.push_back(base32_encode[refer]);
}return outputstr;
}string geohash::getindex(vec2 po)
return base32encoding(totalbit);
}void geohash::halfdivision(double min, double max, double value,string& bit)
if (between(value, min, (min + max) / 2))
else
}bool geohash::like(string index1,string index2)
}std::vector
geohash::getneighbors(vec2 centre, vector
preselectedentities)
);}
該演算法筆者還沒有進行全面測試,估計在處理靜態物體,超大空間的時候效率會遠遠高於csp,畢竟後者在儲存空間格仔申請的記憶體就會讓處理器**。
這兩種演算法有乙個好處,將額外的計算開銷(csp空間格仔的指標操作,geohash額外的索引計算)平均分配,位置改變是一直進行的,所以cpu的開銷就變成非同步的了。總體來看,總的計算量增加了,然而卻被分配到了實體們每次發生位移時候,計算效率當然大大提高。
劃分字母空間
字串 s 由小寫字母組成。我們要把這個字串劃分為盡可能多的片段,同一字母最多出現在乙個片段中。返回乙個表示每個字串片段的長度的列表。示例 輸入 s ababcbacadefegdehijhklij 輸出 9,7,8 解釋 劃分結果為 ababcbaca defegde hijhklij 每個字母最多...
Z劃分空間
具體數學第一章第二節的問題,knuth寫的 zoj 1652 數論 這題木有思路啊。盜用下別人的分析 分析 典型的遞推題 設f n 表示n個z字型折線至多平面劃分數。現在增加一條邊a,和3n條線都相交,增加3n 1個區域。再增加一條邊b,與a平行,同樣增加3n 1個區域。最後增加一條邊c,與已有的邊...
python底層的邏輯回歸
python底層的邏輯演算法 回歸 回歸是統計學的乙個重要概念,其本意是根據之前的資料 乙個準確的輸出值。邏輯回歸是 機器學習 這門課的第三個演算法,它是目前使用最為廣泛的一種學習演算法,用於解決分類問題。與線性回歸演算法一樣,也是監督學習演算法。諸如 新聞分類 基因序列 市場劃分等的一些根據特徵劃...