山寨騰訊「愛消除」遊戲之屏幕拾取技術

在山寨騰訊「愛消除」遊戲項目中,咱們使用了兩種簡單的屏幕拾取技術,這在第五天的教程及山寨騰訊「愛消除」遊戲之菜單特效裏已經有介紹。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.

https://github.com/3125788/CrazyCube3D

相關文章
相關標籤/搜索