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

我正在研究一个等距游戏引擎,并且已经创build了一个像素完美点击检测algorithm。 访问该项目,并注意点击检测能够检测到磁贴的哪个边缘被点击。 它也检查y指数点击最​​前面的瓷砖。

我目前的algorithm解释:

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

瓷砖的大小

地图由三维数组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); 

等距网格

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

 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。 检查红色区域是否大于瓷砖宽度的一半

图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)); }; 

如果鼠标在上面,则返回true


 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数组,然后select具有最高y的图块。 这是最先进的瓷砖。

     if(allContainsMouse && !topContainsMouse) 

底部比赛

  •  if(allContainsMouse && !topContainsMouse && leftContainsMouse) 

左边比赛

(类似的概念适用于右)

最后,我的问题是:

#1你会怎么做到这一点,使它更有效率(不通过所有瓷砖循环)(pududo代码接受)

#2如果您无法回答#1,您有什么build议可以提高点击检测的效率(块加载已被考虑)

我想到的是:

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

检查鼠标是否在瓦片内,使用这种方法是困难的,我无法弄清楚。 我正在检查鼠标(x,y)是否位于取决于tileX,tileY近似(方形网格大约)的y=mx+b行之下。

如果你到了这里,谢谢!

这个答案是基于:

  • 二维网格图像值到二维数组

所以在这里:

  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++; } } } //--------------------------------------------------------------------------- 

    我用你的布局(花了很多时间来转换我的希望,我没有犯一些愚蠢的错误的地方):

    布局

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

    要小心,如果你正在使用整数算术,你需要记住,如果你除以一半的大小,你可以失去精度。 对于这样的情况,使用全尺寸和2分的结果(花费大量的时间来计算过去的一个)。

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

    scr2cell是通过从cell2scr方程中代数地求解屏幕位置来完成的,同时假定z=0所以只select网格地。 最重要的是,如果鼠标位置在find的单元格区域之外,则添加偶数/奇数校正。

  2. 扫描邻居

    scr2cell(x,y,z,mouse_x,mouse_y)只返回鼠标在地面上的单元格。 所以如果你想添加你当前的selectfunction,你需要扫描该位置上的顶部单元格和几个相邻的单元格,并select距离最短的单元格。

    没有必要扫描整个网格/地图返回位置周围的几个单元格。 这应该大大加快事情。

    我这样做:

    扫描模式

    行数取决于单元z轴大小( gzs ), 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 } 

    这总是select顶部单元格(从所有可能的最高),当用鼠标玩它感觉正确(至less对我来说):

    扫描结果

在这里,今天完成了这个为我的等距引擎完整的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: %ix %i",mx,my)); bmp->Canvas->TextOutA(5,20,AnsiString().sprintf("Select: %ix %ix %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方向(对于您的使用#define isometric_layout_2 )。 这个使用了Borland VCL Graphics::TBitmap所以如果你不使用Borland把它改成任何GDI位图,或者把gfx部分覆盖到你的gfx API (这只与draw()resize() )。 此外, TShiftStateVCL的一部分,它只是鼠标button的状态和像shift,alt,ctrl这样的特殊键shift,alt,ctrl所以你可以使用bool或其他任何东西(目前没有使用,因为我没有任何点击function)。

在这里,我的Borland窗口代码(带有一个计时器的单一窗体应用程序),所以你看看如何使用这个:

 //$$---- 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(); } //--------------------------------------------------------------------------- 

graphics方式[Edit1]

看看简单的OpenGL GUI框架用户交互的build议? 。

主要想法是创build阴影屏幕缓冲区,其中呈现的单元格的ID被存储。 这只需要几行代码即可在O(1)提供像素完美的精灵/单元格select。

  1. 创build阴影屏幕缓冲区idx[ys][xs]

    它应该与地图视图具有相同的分辨率并且应该能够将渲染单元的(x,y,z)值存储在单个像素内(以地图网格单元格为单位)。 我使用32位像素格式,因此我select12x,y8z

     DWORD color = (x) | (y<<12) | (z<<24) 
  2. 在渲染map之前清除这个缓冲区

    我使用0xFFFFFFFF作为空的颜色,所以它不与单元格(0,0,0)冲突。

  3. 在地图单元格精灵呈现

    每当你渲染像素到屏幕缓冲区pyx[y][x]=color你也渲染像素到阴影屏幕缓冲区idx[y][x]=c其中c是地图网格单元中的编码单元位置(见#1 )。

  4. 在鼠标点击(或其他)

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

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

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

    屏幕

    也被渲染成这样的阴影屏幕:

    阴影

    select是像素完美无关紧要,如果你点击顶部,侧… … –

    使用的瓷砖是:

     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演示:

    • 演示