编程语言
首页 > 编程语言> > javascript – 提高交错列等距网格上点击检测的性能

javascript – 提高交错列等距网格上点击检测的性能

作者:互联网

我正在研究等距游戏引擎,并且已经为像素完美点击检测创建了算法.访问project,注意点击检测能够检测到点击了哪个边缘.它还会检查y-index以单击最前面的磁贴.

我当前算法的解释:

等距网格由100 * 65px的平铺图像组成.
TileW = 100,TileL = 50,tileH = 15

Sizing of tile

地图由三维阵列图[z] [y] [x]表示.

平铺中心点(x,y)的计算如下:

//x, y, z are the position of the tile

if(y%2===0) { x-=-0.5; }    //To accommodate the offset found in even rows
this.centerX = (x*tileW) + (tileW/2);
this.centerY = (y*tileL) - y*((tileL)/2) + ((tileL)/2) + (tileH/2) - (z*tileH);

Isometric grid

用于确定鼠标是否位于磁贴上给定区域内的原型函数:

Tile.prototype.allContainsMouse = function() {
    var dx = Math.abs(mouse.mapX-this.centerX),
        dy = Math.abs(mouse.mapY-this.centerY);

    if(dx>(tileW/2)) {return false;}    //Refer to image
    return (dx/(tileW*0.5) + (dy/(tileL*0.5)) < (1+tileHLRatio));
}

如果鼠标在绿色范围内,Tile.prototype.allContainsMouse()将返回true.通过检查是否dx>来裁剪红色区域.瓷砖宽度的一半

Figure 1

Tile.prototype.topContainsMouse = function() {
    var topFaceCenterY = this.centerY - (tileH/2);
    var dx = Math.abs(mouse.mapX-this.centerX),
        dy = Math.abs(mouse.mapY-topFaceCenterY);

    return ((dx/(tileW*0.5) + dy/(tileL*0.5) <= 1));
};

Returns true if mouse is on top face

Tile.prototype.leftContainsMouse = function() {
    var dx = mouse.mapX-this.centerX;
    if(dx<0) { return true; } else { return false; }
};

(如果鼠标留在中心点)

Tile.prototype.rightContainsMouse = function() {
    var dx = mouse.mapX-this.centerX;
    if(dx>0) { return true; } else { return false; }
};

(如果鼠标位于中心点右侧)

将所有方法整合在一起工作:

>循环遍历整个三维地图[z] [y] [x]数组
>如果allContainsMouse()返回true,则map [z] [y] [x]是我们鼠标所在的图块.
>将此图块添加到数组tilesUnderneathMouse数组中.
>遍历tilesUnderneathMouse数组,并选择y最高的磁贴.这是最前沿的瓷砖.

if(allContainsMouse && !topContainsMouse)

Bottom match

>

if(allContainsMouse && !topContainsMouse && leftContainsMouse)

left match

(类似的概念适用于权利)

最后,我的问题:

#1您将如何实现这一目标,以便更高效(不循环遍历所有磁贴)(接受pesudo代码)

#2如果你无法回答#1,你有什么建议来提高点击检测的效率(已经考虑了块加载)

我想到的是:

我最初试图通过不使用平铺中心点来解决这个问题,而是将鼠标(x,y)位置直接转换为平铺x,y.在我看来,这是最难编码,但最有效的解决方案.在正方形网格上,将(x,y)位置转换为网格上的正方形非常容易.但是,在交错列网格中,您可以处理偏移量.我尝试使用带有x或y值的函数计算偏移量,并返回结果偏移量y或x. arccos(cosx)的Zig-zag图解决了这个问题.

检查鼠标是否在瓷砖内,使用这种方法很困难,我无法弄明白.我正在检查鼠标(x,y)是否在y = mx b线下面,该线依赖于tileX,tileY近似(约为正方形网格).

如果你到了这里,谢谢!

解决方法:

这个答案基于:

> 2D grid image values to 2D array

所以这里:

>网格和屏幕之间的转换

正如我在评论中提到的,你应该创建在屏幕和单元格位置之间转换的函数.像(在C中):

//---------------------------------------------------------------------------
// tile sizes
const int cxs=100;
const int cys= 50;
const int czs= 15;
const int cxs2=cxs>>1;
const int cys2=cys>>1;
// view pan (no zoom)
int pan_x=0,pan_y=0;
//---------------------------------------------------------------------------
void isometric::cell2scr(int &sx,int &sy,int cx,int cy,int cz) // grid -> screen
    {
    sx=pan_x+(cxs*cx)+((cy&1)*cxs2);
    sy=pan_y+(cys*cy/2)-(czs*cz);
    }
//---------------------------------------------------------------------------
void isometric::scr2cell(int &cx,int &cy,int &cz,int sx,int sy) // screen -> grid
    {
    // rough cell ground estimation (no z value yet)
    cy=(2*(sy-pan_y))/cys;
    cx=   (sx-pan_x-((cy&1)*cxs2))/cxs;
    cz=0;
    // isometric tile shape crossing correction
    int xx,yy;
    cell2scr(xx,yy,cx,cy,cz);
    xx=sx-xx; mx0=cx;
    yy=sy-yy; my0=cy;
    if (xx<=cxs2) { if (yy>     xx *cys/cxs) { cy++; if (int(cy&1)!=0) cx--; } }
    else          { if (yy>(cxs-xx)*cys/cxs) { cy++; if (int(cy&1)==0) cx++; } }
    }
//---------------------------------------------------------------------------

我使用了你的布局(花了很多时间把我的转换成它,希望我不会在某处犯一些愚蠢的错误):

layout

> red cross表示cell2scr返回的坐标(x,y,0,0,0)
>绿色十字表示鼠标坐标
>浅绿色突出显示返回的细胞位置

请注意,如果你使用整数算术,你需要记住,如果你划分/乘以一半大小,你可能会失去精度.对于这种情况,使用完整大小并将结果除以2(花费大量时间来确定过去的结果).

cell2scr非常简单.屏幕位置是平移偏移单元位置乘以其大小(步骤). x轴需要校正偶数/奇数行(即((cy& 1)* cxs2))和y轴偏移z轴(((cy& 1)* cxs2)).我的屏幕左上角有点(0,0),x轴指向右边,y指向下方.

scr2cell由cell2scr的等式中的代数求解的屏幕位置完成,同时假设z = 0,因此仅选择网格地面.最重要的是,如果鼠标位置在找到的单元格区域之外,则添加偶数/奇数校正.
>扫描邻居

scr2cell(x,y,z,mouse_x,mouse_y)只返回鼠标在地面上的单元格.因此,如果要添加当前选择功能,则需要扫描该位置上的顶部单元格以及几个相邻单元格,并选择距离最小的单元格.

无需扫描整个网格/地图只返回返回位置周围的几个单元格.这应该会大大加快速度.

我是这样做的:

scan pattern

行数取决于单元z轴大小(czs),z层的最大数量(gzs)和单元大小(cys).我扫描的C代码如下所示:

// grid size
const int gxs=15;
const int gys=30;
const int gzs=8;
// my map (all the cells)
int map[gzs][gys][gxs];

void isometric::scr2cell(int &cx,int &cy,int &cz,int sx,int sy)
    {
    // rough cell ground estimation (no z value yet)
    cy=(2*(sy-pan_y))/cys;
    cx=   (sx-pan_x-((cy&1)*cxs2))/cxs;
    cz=0;
    // isometric tile shape crossing correction
    int xx,yy;
    cell2scr(xx,yy,cx,cy,cz);
    xx=sx-xx;
    yy=sy-yy;
    if (xx<=cxs2) { if (yy>     xx *cys/cxs) { cy++; if (int(cy&1)!=0) cx--; } }
    else          { if (yy>(cxs-xx)*cys/cxs) { cy++; if (int(cy&1)==0) cx++; } }
    // scan closest neighbors
    int x0=-1,y0=-1,z0=-1,a,b,i;

    #define _scann                                                          \
    if ((cx>=0)&&(cx<gxs))                                                  \
     if ((cy>=0)&&(cy<gys))                                                 \
        {                                                                   \
        for (cz=0;(map[cz+1][cy][cx]!=_cell_type_empty)&&(cz<czs-1);cz++);  \
        cell2scr(xx,yy,cx,cy,cz);                                           \
        if (map[cz][cy][cx]==_cell_type_full) yy-=czs;                      \
        xx=(sx-xx); yy=((sy-yy)*cxs)/cys;                                   \
        a=(xx+yy);  b=(xx-yy);                                              \
        if ((a>=0)&&(a<=cxs)&&(b>=0)&&(b<=cxs))                             \
         if (cz>=z0) { x0=cx; y0=cy; z0=cz; }                               \
        }
                                      _scann;   // scan actual cell
    for (i=gzs*czs;i>=0;i-=cys)                 // scan as many lines bellow actual cell as needed
        {
        cy++; if (int(cy&1)!=0) cx--; _scann;
        cx++;                         _scann;
        cy++; if (int(cy&1)!=0) cx--; _scann;
        }
    cx=x0; cy=y0; cz=z0;                        // return remembered cell coordinate

    #undef _scann
    }

