青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

   C++ 技術中心

   :: 首頁 :: 聯系 ::  :: 管理
  160 Posts :: 0 Stories :: 87 Comments :: 0 Trackbacks

公告

鄭重聲明:本BLOG所發表的原創文章,作者保留一切權利。必須經過作者本人同意后方可轉載,并注名作者(天空)和出處(CppBlog.com)。作者Email:coder@luckcoder.com

留言簿(27)

搜索

  •  

最新隨筆

最新評論

評論排行榜

AOI主要有九宮格、燈塔和十字鏈表的算法實現。本文闡述十字鏈表的實現和嘗試。

1. 基本原理

根據二維地圖,將其分成x軸和y軸兩個鏈表。如果是三維地圖,則還需要維護多一個z軸的鏈表。將對象的坐標值按照大小相應的排列在相應的坐標軸上面。

2. 基本接口

對對象的操作主要有以下三個接口:

  • add:對象進入地圖;
  • leave:對象離開地圖;
  • move:對象在地圖內移動。

2. 算法實現

既然是鏈表,很自然地想到用線性表來實現。因為存在向前和向后找的情況,所以使用雙鏈表實現。其實實現也是非常簡單,就是兩個雙鏈表(這里以二維地圖舉例)。那么我們的節點需要四個指針,分布為x軸的前后指針,y軸的前后指針。

// 雙鏈表(對象)
class DoubleNode
{
public:
    DoubleNode(string key, int x, int y)
    {
        this->key = key;
        this->x = x;
        this->y = y;
        xPrev = xNext = NULL;
    };
    
    DoubleNode * xPrev;
    DoubleNode * xNext;
    
    DoubleNode * yPrev;
    DoubleNode * yNext;
    
    string key;  // 只是一個關鍵字
    int x; // 位置(x坐標)
    int y; // 位置(y坐標)

private:

};

下面是地圖場景信息和接口。這里的實現比較粗略,是帶頭尾的的雙鏈表,暫時不考慮空間占用的問題。類Scene有分別有一個頭尾指針,初始化的時候會為其賦值,主要用DoubleNode類的指針來存儲x軸和y軸的頭尾。初始化的時候,將_head的next指針指向尾_tail;將_tail的prev指針指向_head
// 地圖/場景
class Scene
{
public:
    Scene()
    {
        this->_head = new DoubleNode("[head]", 0, 0); // 帶頭尾的雙鏈表(可優化去掉頭尾)
        this->_tail = new DoubleNode("[tail]", 0, 0);
        _head->xNext = _tail;
        _head->yNext = _tail;
        _tail->xPrev = _head;
        _tail->yPrev = _head;
    };

    // 對象加入(新增)
    DoubleNode * Add(string name, int x, int y);

    // 對象離開(刪除)
    void Leave(DoubleNode * node);

    // 對象移動
    void Move(DoubleNode * node, int x, int y);

    // 獲取范圍內的AOI (參數為查找范圍)
    void PrintAOI(DoubleNode * node, int xAreaLen, int yAreaLen);

private:
    DoubleNode * _head;
    DoubleNode * _tail;
};

2.1. add(進入地圖)

DoubleNode對象插入到十字鏈表中。x軸和y軸分別處理,處理方法基本一致。其實就是雙鏈表的數據插入操作,需要從頭開始遍歷線性表,對比相應軸上的值的大小,插入到合適的位置。

void _add(DoubleNode * node)
{
    // x軸處理
    DoubleNode * cur = _head->xNext;
    while(cur != NULL)
    {
        if((cur->x > node->x) || cur==_tail) // 插入數據
        {
            node->xNext = cur;
            node->xPrev = cur->xPrev;
            cur->xPrev->xNext = node;
            cur->xPrev = node;
            break;
        }
        cur = cur->xNext;
    }

    // y軸處理
    cur = _head->yNext;
    while(cur != NULL)
    {
        if((cur->y > node->y) || cur==_tail) // 插入數據
        {
            node->yNext = cur;
            node->yPrev = cur->yPrev;
            cur->yPrev->yNext = node;
            cur->yPrev = node;
            break;
        }
        cur = cur->yNext;
    }
}

假設可視范圍為x軸2以內,y軸2以內,則運行:

  1. 分別插入以下數據a(1,5)、f(6,6)、c(3,1)、b(2,2)、e(5,3),然后插入d(3,3),按照x軸和y軸打印其雙鏈表結果;
  2. 插入d(3,3)數據,求其可視AOI范圍(如圖,除了f(6,6),其它對象都在d的可視范圍內)。

控制臺結果(前8行):

步驟1結果圖示:

步驟2結果圖示:

2.2. leave(離開地圖)和move(移動)

其實都是雙鏈表的基本操作,斷掉其相應的指針就好了。按理,是需要

