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

时间:2016-03-09 07:01:24

标签: javascript algorithm click collision-detection isometric

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

我当前算法的解释:

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

Sizing of tile

地图由三维数组map[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&gt;来裁剪红色区域。瓷砖宽度的一半

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)是否位于依赖于tileX,tileY近似(约为正方形网格)的y=mx+b行之下。

如果你到了这里,谢谢!

1 个答案:

答案 0 :(得分:4)

这个答案基于:

所以这就是:

  1. 网格和屏幕之间的转换

    正如我在评论中提到的,你应该创建在屏幕和单元格位置之间转换的函数。类似的东西(在 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

    • 红叉表示cell2scr(x,y,0,0,0)
    • 返回的坐标
    • 绿色十字表示鼠标坐标
    • 浅绿色突出显示表示返回的单元格位置

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

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

    scr2cellcell2scr方程式中的代数求解屏幕位置完成,同时假设为z=0,因此仅选择网格地面。最重要的是,如果鼠标位置在找到的单元格区域之外,则添加偶数/奇数校正。

  2. 扫描邻居

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

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

    我这样做:

    scan pattern

    行数取决于单元格z轴大小(czs),最大z层数(gzs)和单元格大小({{1 }})。我的扫描的 C ++ 代码如下所示:

    cys

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

    scan result

  3. 这里完整的 VCL / 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
        }
    

    布局仅定义坐标系轴线方向(供您使用 //--------------------------------------------------------------------------- //--- 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 //--------------------------------------------------------------------------- )。这使用 Borlands VCL #define isometric_layout_2,因此如果您不使用 Borland ,请将其更改为任何 GDI 位图,或将gfx部分覆盖到您的& #39; s gfx API (仅适用于Graphics::TBitmapdraw())。另外resize() VCL 的一部分,它只是鼠标按钮的状态和TShiftState之类的特殊键,因此您可以使用shift,alt,ctrl或其他任何代替(目前未使用)因为我还没有任何点击功能。)

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

    bool

    [Edit1]图片方法

    查看Simple OpenGL GUI Framework User Interaction Advice?

    主要思想是创建阴影屏幕缓冲区,其中存储了渲染单元格的id。这提供了//$$---- 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(); } //--------------------------------------------------------------------------- 中像素完美的精灵/单元格选择,只需几行代码。

    1. 创建影子屏幕缓冲区O(1)

      它应该具有与地图视图相同的分辨率并且应该能够在单个像素内(在地图网格单元格单元中)存储渲染单元格的idx[ys][xs]值。我使用32位像素格式,因此我为(x,y,z)选择12位,为x,y选择8

      z
    2. 在渲染地图之前清除此缓冲区

      我使用DWORD color = (x) | (y<<12) | (z<<24) 作为空白颜色,因此它不会与单元格0xFFFFFFFF发生碰撞。

    3. 地图单元格精灵渲染
    4. 每当您将像素渲染到屏幕缓冲区(0,0,0)时,您也会将像素渲染到阴影屏幕缓冲区pyx[y][x]=color,其中idx[y][x]=c是以地图网格单位编码的单元格位置(请参阅#1 < /强>)。

    5. 点击鼠标(或其他)

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

      mx,my

      通过以上编码此地图(屏幕):

      screen

      也会像这样渲染到阴影屏幕:

      shadow

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

      使用的瓷砖是:

      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.
       }
      

      这里是Win32演示: