• 山寨腾讯“爱消除”游戏之菜单特效


    前面的教程,我们一直关注游戏主要功能的设计,今天我们将介绍其他的辅助功能设计,比如游戏的主菜单设计。

    如下图示,游戏主界面中的“极限模式”,其实是由一个动画图片及一个静态文字图片构成的。不管触摸到的是动画图片,或是文字图片,最后都会进入游戏的“极限模式”。


    我们设计了DrawMenu来实现这个功能。除了要用到前面介绍的纹理渲染技术外,DrawMenu还绑定了TouchArea,这样当触摸事件发生时,会自动检测是否触摸到了DrawMenu所绘制的图片,如果是,这发出携带有对应触摸区域信息的触摸事件。在事件处理函数中,处理该事件让其执行特定的操作即可。

    1、DrawMenu类,给类与前面介绍的渲染类很类似,唯一不同的地方就是在创建对象时,会touchRegister函数向控制中心ControlCenter类注册TouchArea。当触摸事件发生时,会检查对应的TouchArea。

     

    public class DrawMenu {
    
    	float mCol = 0;
    	float mRow = 0;
    	int mWidth = 0;
    	int mHeight = 0;
    	float mPicNum = 4.0f;
    	E_TOUCHAREA mTouchArea = E_TOUCHAREA.NONE;
    	private IntBuffer   mVertexBuffer;		//顶点坐标数据缓冲
        private FloatBuffer   mTextureBuffer;	//顶点纹理数据缓冲
        int vCount=0;							//顶点数量     
        int textureId;							//纹理索引
        float textureRatio;						//为了准确获取纹理图片中的素材对象,需要设置纹理的变换率
        
        public IControl control;
        
        public DrawMenu(int textureId, float col, float row, int width, int height, int picNum, E_TOUCHAREA area)
        {
        	this.textureId = textureId;
        	mCol = col - 3;
        	mRow = row - 3;
        	mTouchArea = area;
        	
        	//要渲染的图片宽和高,是实际宽高像素的一半
        	mWidth = width/2;
        	mHeight = height/2;
        	mPicNum = picNum;
        	control = new CtlMenu();
        	CtlMenu ctl = (CtlMenu)control;
        	ctl.init(picNum);
        	touchRegister();
        }
        
        void touchRegister()
        {
            int w = mWidth;
            int h = mHeight;
            int deltaX = (int)(mCol*w);
            int deltaY = (int)(mRow*h);
    
            int x = -w+deltaX + CrazyZombyConstent.VIEW_WIDTH/2;
        	int y = (CrazyZombyConstent.REAL_HEIGHT - CrazyZombyConstent.VIEW_HEIGHT) / 2 + CrazyZombyConstent.VIEW_HEIGHT/2 - (h+deltaY);
        	
        	TouchArea touchArea = new TouchArea(x, y, w*2, h*2, mTouchArea);
        	ControlCenter.mTouchMsg.touchRegister(touchArea, control); 
        }
        
    	//顶点坐标数据的初始化
        private void initVertexBuffer()
        {
            vCount=6;//顶点的数量,一个正方形用两个三角形表示,共需要6个顶点   
            int w = mWidth*CrazyZombyConstent.ADP_SIZE;
            int h = mHeight*CrazyZombyConstent.ADP_SIZE;
            int deltaX = (int)(mCol*w);
            int deltaY = (int)(mRow*h);
            int vertices[]=new int[]//顶点坐标数据数组
            {
               	-w+deltaX,h+deltaY,0,
            	-w+deltaX,-h+deltaY,0,
            	w+deltaX,-h+deltaY,0,
            	w+deltaX,-h+deltaY,0,
            	w+deltaX,h+deltaY,0,
            	-w+deltaX,h+deltaY,0
            };
            //创建顶点坐标数据缓冲
            //int类型占用4个字节,因此转换为byte的数据时需要*4
            ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
            vbb.order(ByteOrder.nativeOrder());		//设置本地的字节顺序
            //特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer
            //转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题    	        
            mVertexBuffer = vbb.asIntBuffer();		//转换为int型缓冲
            mVertexBuffer.put(vertices);			//向缓冲区中放入顶点坐标数据
            mVertexBuffer.position(0);				//设置缓冲区起始位置
            return;
        }
        
        //顶点纹理数据的初始化    
        private void initTextureBuffer(int witch)
        {
            textureRatio = (float)(1/mPicNum);		//图片是4个独立的素材对象组成,每次需要根据witch准确地获取对应的素材
            float textureCoors[]=new float[]	//顶点纹理S、T坐标值数组
    	    {
            	(witch - 1) * textureRatio,0,
            	(witch - 1) * textureRatio,1,
            	witch * textureRatio,1,
            	witch * textureRatio,1,
            	witch * textureRatio,0,        	
            	(witch - 1) * textureRatio,0
    	    };        
            
            //创建顶点纹理数据缓冲
            //int类型占用4个字节,因此转换为byte的数据时需要*4
            ByteBuffer cbb = ByteBuffer.allocateDirect(textureCoors.length*4);
            cbb.order(ByteOrder.nativeOrder());//设置本地字节顺序
            //特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer
            //转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题
            mTextureBuffer = cbb.asFloatBuffer();//转换为int型缓冲
            mTextureBuffer.put(textureCoors);//向缓冲区中放入顶点着色数据
            mTextureBuffer.position(0);//设置缓冲区起始位置
        	return;
        }
    	
    
        public void draw(GL10 gl)
        {
        	if (!control.isRun()) return;
        	CtlMenu ctl = (CtlMenu)control;
        	initVertexBuffer();    	
        	initTextureBuffer(ctl.getPicId());	//初始化纹理顶点数据    	
            //顶点坐标,允许使用顶点数组
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    		//为画笔指定顶点坐标数据
            gl.glVertexPointer
            (
        		3,				//每个顶点的坐标数量为3  xyz 
        		GL10.GL_FIXED,	//顶点坐标值的类型为 GL_FIXED
        		0, 				//连续顶点坐标数据之间的间隔
        		mVertexBuffer	//顶点坐标数据
            );
            
            //纹理坐标,开启纹理
            gl.glEnable(GL10.GL_TEXTURE_2D);   
            //允许使用纹理数组
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
            //为画笔指定纹理uv坐标数据
            gl.glTexCoordPointer
            (
        		2, 					//每个顶点两个纹理坐标数据 S、T
        		GL10.GL_FLOAT, 		//数据类型
        		0, 					//连续纹理坐标数据之间的间隔
        		mTextureBuffer		//纹理坐标数据
            );        		
            gl.glBindTexture(GL10.GL_TEXTURE_2D,textureId);//为画笔绑定指定ID纹理   
            
            //绘制图形
            gl.glDrawArrays
            (
        		GL10.GL_TRIANGLES, 
        		0, 
        		vCount
            );
            gl.glDisable(GL10.GL_TEXTURE_2D);//关闭纹理
        }
    }
    
    


    2、TouchArea的检测。当触摸事件发生,会调用到raiseTouchEvent函数,根据输入的坐标值,按注册的顺序检测TouchArea,只要检测到其中一个满足条件,就发送一个带有区域信息的消息;如果没有符合条件的TouchArea,则发送E_TOUCHARE.NONE消息。

     

    //输入坐标是(x,y),检测是否落在某个TouchArea
    	void raiseTouchEvent(int x, int y)
    	{
    		TouchArea touchArea;
    		IControl control;
    		for(int i = 0; i < mTouchList.mTouchAreaList.size(); i++)
    		{
    			touchArea = mTouchList.mTouchAreaList.get(i);
    			control = mTouchList.mControl.get(i);
    			if(x >= touchArea.mStartX && x <= touchArea.mStartX + touchArea.mW)
    			{
    				if(y >= touchArea.mStartY && y <= touchArea.mStartY + touchArea.mH)
    				{
    					if(control.isRun())
    					{
    						//检测到一个有效的就立即退出
    						sendMsg(touchArea.mTouchArea);
    						return;
    					}
    				}
    			}
    		}
    		sendMsg(E_TOUCHAREA.NONE);
    		return;
    	}
    	


    3、TOUCHAREA消息的处理。在handleMessage中,会处理上面发出的消息。

     

    	//处理触摸事件
    	static void dealTouchMsg(int event)
    	{
    		event = event - TOUCH_EVENT_BASE;
    		if(event == E_TOUCHAREA.MENU_TIME_MODE.ordinal())
    		{
    			mMode = E_GAMEMODE.TIME;
    			mScore.init();
    			mLife.set(CrazyZombyConstent.LIFE_NUM);
    			mLife.reset();
    			mTimer.reset();
    			init();
    			Message msg = new Message();
    			msg.what = ControlCenter.LOADING_START;
    		    ControlCenter.mHandler.sendMessage(msg);
    		    stopMenuScene();
    		}
    		else if(event == E_TOUCHAREA.MENU_LIFE_MODE.ordinal())
    		{
    			mMode = E_GAMEMODE.LIFE;
    			mScore.init();
    			mLife.set(CrazyZombyConstent.LIFE_NUM);
    			mLife.reset();
    			mTimer.reset();
    			init();
    			Message msg = new Message();
    			msg.what = ControlCenter.LOADING_START;
    		    ControlCenter.mHandler.sendMessage(msg);
    		    stopMenuScene();
    		}
    		else if(event == E_TOUCHAREA.MENU_ABOUT.ordinal())
    		{}
    		else if(event == E_TOUCHAREA.MENU_EXIT.ordinal())
    		{}
    		else if(event == E_TOUCHAREA.RESULT_CONTINUE.ordinal())
    		{
    			ControlCenter.mScene = E_SCENARIO.MENU;
    			stopResultScene();
    			startMenuScene();
    		}
    		else if(event == E_TOUCHAREA.RESULT2.ordinal())
    		{}
    		
    	}
    


    这样,我们就完成了一个可以处理触摸事件的渲染类的设计。

    顺便提一下,DrawMenu渲染类不光可以渲染静态的效果,也可以渲染动态的效果。

        public DrawMenu(int textureId, float col, float row, int width, int height, int picNum, E_TOUCHAREA area)

    col,row:图片显示的位置

    要渲染的图片像素宽度

    height:要渲染的图片像素高度

    picNum:要渲染的素材由几张图片组成

    area:自动根据图片尺寸及显示位置计算出TouchArea

    通过设计合理的素材,并设定picNum,就可以实现静态或动态的渲染效果。

    如上面这一幅素材,通过下面的代码就可以渲染出动画效果:

    drawMenuTimeModePic = new DrawMenu(timeModePicTextureId, 1, 3, 128, 128, 4, E_TOUCHAREA.MENU_TIME_MODE);



    【后记】上述代码在我的另一个开源项目“消除僵尸”中可以免费下载:https://github.com/3125788/CrazyZomby





  • 相关阅读:
    poj 2251 Dungeon Master
    poj 2488 A Knight's Journey
    poj 3349
    poj 2442
    poj 3274 Gold Balanced Lineup
    优先队列
    广州华盟信息科技有限公司
    山东山大华天软件有限公司
    RvmTranslator6.5 is released
    PipeCAD之管道标准库PipeStd(2)
  • 原文地址:https://www.cnblogs.com/riasky/p/3483370.html
Copyright © 2020-2023  润新知