当玩鼠标时,它总是选择顶部单元格(从所有可能的最高位置开始),感觉正确(至少对我来说):

scan result

这里完整的VCL / C我的等距引擎源我今天破坏了这个:

    //---------------------------------------------------------------------------
    //--- Isometric ver: 1.01 ---------------------------------------------------
    //---------------------------------------------------------------------------
    #ifndef _isometric_h
    #define _isometric_h
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    // colors       0x00BBGGRR
    DWORD col_back =0x00000000;
    DWORD col_grid =0x00202020;
    DWORD col_xside=0x00606060;
    DWORD col_yside=0x00808080;
    DWORD col_zside=0x00A0A0A0;
    DWORD col_sel  =0x00FFFF00;
    //---------------------------------------------------------------------------
    //--- configuration defines -------------------------------------------------
    //---------------------------------------------------------------------------
    //  #define isometric_layout_1  // x axis: righ+down, y axis: left+down
    //  #define isometric_layout_2  // x axis: righ     , y axis: left+down
    //---------------------------------------------------------------------------
    #define isometric_layout_2
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    /*
    // grid size
    const int gxs=4;
    const int gys=16;
    const int gzs=8;
    // cell size
    const int cxs=100;
    const int cys= 50;
    const int czs= 15;
    */
    // grid size
    const int gxs=15;
    const int gys=30;
    const int gzs=8;
    // cell size
    const int cxs=40;
    const int cys=20;
    const int czs=10;

    const int cxs2=cxs>>1;
    const int cys2=cys>>1;
    // cell types
    enum _cell_type_enum
        {
        _cell_type_empty=0,
        _cell_type_ground,
        _cell_type_full,
        _cell_types
        };
    //---------------------------------------------------------------------------
    class isometric
        {
    public:
        // screen buffer
        Graphics::TBitmap *bmp;
        DWORD **pyx;
        int xs,ys;
        // isometric map
        int map[gzs][gys][gxs];
        // mouse
        int mx,my,mx0,my0;          // [pixel]
        TShiftState sh,sh0;
        int sel_x,sel_y,sel_z;      // [grid]
        // view
        int pan_x,pan_y;
        // constructors for compiler safety
        isometric();
        isometric(isometric& a) { *this=a; }
        ~isometric();
        isometric* operator = (const isometric *a) { *this=*a; return this; }
        isometric* operator = (const isometric &a);
        // Window API
        void resize(int _xs,int _ys);                       // [pixels]
        void mouse(int x,int y,TShiftState sh);             // [mouse]
        void draw();
        // auxiliary API
        void cell2scr(int &sx,int &sy,int cx,int cy,int cz);
        void scr2cell(int &cx,int &cy,int &cz,int sx,int sy);
        void cell_draw(int x,int y,int tp,bool _sel=false);     // [screen]
        void map_random();
        };
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    isometric::isometric()
        {
        // init screen buffers
        bmp=new Graphics::TBitmap;
        bmp->HandleType=bmDIB;
        bmp->PixelFormat=pf32bit;
        pyx=NULL; xs=0; ys=0;
        resize(1,1);
        // init map
        int x,y,z,t;
        t=_cell_type_empty;
    //  t=_cell_type_ground;
    //  t=_cell_type_full;
        for (z=0;z<gzs;z++,t=_cell_type_empty)
         for (y=0;y<gys;y++)
          for (x=0;x<gxs;x++)
           map[z][y][x]=t;
        // init mouse
        mx =0; my =0; sh =TShiftState();
        mx0=0; my0=0; sh0=TShiftState();
        sel_x=-1; sel_y=-1; sel_z=-1;
        // init view
        pan_x=0; pan_y=0;
        }
    //---------------------------------------------------------------------------
    isometric::~isometric()
        {
        if (pyx) delete[] pyx; pyx=NULL;
        if (bmp) delete   bmp; bmp=NULL;
        }
    //---------------------------------------------------------------------------
    isometric* isometric::operator = (const isometric &a)
        {
        resize(a.xs,a.ys);
        bmp->Canvas->Draw(0,0,a.bmp);
        int x,y,z;
        for (z=0;z<gzs;z++)
         for (y=0;y<gys;y++)
          for (x=0;x<gxs;x++)
           map[z][y][x]=a.map[z][y][x];
        mx=a.mx; mx0=a.mx0; sel_x=a.sel_x;
        my=a.my; my0=a.my0; sel_y=a.sel_y;
        sh=a.sh; sh0=a.sh0; sel_z=a.sel_z;
        pan_x=a.pan_x;
        pan_y=a.pan_y;
        return this;
        }
    //---------------------------------------------------------------------------
    void isometric::resize(int _xs,int _ys)
        {
        if (_xs<1) _xs=1;
        if (_ys<1) _ys=1;
        if ((xs==_xs)&&(ys==_ys)) return;
        bmp->SetSize(_xs,_ys);
        xs=bmp->Width;
        ys=bmp->Height;
        if (pyx) delete pyx;
        pyx=new DWORD*[ys];
        for (int y=0;y<ys;y++) pyx[y]=(DWORD*) bmp->ScanLine[y];
        // center view
        cell2scr(pan_x,pan_y,gxs>>1,gys>>1,0);
        pan_x=(xs>>1)-pan_x;
        pan_y=(ys>>1)-pan_y;
        }
    //---------------------------------------------------------------------------
    void isometric::mouse(int x,int y,TShiftState shift)
        {
        mx0=mx; mx=x;
        my0=my; my=y;
        sh0=sh; sh=shift;
        scr2cell(sel_x,sel_y,sel_z,mx,my);
        if ((sel_x<0)||(sel_y<0)||(sel_z<0)||(sel_x>=gxs)||(sel_y>=gys)||(sel_z>=gzs)) { sel_x=-1; sel_y=-1; sel_z=-1; }
        }
    //---------------------------------------------------------------------------
    void isometric::draw()
        {
        int x,y,z,xx,yy;
        // clear space
        bmp->Canvas->Brush->Color=col_back;
        bmp->Canvas->FillRect(TRect(0,0,xs,ys));
        // grid
        DWORD c0=col_zside;
        col_zside=col_back;
        for (y=0;y<gys;y++)
         for (x=0;x<gxs;x++)
            {
            cell2scr(xx,yy,x,y,0);
            cell_draw(xx,yy,_cell_type_ground,false);
            }
        col_zside=c0;
        // cells
        for (z=0;z<gzs;z++)
         for (y=0;y<gys;y++)
          for (x=0;x<gxs;x++)
            {
            cell2scr(xx,yy,x,y,z);
            cell_draw(xx,yy,map[z][y][x],(x==sel_x)&&(y==sel_y)&&(z==sel_z));
            }
        // mouse0 cross
        bmp->Canvas->Pen->Color=clBlue;
        bmp->Canvas->MoveTo(mx0-10,my0); bmp->Canvas->LineTo(mx0+10,my0);
        bmp->Canvas->MoveTo(mx0,my0-10); bmp->Canvas->LineTo(mx0,my0+10);
        // mouse cross
        bmp->Canvas->Pen->Color=clGreen;
        bmp->Canvas->MoveTo(mx-10,my); bmp->Canvas->LineTo(mx+10,my);
        bmp->Canvas->MoveTo(mx,my-10); bmp->Canvas->LineTo(mx,my+10);
        // grid origin cross
        bmp->Canvas->Pen->Color=clRed;
        bmp->Canvas->MoveTo(pan_x-10,pan_y); bmp->Canvas->LineTo(pan_x+10,pan_y);
        bmp->Canvas->MoveTo(pan_x,pan_y-10); bmp->Canvas->LineTo(pan_x,pan_y+10);

        bmp->Canvas->Font->Charset=OEM_CHARSET;
        bmp->Canvas->Font->Name="System";
        bmp->Canvas->Font->Pitch=fpFixed;
        bmp->Canvas->Font->Color=clAqua;
        bmp->Canvas->Brush->Style=bsClear;
        bmp->Canvas->TextOutA(5, 5,AnsiString().sprintf("Mouse: %i x %i",mx,my));
        bmp->Canvas->TextOutA(5,20,AnsiString().sprintf("Select: %i x %i x %i",sel_x,sel_y,sel_z));
        bmp->Canvas->Brush->Style=bsSolid;
        }
    //---------------------------------------------------------------------------
    void isometric::cell2scr(int &sx,int &sy,int cx,int cy,int cz)
        {
        #ifdef isometric_layout_1
        sx=pan_x+((cxs*(cx-cy))/2);
        sy=pan_y+((cys*(cx+cy))/2)-(czs*cz);
        #endif
        #ifdef isometric_layout_2
        sx=pan_x+(cxs*cx)+((cy&1)*cxs2);
        sy=pan_y+(cys*cy/2)-(czs*cz);
        #endif
        }
    //---------------------------------------------------------------------------
    void isometric::scr2cell(int &cx,int &cy,int &cz,int sx,int sy)
        {
        int x0=-1,y0=-1,z0=-1,a,b,i,xx,yy;

        #ifdef isometric_layout_1
        // rough cell ground estimation (no z value yet)
        // translate to (0,0,0) top left corner of the grid
        xx=sx-pan_x-cxs2;
        yy=sy-pan_y+cys2;
        // change aspect to square cells cxs x cxs
        yy=(yy*cxs)/cys;
        // use the dot product with axis vectors to compute grid cell coordinates
        cx=(+xx+yy)/cxs;
        cy=(-xx+yy)/cxs;
        cz=0;

        // scan closest neighbors
        #define _scann                                                          \
        if ((cx>=0)&&(cx<gxs))                                                  \
         if ((cy>=0)&&(cy<gys))                                                 \
            {                                                                   \
            for (cz=0;(map[cz+1][cy][cx]!=_cell_type_empty)&&(cz<czs-1);cz++);  \
            cell2scr(xx,yy,cx,cy,cz);                                           \
            if (map[cz][cy][cx]==_cell_type_full) yy-=czs;                      \
            xx=(sx-xx); yy=((sy-yy)*cxs)/cys;                                   \
            a=(xx+yy);  b=(xx-yy);                                              \
            if ((a>=0)&&(a<=cxs)&&(b>=0)&&(b<=cxs))                             \
             if (cz>=z0) { x0=cx; y0=cy; z0=cz; }                               \
            }
                      _scann;           // scan actual cell
        for (i=gzs*czs;i>=0;i-=cys)     // scan as many lines bellow actual cell as needed
            {
            cy++;       _scann;
            cx++; cy--; _scann;
            cy++;       _scann;
            }
        cx=x0; cy=y0; cz=z0;            // return remembered cell coordinate
        #undef _scann
        #endif

        #ifdef isometric_layout_2
        // rough cell ground estimation (no z value yet)
        cy=(2*(sy-pan_y))/cys;
        cx=   (sx-pan_x-((cy&1)*cxs2))/cxs;
        cz=0;
        // isometric tile shape crossing correction
        cell2scr(xx,yy,cx,cy,cz);
        xx=sx-xx;
        yy=sy-yy;
        if (xx<=cxs2) { if (yy>     xx *cys/cxs) { cy++; if (int(cy&1)!=0) cx--; } }
        else          { if (yy>(cxs-xx)*cys/cxs) { cy++; if (int(cy&1)==0) cx++; } }
        // scan closest neighbors
        #define _scann                                                          \
        if ((cx>=0)&&(cx<gxs))                                                  \
         if ((cy>=0)&&(cy<gys))                                                 \
            {                                                                   \
            for (cz=0;(map[cz+1][cy][cx]!=_cell_type_empty)&&(cz<czs-1);cz++);  \
            cell2scr(xx,yy,cx,cy,cz);                                           \
            if (map[cz][cy][cx]==_cell_type_full) yy-=czs;                      \
            xx=(sx-xx); yy=((sy-yy)*cxs)/cys;                                   \
            a=(xx+yy);  b=(xx-yy);                                              \
            if ((a>=0)&&(a<=cxs)&&(b>=0)&&(b<=cxs))                             \
             if (cz>=z0) { x0=cx; y0=cy; z0=cz; }                               \
            }
                                          _scann;   // scan actual cell
        for (i=gzs*czs;i>=0;i-=cys)                 // scan as many lines bellow actual cell as needed
            {
            cy++; if (int(cy&1)!=0) cx--; _scann;
            cx++;                         _scann;
            cy++; if (int(cy&1)!=0) cx--; _scann;
            }
        cx=x0; cy=y0; cz=z0;                        // return remembered cell coordinate
        #undef _scann
        #endif
        }
    //---------------------------------------------------------------------------
    void isometric::cell_draw(int x,int y,int tp,bool _sel)
        {
        TPoint pnt[5];
        bmp->Canvas->Pen->Color=col_grid;
        if (tp==_cell_type_empty)
            {
            if (!_sel) return;
            bmp->Canvas->Pen->Color=col_sel;
            pnt[0].x=x;      pnt[0].y=y     ;
            pnt[1].x=x+cxs2; pnt[1].y=y+cys2;
            pnt[2].x=x+cxs;  pnt[2].y=y     ;
            pnt[3].x=x+cxs2; pnt[3].y=y-cys2;
            pnt[4].x=x;      pnt[4].y=y     ;
            bmp->Canvas->Polyline(pnt,4);
            }
        else if (tp==_cell_type_ground)
            {
            if (_sel) bmp->Canvas->Brush->Color=col_sel;
            else      bmp->Canvas->Brush->Color=col_zside;
            pnt[0].x=x;      pnt[0].y=y     ;
            pnt[1].x=x+cxs2; pnt[1].y=y+cys2;
            pnt[2].x=x+cxs;  pnt[2].y=y     ;
            pnt[3].x=x+cxs2; pnt[3].y=y-cys2;
            bmp->Canvas->Polygon(pnt,3);
            }
        else if (tp==_cell_type_full)
            {
            if (_sel) bmp->Canvas->Brush->Color=col_sel;
            else      bmp->Canvas->Brush->Color=col_xside;
            pnt[0].x=x+cxs2; pnt[0].y=y+cys2;
            pnt[1].x=x+cxs;  pnt[1].y=y;
            pnt[2].x=x+cxs;  pnt[2].y=y     -czs;
            pnt[3].x=x+cxs2; pnt[3].y=y+cys2-czs;
            bmp->Canvas->Polygon(pnt,3);

            if (_sel) bmp->Canvas->Brush->Color=col_sel;
            else bmp->Canvas->Brush->Color=col_yside;
            pnt[0].x=x;      pnt[0].y=y;
            pnt[1].x=x+cxs2; pnt[1].y=y+cys2;
            pnt[2].x=x+cxs2; pnt[2].y=y+cys2-czs;
            pnt[3].x=x;      pnt[3].y=y     -czs;
            bmp->Canvas->Polygon(pnt,3);

            if (_sel) bmp->Canvas->Brush->Color=col_sel;
            else bmp->Canvas->Brush->Color=col_zside;
            pnt[0].x=x;      pnt[0].y=y     -czs;
            pnt[1].x=x+cxs2; pnt[1].y=y+cys2-czs;
            pnt[2].x=x+cxs;  pnt[2].y=y     -czs;
            pnt[3].x=x+cxs2; pnt[3].y=y-cys2-czs;
            bmp->Canvas->Polygon(pnt,3);
            }
        }
    //---------------------------------------------------------------------------
    void isometric::map_random()
        {
        int i,x,y,z,x0,y0,r,h;
        // clear
        for (z=0;z<gzs;z++)
         for (y=0;y<gys;y++)
          for (x=0;x<gxs;x++)
           map[z][y][x]=_cell_type_empty;
        // add pseudo-random bumps
        Randomize();
        for (i=0;i<10;i++)
            {
            x0=Random(gxs);
            y0=Random(gys);
            r=Random((gxs+gys)>>3)+1;
            h=Random(gzs);
            for (z=0;(z<gzs)&&(r);z++,r--)
             for (y=y0-r;y<y0+r;y++)
              if ((y>=0)&&(y<gys))
               for (x=x0-r;x<x0+r;x++)
                if ((x>=0)&&(x<gxs))
                 map[z][y][x]=_cell_type_full;
            }
        }
    //---------------------------------------------------------------------------
    #endif
    //---------------------------------------------------------------------------