move和leave操作如圖,move是將d(3,3)移動到(4,4),然后再打印其AOI范圍。

控制臺結果:

移動后AOI范圍圖示:


3. 完整代碼實例
// ConsoleApplication2.cpp : 定義控制臺應用程序的入口點。
//

#include "stdafx.h"


#include "stdafx.h"
#include "stdio.h"
#include <iostream>
#include <string>

using namespace std;

// 雙鏈表(對象)
class DoubleNode
{
public:
    DoubleNode(string key, int x, int y)
    {
        this->key = key;
        this->x = x;
        this->y = y;
        xPrev = xNext = NULL;
    };

    DoubleNode * xPrev;
    DoubleNode * xNext;

    DoubleNode * yPrev;
    DoubleNode * yNext;

    string key;
    int x; // 位置(x坐標)
    int y; // 位置(y坐標)

private:

};




// 地圖/場景
class Scene
{
public:

    Scene()
    {
        this->_head = new DoubleNode("[head]", 0, 0); // 帶頭尾的雙鏈表(可優化去掉頭尾)
        this->_tail = new DoubleNode("[tail]", 0, 0);
        _head->xNext = _tail;
        _head->yNext = _tail;
        _tail->xPrev = _head;
        _tail->yPrev = _head;
    };

    // 對象加入(新增)
    DoubleNode * Add(string name, int x, int y)
    {

        DoubleNode * node = new DoubleNode(name, x, y);
        _add(node);
        return node;
    };

    // 對象離開(刪除)
    void Leave(DoubleNode * node)
    {
        node->xPrev->xNext = node->xNext;
        node->xNext->xPrev = node->xPrev;
        node->yPrev->yNext = node->yNext;
        node->yNext->yPrev = node->yPrev;

        node->xPrev = NULL;
        node->xNext = NULL;
        node->yPrev = NULL;
        node->yNext = NULL;
    };

    // 對象移動
    void Move(DoubleNode * node, int x, int y)
    {
        Leave(node);
        node->x = x;
        node->y = y;
        _add(node);
    };

    // 獲取范圍內的AOI (參數為查找范圍)
    void PrintAOI(DoubleNode * node, int xAreaLen, int yAreaLen)
    {
        cout << "Cur is: " << node->key << "(" << node->x << "," << node->y << ")" << endl;
        cout << "Print AOI:" << endl;

        // 往后找
        DoubleNode * cur = node->xNext;
        while (cur != _tail)
        {
            if ((cur->x - node->x) > xAreaLen)
            {
                break;
            }
            else
            {
                int inteval = 0;
                inteval = node->y - cur->y;
                if (inteval >= -yAreaLen && inteval <= yAreaLen)
                {
                    cout << "\t" << cur->key << "(" << cur->x << "," << cur->y << ")" << endl;
                }
            }
            cur = cur->xNext;
        }

        // 往前找
        cur = node->xPrev;
        while (cur != _head)
        {
            if ((node->x - cur->x) > xAreaLen)
            {
                break;
            }
            else
            {
                int inteval = 0;
                inteval = node->y - cur->y;
                if (inteval >= -yAreaLen && inteval <= yAreaLen)
                {
                    cout << "\t" << cur->key << "(" << cur->x << "," << cur->y << ")" << endl;
                }
            }
            cur = cur->xPrev;
        }
    };

    // 調試代碼
    void PrintLink()  // 打印鏈表(從頭開始)
    {
        // 打印x軸鏈表
        DoubleNode * cur = _head->xNext;
        while (cur != _tail)
        {
            cout << (cur->key) << "(" << (cur->x) << "," << (cur->y) << ") -> ";
            cur = cur->xNext;
        }
        cout << "end" << endl;

        // 打印y軸鏈表
        cur = _head->yNext;
        while (cur != _tail)
        {
            cout << (cur->key) << "(" << (cur->x) << "," << (cur->y) << ") -> ";
            cur = cur->yNext;
        }
        cout << "end" << endl;
    };

private:
    DoubleNode * _head;
    DoubleNode * _tail;

    void _add(DoubleNode * node)
    {
        // x軸處理
        DoubleNode * cur = _head->xNext;
        while (cur != NULL)
        {
            if ((cur->x > node->x) || cur == _tail) // 插入數據
            {
                node->xNext = cur;
                node->xPrev = cur->xPrev;
                cur->xPrev->xNext = node;
                cur->xPrev = node;
                break;
            }
            cur = cur->xNext;
        }

        // y軸處理
        cur = _head->yNext;
        while (cur != NULL)
        {
            if ((cur->y > node->y) || cur == _tail) // 插入數據
            {
                node->yNext = cur;
                node->yPrev = cur->yPrev;
                cur->yPrev->yNext = node;
                cur->yPrev = node;
                break;
            }
            cur = cur->yNext;
        }
    }
};

