在山寨騰訊「愛消除」遊戲項目中,咱們使用了兩種簡單的屏幕拾取技術,這在第五天的教程及山寨騰訊「愛消除」遊戲之菜單特效裏已經有介紹。java
很顯然,對於一些有複雜不規則圖案,或有層次感的場面,上面的技術並不能知足要求。今天咱們將介紹另一種屏幕拾取的方法。git
以下圖所示,這個是《教你玩魔方》遊戲裏的一個場景。github
顯然,因爲如下的緣由,用前面介紹的兩種技術將很難完成準確的屏幕拾取。函數
一、中間的魔方體是能夠隨意縮放的;.net
二、魔方的每個面都是能夠轉動的;code
三、每一個面在轉動過程當中,位置都是隨時變化的;orm
四、轉動結束後,面上每個方塊都會發生變化;對象
五、每一個方塊都有6個面,有些面是可見的,有些面是不可見的,觸摸到不一樣的面,產生的動做效果應該是不同的。blog
好,下面詳細地看一下DisplaySingleCube函數,該函數分別將方塊的6個面渲染出來。教程
一、DisplaySingleCube用於顯示一個小方塊,一個完整的魔方須要調用27次這個函數,最後一個參數cubeIndex指定了方塊的索引(0~26)
二、DisplaySingleCube函數中的渲染操做分爲DRAW和SELECT_PLATE兩種模式,在屏幕拾取時,要將模式設置爲SELECT_PLATE
三、DRAW模式下,使用紋理渲染;SELECT_PLATE模式下,使用色彩渲染,每一個面分別渲染出不一樣的顏色,詳細看下面代碼的註釋;根據選定的顏色,就能夠知道觸摸到的是哪個面了。
//顯示單個方塊 private void DisplaySingleCube(ST_DreamCube dreamcube, float fX, float fY,float fZ,float fRX,float fRY,float fRZ, int cubeIndex) { E_WORKMODE eMode = GetGLMode(); E_COLOR cU, cD, cF, cB, cL, cR; cU = dreamcube.cube_status[cubeIndex].Color.U; cD = dreamcube.cube_status[cubeIndex].Color.D; cF = dreamcube.cube_status[cubeIndex].Color.F; cB = dreamcube.cube_status[cubeIndex].Color.B; cL = dreamcube.cube_status[cubeIndex].Color.L; cR = dreamcube.cube_status[cubeIndex].Color.R; BindVertexAndTexture(cubeBuff, cubetexBuff); mGl.glLoadIdentity(); //可不要 GLU.gluLookAt(mGl, -5.0f, 5.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); mGl.glScalef(mCfg.cubeConfig.fZoomFactor, mCfg.cubeConfig.fZoomFactor, mCfg.cubeConfig.fZoomFactor); mGl.glTranslatef((float)0.3, (float)0.3-1, (float)-0.3); mGl.glFrontFace(GL10.GL_CCW); if (mCube.fYDegree != 0) { mGl.glRotatef(mCube.fYDegree, 0.0f, 1.0f, 0.0f); } if (fRX != 0 || fRY != 0 || fRZ != 0) { mGl.glRotatef(fRotate, fRX, fRY, fRZ); } mGl.glTranslatef(fX, fY, fZ); // FRONT AND BACK if (eMode == E_WORKMODE.DRAW) { mGl.glBindTexture(GL10.GL_TEXTURE_2D, texture[cF.ordinal()]); } else if (eMode == E_WORKMODE.SELECT_PLATE) { mGl.glColor4f(0, 0, 1, 1); //RGB(0,0,1) 藍 } mGl.glNormal3f(0.0f, 0.0f, 1.0f); mGl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); if (eMode == E_WORKMODE.DRAW) { mGl.glBindTexture(GL10.GL_TEXTURE_2D, texture[cB.ordinal()]); } else if (eMode == E_WORKMODE.SELECT_PLATE) { mGl.glColor4f(0, 1, 0, 1); //RGB(0,1,0) 綠 } mGl.glNormal3f(0.0f, 0.0f, -1.0f); mGl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4); // LEFT AND RIGHT if (eMode == E_WORKMODE.DRAW) { mGl.glBindTexture(GL10.GL_TEXTURE_2D, texture[cL.ordinal()]); } else if (eMode == E_WORKMODE.SELECT_PLATE) { mGl.glColor4f(0, 1, 1, 1); //RGB(0,0,1) 藍+綠 } mGl.glNormal3f(-1.0f, 0.0f, 0.0f); mGl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4); if (eMode == E_WORKMODE.DRAW) { mGl.glBindTexture(GL10.GL_TEXTURE_2D, texture[cR.ordinal()]); } else if (eMode == E_WORKMODE.SELECT_PLATE) { mGl.glColor4f(1, 0, 0, 1); //RGB(0,0,1) 紅 } mGl.glNormal3f(1.0f, 0.0f, 0.0f); mGl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4); // TOP AND BOTTOM if (eMode == E_WORKMODE.DRAW) { mGl.glBindTexture(GL10.GL_TEXTURE_2D, texture[cU.ordinal()]); } else if (eMode == E_WORKMODE.SELECT_PLATE) { mGl.glColor4f(1, 0, 1, 1); //RGB(0,0,1) 紅+藍 } mGl.glNormal3f(0.0f, 1.0f, 0.0f); mGl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4); if (eMode == E_WORKMODE.DRAW) { mGl.glBindTexture(GL10.GL_TEXTURE_2D, texture[cD.ordinal()]); } else if (eMode == E_WORKMODE.SELECT_PLATE) { mGl.glColor4f(1, 1, 0, 1); //RGB(0,0,1) 紅+綠 } mGl.glNormal3f(0.0f, -1.0f, 0.0f); mGl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4); }
接下來介紹選擇物體的函數SelectObj,參數是手指觸碰到屏幕的座標值。
一、在進入SelectObj函數以前,須要將模式設置爲PICK,這樣DisplaySingleCube函數內部的DRAW及SELECT_PLATE將不起做用;
二、在繪製每個小方塊以前,調用glColor4f給這個方塊設置顏色,每一個方塊都會設置成不一樣的顏色,詳細看代碼註釋;
三、咱們用(0,0,1)~(1,1,1)來表示不一樣的顏色,最多隻能7種顏色,那麼如何用7種顏色來識別27個方塊呢?咱們採用分組的方法來作到這一點的,詳細見代碼;
//對象選擇操做 E_SELECTION SelectObj(int x, int y) { E_SELECTION eObj = E_SELECTION.SELE_INVALID; int iObj = 0; InitViewPortMain(); mGl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); { mCube.XChgDreamCube4Display(mCube.DREAM_CUBE_CACULATE); mGl.glColor4f(0, 0, 1, 1); // RGB(0,0,1) 藍色 DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 24); mGl.glColor4f(0, 1, 0, 1); // RGB(0,1,0) 綠色 DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 25); mGl.glColor4f(0, 1, 1, 1); // RGB(0,1,1) 綠色+藍色 DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 26); mGl.glColor4f(1, 0, 0, 1); // RGB(1,0,0) 紅色 DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 15); mGl.glColor4f(1, 0, 1, 1); // RGB(1,0,1) 紅色+藍色 DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 16); mGl.glColor4f(1, 1, 0, 1); // RGB(1,1,0) 紅色+綠色 DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 17); iObj = GetObj(x, y); //分組1 if(iObj != 0) { switch(iObj) { case 1: eObj = E_SELECTION.SELE_BLK24; break; case 2: eObj = E_SELECTION.SELE_BLK25; break; case 3: eObj = E_SELECTION.SELE_BLK26; break; case 4: eObj = E_SELECTION.SELE_BLK15; break; case 5: eObj = E_SELECTION.SELE_BLK16; break; case 6: eObj = E_SELECTION.SELE_BLK17; break; // default: // eObj = -1; // break; } return eObj; } mGl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); mGl.glColor4f(0, 0, 1, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 6); mGl.glColor4f(0, 1, 0, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 7); mGl.glColor4f(0, 1, 1, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 8); mGl.glColor4f(1, 0, 0, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 23); mGl.glColor4f(1, 0, 1, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 14); mGl.glColor4f(1, 1, 0, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5); iObj = GetObj(x, y); //分組2 if(iObj != 0) { switch(iObj) { case 1: eObj = E_SELECTION.SELE_BLK6; break; case 2: eObj = E_SELECTION.SELE_BLK7; break; case 3: eObj = E_SELECTION.SELE_BLK8; break; case 4: eObj = E_SELECTION.SELE_BLK23; break; case 5: eObj = E_SELECTION.SELE_BLK14; break; case 6: eObj = E_SELECTION.SELE_BLK5; break; // default: // eObj = -1; // break; } return eObj; } mGl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); mGl.glColor4f(0, 0, 1, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 2); mGl.glColor4f(0, 1, 0, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 11); mGl.glColor4f(0, 1, 1, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 18); mGl.glColor4f(1, 0, 0, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 19); mGl.glColor4f(1, 0, 1, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 20); mGl.glColor4f(1, 1, 0, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 21); mGl.glColor4f(1, 1, 1, 1); DisplaySingleCube(mCube.DREAM_CUBE_DISPLAY, 0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 22); iObj = GetObj(x, y); //分組3 if(iObj != 0) { switch(iObj) { case 1: eObj = E_SELECTION.SELE_BLK2; break; case 2: eObj = E_SELECTION.SELE_BLK11; break; case 3: eObj = E_SELECTION.SELE_BLK18; break; case 4: eObj = E_SELECTION.SELE_BLK19; break; case 5: eObj = E_SELECTION.SELE_BLK20; break; case 6: eObj = E_SELECTION.SELE_BLK21; break; case 7: eObj = E_SELECTION.SELE_BLK22; break; // default: // eObj = -1; // break; } return eObj; } } mGl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); ShowUnseenPlate(mCube.DREAM_CUBE_CACULATE); iObj = GetObj(x, y); if(iObj != 0) { switch(iObj) { case 1: eObj = E_SELECTION.SELE_LEFT; break; case 2: eObj = E_SELECTION.SELE_RIGHT; break; case 3: eObj = E_SELECTION.SELE_DOWN; break; // default: // eObj = E_Selection.SELE_INVALID; // break; } return eObj; } mGl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); ShowLButton(); iObj = GetObj(x, y); if(iObj != 0) { switch(iObj) { case 1: eObj = E_SELECTION.SELE_MENU; break; case 2: eObj = E_SELECTION.SELE_HELP; break; case 3: eObj = E_SELECTION.SELE_ZOOMOUT; break; case 4: eObj = E_SELECTION.SELE_DISRUPT; break; case 5: eObj = E_SELECTION.SELE_AUTOPLAY; break; case 6: eObj = E_SELECTION.SELE_RESTART; break; case 7: eObj = E_SELECTION.SELE_STUDY; break; } return eObj; } mGl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); ShowRButton(); iObj = GetObj(x, y); if(iObj != 0) { switch(iObj) { case 1: eObj = E_SELECTION.SELE_ZOOMIN; break; case 2: eObj = E_SELECTION.SELE_SETUP; break; } return eObj; } mGl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); ShowProgressStars(); iObj = GetObj(x, y); if(iObj != 0) { switch(iObj) { case 1: eObj = E_SELECTION.SELE_STAR; break; } return eObj; } mGl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); ShowCubeTip(); iObj = GetObj(x, y); if(iObj != 0) { switch(iObj) { case 1: eObj = E_SELECTION.TIP_0; break; case 2: eObj = E_SELECTION.TIP_1; break; case 3: eObj = E_SELECTION.TIP_2; break; case 4: eObj = E_SELECTION.TIP_3; break; case 5: eObj = E_SELECTION.TIP_4; break; case 6: eObj = E_SELECTION.TIP_5; break; case 7: eObj = E_SELECTION.TIP_6; break; } return eObj; } mGl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); ShowTime(miCubeClockSec); iObj = GetObj(x, y); if(iObj != 0) { switch(iObj) { case 1: eObj = E_SELECTION.SELE_TIMER; break; } return eObj; } mGl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); ShowStep(mCube.GetStepBar()); iObj = GetObj(x, y); if(iObj != 0) { switch(iObj) { case 1: eObj = E_SELECTION.SELE_STEP; break; } return eObj; } return eObj; }
下面介紹獲取對象函數GetObj:
一、根據傳入的座標值,獲取指定座標出的色彩信息;
二、將色彩信息轉換爲RGB格式,而後返回該信息。
//獲取對象 private int GetObj(int x, int y) { mGl.glFinish(); mGl.glFinish(); Delay(miSelectDelay); ByteBuffer pixel = ByteBuffer.allocate(4); byte data[] = new byte[4]; mGl.glReadPixels(x , iScreenHeight - y, 1, 1, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixel); data = pixel.array(); data[0] = (byte) Math.abs(data[0]); data[1] = (byte) Math.abs(data[1]); data[2] = (byte) Math.abs(data[2]); data[0] = (byte) (data[0] << 2); data[1] = (byte) (data[1] << 1); int iObj = data[0] + data[1] + data[2]; return iObj; }
調用GetObj獲得RGB格式的顏色信息,根據該信息,咱們能夠肯定手指觸摸到的是哪一個方塊了:
iObj = GetObj(x, y); if(iObj != 0) { switch(iObj) { case 1: eObj = E_SELECTION.SELE_BLK24; break; case 2: eObj = E_SELECTION.SELE_BLK25; break; case 3: eObj = E_SELECTION.SELE_BLK26; break; case 4: eObj = E_SELECTION.SELE_BLK15; break; case 5: eObj = E_SELECTION.SELE_BLK16; break; case 6: eObj = E_SELECTION.SELE_BLK17; break; // default: // eObj = -1; // break; } return eObj; }
當觸摸事件發生時,咱們作了如下事情:
一、將模式設置爲PICK
二、用不一樣顏色來渲染魔方體的各個方塊,並拾取到手指觸摸處的方塊對象
三、將模式設置爲DRAW模式
四、按正常的紋理渲染模式,將魔方體完整地渲染出來
case TOUCH: mCubeGL.SetGLMode(E_WORKMODE.PICK); GetTouchObj(); mCubeGL.SetGLMode(E_WORKMODE.DRAW); mCubeGL.DisplayCube(); break;
採用這種方法,只有模式爲DRAW的圖案會最終顯示出來,PICK或SELECT_PLATE模式下的圖案是不會顯示的,所以,你不須要擔憂PICK模式下會破壞總體的渲染效果。
好了,完整的代碼請參考個人另外一個開源項目《教你玩魔方》
項目地址在GITHUB,歡迎你FORK.