【Android游戏开发之四】Android 游戏框架(一个游戏角色在屏幕行走的demo)
各位童鞋请你们注意:surfaceview中确实有 onDraw这个方法,但是surfaceview不会自己去调用!!! 而我代码中的ondraw 也好 draw 也好,都是我自己定义的一个方法。。。放在线程中不断调用的,一定要注意!! 其实上一篇分析surfaceview的文章就是一个简单的游戏框架了,当然这里再强调一下,简单的游戏框架,所以不要高手们不要乱喷~ 这个Demo是给群里一童鞋写的一个对图片操作以及按键处理,游戏简单框架的一个demo,这里放出给大家分享~ packagecom.himi; importandroid.content.Context; importandroid.content.res.Resources; importandroid.graphics.Bitmap; importandroid.graphics.BitmapFactory; importandroid.graphics.Canvas; importandroid.graphics.Color; importandroid.graphics.Paint; importandroid.util.Log; importandroid.view.KeyEvent; importandroid.view.SurfaceHolder; importandroid.view.SurfaceView; importandroid.view.SurfaceHolder.Callback; publicclassMySurfaceViewextendsSurfaceViewimplementsCallback,Runnable{ privateThreadth=newThread(this); privateSurfaceHoldersfh; privateintSH,SW; privateCanvascanvas; privatePaintp; privatePaintp2; privateResourcesres; privateBitmapbmp; privateintbmp_x=100,bmp_y=100; privatebooleanUP,DOWN,LEFT,RIGHT; privateintanimation_up[]={3,4,5}; privateintanimation_down[]={0,1,2}; privateintanimation_left[]={6,7,8}; privateintanimation_right[]={9,10,11}; privateintanimation_init[]=animation_down; privateintframe_count; publicMySurfaceView(Contextcontext){ super(context); this.setKeepScreenOn(true); res=this.getResources(); bmp=BitmapFactory.decodeResource(res,R.drawable.enemy1); sfh=this.getHolder(); sfh.addCallback(this); p=newPaint(); p.setColor(Color.YELLOW); p2=newPaint(); p2.setColor(Color.RED); p.setAntiAlias(true); setFocusable(true);//备注1 } publicvoidsurfaceCreated(SurfaceHolderholder){ SH=this.getHeight(); SW=this.getWidth(); th.start(); } publicvoiddraw(){ canvas=sfh.lockCanvas(); canvas.drawRect(0,0,SW,SH,p);//备注2 canvas.save();//备注3 canvas.drawText("Himi",bmp_x-2,bmp_y-10,p2); canvas.clipRect(bmp_x,bmp_y,bmp_x+bmp.getWidth()/13,bmp_y+bmp.getHeight()); if(animation_init==animation_up){ canvas.drawBitmap(bmp,bmp_x-animation_up[frame_count]*(bmp.getWidth()/13),bmp_y,p); }elseif(animation_init==animation_down){ canvas.drawBitmap(bmp,bmp_x-animation_down[frame_count]*(bmp.getWidth()/13),bmp_y,p); }elseif(animation_init==animation_left){ canvas.drawBitmap(bmp,bmp_x-animation_left[frame_count]*(bmp.getWidth()/13),bmp_y,p); }elseif(animation_init==animation_right){ canvas.drawBitmap(bmp,bmp_x-animation_right[frame_count]*(bmp.getWidth()/13),bmp_y,p); } canvas.restore();//备注3 sfh.unlockCanvasAndPost(canvas); } publicvoidcycle(){ if(DOWN){ bmp_y+=5; }elseif(UP){ bmp_y-=5; }elseif(LEFT){ bmp_x-=5; }elseif(RIGHT){ bmp_x+=5; } if(DOWN||UP||LEFT||RIGHT){ if(frame_count<2){ frame_count++; }else{ frame_count=0; } } if(DOWN==false&&UP==false&&LEFT==false&&RIGHT==false){ frame_count=0; } } @Override publicbooleanonKeyDown(intkey,KeyEventevent){ if(key==KeyEvent.KEYCODE_DPAD_UP){ if(UP==false){ animation_init=animation_up; } UP=true; }elseif(key==KeyEvent.KEYCODE_DPAD_DOWN){ if(DOWN==false){ animation_init=animation_down; } DOWN=true; }elseif(key==KeyEvent.KEYCODE_DPAD_LEFT){ if(LEFT==false){ animation_init=animation_left; } LEFT=true; }elseif(key==KeyEvent.KEYCODE_DPAD_RIGHT){ if(RIGHT==false){ animation_init=animation_right; } RIGHT=true; } returnsuper.onKeyDown(key,event); } /*(non-Javadoc) *@seeandroid.view.View#onKeyUp(int,android.view.KeyEvent) */ @Override publicbooleanonKeyUp(intkeyCode,KeyEventevent){ if(DOWN){ DOWN=false; }elseif(UP){ UP=false; }elseif(LEFT){ LEFT=false; }elseif(RIGHT){ RIGHT=false; } returnsuper.onKeyUp(keyCode,event); } @Override publicvoidrun(){ //TODOAuto-generatedmethodstub while(true){ draw(); cycle(); try{ Thread.sleep(100); }catch(Exceptionex){ } } } @Override publicvoidsurfaceChanged(SurfaceHolderholder,intformat,intwidth,intheight){ //TODOAuto-generatedmethodstub } @Override publicvoidsurfaceDestroyed(SurfaceHolderholder){ //TODOAuto-generatedmethodstub } } 备注1 此方法是用来响应按键!如果是自己定义一个继承自View的类,重新实现onKeyDown方法后,只有当该View获得焦点时才会调用onKeyDown方法,Actvity中的onKeyDown方法是当所有控件均没有处理该按键事件时,才会调用. 备注2 这里也是对屏幕进行刷屏操作,其实这也只是一种,之前文章里我也用到drawRGB的方法同样实现,当然也可以用fillRect等来刷屏。 那么这里我想说下,在继承view中,因为onDraw方法是系统自动调用的,不像在surfaceview这里这样去在run里面自己去不断调用,在view中我们可以抵用 invalidate()/postInvalidate() 这两种方法实现让系统调用onDraw方法,这里也是和surfaceview中的不同之一! 备注3 这里canvas.save();和canvas.restore();是两个相互匹配出现的,作用是用来保存画布的状态和取出保存的状态的。这里稍微解释一下,当我们对画布进行旋转,缩放,平移等操作的时候其实我们是想对特定的元素进行操作,比如图片,一个矩形等,但是当你用canvas的方法来进行这些操作的时候,其实是对整个画布进行了操作,那么之后在画布上的元素都会受到影响,所以我们在操作之前调用canvas.save()来保存画布当前的状态,当操作之后取出之前保存过的状态,这样就不会对其他的元素进行影响。 对于 canvas.save();和canvas.restore(); 还有不少童鞋不懂,OK、我再补充点: 代码段1: publicvoiddraw(){ Canvascanvas=sfh.lockCanvas(); canvas.drawColor(Color.BLACK); canvas.drawBitmap(bmp1,0,0,paint); canvas.save(); canvas.scale(1.5f,1.5f); canvas.restore(); canvas.drawBitmap(bmp2,0,0,paint); sfh.unlockCanvasAndPost(canvas); } 代码段2: publicvoiddraw(){ Canvascanvas=sfh.lockCanvas(); canvas.drawColor(Color.BLACK); canvas.drawBitmap(bmp1,0,0,paint); canvas.scale(1.5f,1.5f); canvas.drawBitmap(bmp2,0,0,paint); sfh.unlockCanvasAndPost(canvas); } 上面这两个代码片段中我们都假设有两张图片 bmp1和bmp2,并且都画在画布上! 那么代码段1和代码段2的不同: 代码段1中我们进行画布缩放的之前保存了画布状态,做了缩放操作之后又取出之前保存的状态,这样做是为了保证bmp2正常画出来不受到缩放的影响! 代码段2里,画了bmp1后就执行了缩放操作,并且没有保存状态!紧接着画了bmp2,那么bmp2也会一样受到缩放的影响!! 所以我们如果单独处理一张图片的时候,而且不想影响其他部分的绘制,那么应该如下来做: publicvoiddraw(){ Canvascanvas=sfh.lockCanvas(); canvas.drawColor(Color.BLACK); canvas.drawBitmap(bmp1,0,0,paint); canvas.save(); canvas.scale(1.5f,1.5f); canvas.drawBitmap(bmp2,0,0,paint); canvas.restore(); sfh.unlockCanvasAndPost(canvas); } 本文转自 xiaominghimi 51CTO博客,原文链接:http://blog.51cto.com/xiaominghimi/605690,如需转载请自行联系原作者