// --------------------------------------------

int _tmain(int argc, _TCHAR* argv[])
{
    Scene scene = Scene();
    // 增加
    scene.Add("a", 1, 5);
    scene.Add("f", 6, 6);
    scene.Add("c", 3, 1);
    scene.Add("b", 2, 2);
    scene.Add("e", 5, 3);
    DoubleNode * node = scene.Add("d", 3, 3);

    scene.PrintLink();
    scene.PrintAOI(node, 2, 2);

    // 移動
    cout << endl << "[MOVE]" << endl;
    scene.Move(node, 4, 4);
    scene.PrintLink();

    scene.PrintAOI(node, 2, 2);

    // 刪除
    cout << endl << "[LEAVE]" << endl;
    scene.Leave(node);
    scene.PrintLink();

}

算法的大概思想如下.每個場景維護兩個鏈表,分別為X軸和Y軸的坐標按序排列好的鏈表,也就是比如在X軸鏈表上,越在前的對象,X坐標越小,Y軸鏈表同理.這樣,每次需要更新狀態的時候,只需要在這個鏈表上向前或者向后遍歷結點就知道該通知誰了.

這里假設有三個API:Add(向場景中添加一個對象),Leave(某對象離開場景),Move(某對象在場景中移動).

來一個一個看.

Add:根據新增對象的X,Y坐標,依次遍歷X,Y軸坐標鏈表,這里有兩個目的,一個是獲得這個新增對象的坐標在X,Y軸坐標的位置,另一方面獲得該通知哪些結點.通知的范圍,每個對象可以自己定制自己的通知范圍.但是為了簡單起見,在這里我們假設每個結點X,Y坐標相差1,而通知的范圍是2.比如原有的X軸坐標為:
a->b->c->d->e->f->g->h
假設新增一個對象z,它最終所在的位置是c和d之間,根據前面的假設,它只需要通知b,c,e,f四個結點就好了.所以,新增一個結點的時候,并不需要遍歷完鏈表的.
但是這里還需要注意的是,一個結點,必須X,Y坐標同時都在通知范圍內才可以進入通知集合.

Leave:在添加了對象之后,對象身上掛了兩個結點,分別存放在X,Y軸坐標鏈表上的位置,那么在這個對象要離開場景時,也只需要向前向后探索一定的范圍,就可以得到需要通知該對象要離開的集合了.

Move:移動操作比較麻煩,但是也可以比較漂亮的解決.在更新位置之前,同樣根據前面的算法得到要通知的結點集合,稱為old_set;更新位置之后,再獲取另一個通知集合,稱為new_set;然后,old_set和new_set的交集,稱為move_set,在此集合中的結點,在移動前后都在通知范圍,因此要向這個集合的結點發送該對象移動的消息;而old_set-move_set的集合,在移動之后已經離開了視野,因此要向它們發送該對象離開的消息;最后,new_set-move_set是移動之后才看見該結點的結點集合,這個集合的結點,要發送該結點進入場景的消息.