布局仅定义坐标系轴方向(对于您的使用#define isometric_layout_2).这使用Borlands VCL Graphics :: TBitmap,所以如果你不使用Borland,将它改为任何GDI位图或将gfx部分覆盖到你的gfx API(它只与draw()和resize()相关).此外,TShiftState是VCL的一部分,它只是鼠标按钮和特殊键的状态,如shift,alt,ctrl,所以你可以使用bool或其他任何东西(目前没有使用,因为我还没有任何点击功能).

这里我的Borland窗口代码(单个表单app上有一个计时器),所以你看看如何使用它:

//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "win_main.h"
#include "isometric.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TMain *Main;
isometric iso;
//---------------------------------------------------------------------------
void TMain::draw()
    {
    iso.draw();
    Canvas->Draw(0,0,iso.bmp);
    }
//---------------------------------------------------------------------------
__fastcall TMain::TMain(TComponent* Owner) : TForm(Owner)
    {
    Cursor=crNone;
    iso.map_random();
    }
//---------------------------------------------------------------------------
void __fastcall TMain::FormResize(TObject *Sender)
    {
    iso.resize(ClientWidth,ClientHeight);
    draw();
    }
//---------------------------------------------------------------------------
void __fastcall TMain::FormPaint(TObject *Sender)
    {
    draw();
    }
//---------------------------------------------------------------------------
void __fastcall TMain::tim_redrawTimer(TObject *Sender)
    {
    draw();
    }
//---------------------------------------------------------------------------
void __fastcall TMain::FormMouseMove(TObject *Sender, TShiftState Shift, int X,int Y)                        { iso.mouse(X,Y,Shift); draw(); }
void __fastcall TMain::FormMouseDown(TObject *Sender, TMouseButton Button,TShiftState Shift, int X, int Y)   { iso.mouse(X,Y,Shift); draw(); }
void __fastcall TMain::FormMouseUp(TObject *Sender, TMouseButton Button,TShiftState Shift, int X, int Y)     { iso.mouse(X,Y,Shift); draw(); }
//---------------------------------------------------------------------------
void __fastcall TMain::FormDblClick(TObject *Sender)
    {
    iso.map_random();
    }
//---------------------------------------------------------------------------

[Edit1]图形方法

看看Simple OpenGL GUI Framework User Interaction Advice?.

主要思想是创建阴影屏幕缓冲区,其中存储了渲染单元格的id.这提供了O(1)中的像素完美的子画面/单元选择,只需几行代码.

>创建阴影屏幕缓冲区idx [ys] [xs]

它应该与地图视图具有相同的分辨率并且应该能够将渲染单元格的(x,y,z)值存储在单个像素内(在地图网格单元格中).我使用32位像素格式,所以我选择12位用于x,y和8位用于z

DWORD color = (x) | (y<<12) | (z<<24)

>在渲染地图之前清除此缓冲区

我使用0xFFFFFFFF作为空颜色,因此它不会与单元格(0,0,0)发生冲突.
>在地图上细胞精灵渲染

每当您将像素渲染到屏幕缓冲区pyx [y] [x] =颜色时,您还将像素渲染到阴影屏幕缓冲区idx [y] [x] = c,其中c是以地图网格单位编码的单元格位置(请参阅#1).
>点击鼠标(或其他)

你有鼠标mx的屏幕位置,所以如果它在范围内,只需读取阴影缓冲区并获得所选的单元格位置.

c=idx[my][mx]
if (c!=0xFFFFFFFF)
 {
 x= c     &0x00000FFF;
 y=(c>>12)&0x00000FFF;
 z=(c>>24)&0x000000FF;
 }
else 
 {
 // here use the grid floor cell position formula from above approach if needed
 // or have empty cell rendered for z=0 with some special sprite to avoid this case.
 }

使用上面的编码这个地图(屏幕):

screen

也被渲染到阴影屏幕,如下所示:

shadow

选择像素完美无关紧要,如果你点击顶部,侧面……

使用的瓷砖是:

Title: Isometric 64x64 Outside Tileset
Author: Yar
URL: http://opengameart.org/content/isometric-64x64-outside-tileset
License(s): * CC-BY 3.0 http://creativecommons.org/licenses/by/3.0/legalcode

在这里Win32演示:

> demo

标签:javascript,algorithm,click,collision-detection,isometric
来源: https://codeday.me/bug/20190916/1806493.html