posted on 2017-03-07 15:09 C++技術中心 閱讀(1908) 評論(0)  編輯 收藏 引用 所屬分類: 游戲開發
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美日韩亚洲一区| 99精品国产福利在线观看免费| 亚洲制服av| 免费亚洲视频| 亚洲免费综合| 欧美日韩国产成人高清视频| 国产在线精品自拍| 午夜亚洲性色福利视频| 免费日韩视频| 欧美一区二区三区日韩视频| 国产精品v欧美精品∨日韩| 亚洲激情视频网站| 久久一区免费| 久久精品观看| 国产一区二区三区无遮挡| 亚洲欧美三级伦理| 一本一本久久| 国产精品捆绑调教| 亚洲一区免费视频| 亚洲免费中文字幕| 亚洲国产欧美日韩| 午夜精品久久久久久久99水蜜桃| 国产精品第一页第二页第三页| 一区二区三区蜜桃网| 亚洲人屁股眼子交8| 欧美精品福利| 在线视频你懂得一区| 亚洲美女视频在线观看| 欧美日韩成人激情| 亚洲网站在线播放| 亚洲女性喷水在线观看一区| 国产区精品视频| 久久―日本道色综合久久| 欧美在线播放一区二区| 一色屋精品亚洲香蕉网站| 蜜臀99久久精品久久久久久软件| 亚洲欧美一区二区三区在线| 99成人精品| 国产精品一区二区三区观看| 欧美中文日韩| 久久精品欧美日韩精品| 亚洲激情中文1区| 日韩视频一区二区三区在线播放免费观看| 欧美福利电影在线观看| 中文av一区特黄| 亚洲一区国产精品| 精品999日本| 亚洲国产高清aⅴ视频| 欧美另类一区| 欧美伊人久久| 老司机一区二区三区| 99国产精品私拍| 亚洲永久精品大片| 亚洲高清一区二| 一区二区免费看| 黄色欧美成人| 99精品热6080yy久久| 国内精品久久久久影院色| 亚洲第一区在线| 国产精品推荐精品| 欧美福利在线| 国产欧美一区二区色老头 | 亚洲欧美另类中文字幕| 欧美一二区视频| 亚洲毛片在线观看.| 亚洲综合国产| 亚洲精品日韩综合观看成人91| 亚洲自拍都市欧美小说| 亚洲精品久久久久中文字幕欢迎你 | 亚洲精品视频在线看| 亚洲一级二级| 欧美新色视频| 久久久午夜精品| 国产精品国产亚洲精品看不卡15| 免费日本视频一区| 国产精品福利av| 亚洲国产美女精品久久久久∴| 国内精品99| 亚洲欧美国产精品桃花| 99视频有精品| 女人香蕉久久**毛片精品| 久久国产毛片| 国产精品一区二区久久| 中文国产成人精品久久一| 日韩午夜在线观看视频| 你懂的视频欧美| 欧美大色视频| 亚洲国产成人久久| 久久五月天婷婷| 毛片一区二区| 激情久久久久久久久久久久久久久久| 亚洲性人人天天夜夜摸| 午夜精品久久久久久久蜜桃app| 欧美日韩视频在线观看一区二区三区| 欧美成人在线影院| 亚洲国产色一区| 久久久福利视频| 国产在线播放一区二区三区| 欧美一级精品大片| 欧美一区二区在线免费观看| 国产精品一区一区三区| 亚洲欧美国产毛片在线| 久久久久久高潮国产精品视| 国产视频一区免费看| 欧美在线视频二区| 久久频这里精品99香蕉| 国产亚洲欧美激情| 欧美一区二区三区在线观看视频| 久久xxxx精品视频| 好看不卡的中文字幕| 亚洲午夜久久久久久久久电影院| 小黄鸭精品密入口导航| 国产精品vip| 国产精品99久久久久久人| 一本色道久久综合狠狠躁篇的优点 | 久久国产精品免费一区| 欧美亚洲综合网| 国产精品一二一区| 久久久欧美一区二区| 久久综合影音| 亚洲高清在线| 欧美刺激性大交免费视频| 欧美激情一区二区三区在线视频观看| 欧美性事在线| 久久se精品一区二区| 久久蜜桃精品| 亚洲国产婷婷综合在线精品| 免费观看成人www动漫视频| 久久人人爽爽爽人久久久| 在线欧美一区| 国产精品videossex久久发布| 这里只有精品丝袜| 欧美一级视频精品观看| 国产一级久久| 玖玖玖免费嫩草在线影院一区| 欧美成人免费小视频| 亚洲风情亚aⅴ在线发布| 欧美激情1区2区3区| 91久久精品一区| 亚洲无亚洲人成网站77777 | 久久男人av资源网站| 精品二区视频| 老司机精品视频网站| 亚洲特色特黄| 国产婷婷色一区二区三区四区| 久久久水蜜桃| 亚洲免费激情| 久久精品水蜜桃av综合天堂| 亚洲国产成人不卡| 国产精品盗摄久久久| 久久精品国产99精品国产亚洲性色 | 欧美性片在线观看| 中国成人在线视频| 美女日韩欧美| 中文久久精品| 一区视频在线播放| 欧美私人网站| 久久偷看各类wc女厕嘘嘘偷窃| 久久中文字幕导航| 午夜性色一区二区三区免费视频| 极品av少妇一区二区| 欧美一区二区成人6969| 欧美不卡在线视频| 亚洲天堂av电影| 亚洲国产cao| 国产精品区一区二区三| 欧美日韩精品一二三区| 久久精品国产99| 亚洲精品麻豆| 欧美69视频| 久久激情视频久久| 一本色道久久| 亚洲国产精品va| 国产一区二区无遮挡| 欧美三级视频在线观看| 免费成人网www| 久久精品视频导航| 午夜日韩电影| 一区二区三区四区五区视频 | 欧美精品观看| 亚洲免费影视| 亚洲国产一区二区三区在线播 | 欧美理论电影在线播放| 午夜欧美大尺度福利影院在线看 | 欧美一区二区在线观看| 国内久久婷婷综合| 国产精品麻豆成人av电影艾秋| 欧美成人一区二区三区| 欧美电影免费观看网站 | 午夜精品久久久久久久久久久久| 亚洲欧洲日本国产| 免费久久99精品国产自| 亚洲欧美一区二区精品久久久| 洋洋av久久久久久久一区| 一道本一区二区| 欧美日韩视频免费播放| 欧美极品影院| 欧美精品18| 欧美日韩另类一区| 黄网动漫久久久|