Android游戏开发.docx
《Android游戏开发.docx》由会员分享,可在线阅读,更多相关《Android游戏开发.docx(72页珍藏版)》请在冰点文库上搜索。
Android游戏开发
Android游戏开发
序言
前面我们已经学习了Android中的常用组件,控件和布局,利用前面的知识可以满足目前主流的应用程序开发主流,如果以后还有新的技术知识点开始流行,我将在第一时间给大家更新技术文档,接下来,我们将开始我们的Android游戏开发旅程,我们前面所学习UI设计仅仅只能满足我们的应用程序开发,如果开发游戏的话,这些组件和UI控件是远远不能够满足我们的要求的,游戏中的UI界面大部分都是美工资源构成的,因此,在设计游戏界面的时候,我们不能再指望LayOut能帮到我们,因为它只会影响我们的游戏速度和开发效率。
所以我们要学习新的知识才能做游戏,我相信大家都想做自己的游戏已经迫不及待了吧,但是做游戏之前,我需要给大家讲讲基本的情况,首先,做出一个游戏实际上比做出一个应用程序还要简单,但是如果要把一个游戏做好,却比应用程序更加困难,而且,在开发游戏的时候,需要学习很多大家曾经不知道的内容,甚至已经超越了我们的Android知识范围,所以我希望大家真正的能持之以恒,坚持到最后,写出自己心目中的游戏。
Android游戏开发简介
我相信大家已经都玩过电脑游戏或者家用机游戏(PS,XBOX360,WII),又或者是手机游戏,那么在这里我希望大家要知道,原来你只是一个游戏玩家,现在你是一个游戏开发人员,两者有相似之处,也有不相似之处,但是这两个身份却是相辅相成的,也就是说,没有真正的玩过游戏,那么你绝对不可能写出好的游戏,因为你没有那种玩家感受,只是一味的追求程序的设计,这样的游戏做出来肯定会被玩家抛弃的。
做游戏之前,我们需要知道,Android目前没有一个固定的标准,不管是硬件标准还是软件标准都是混乱的,不像iPhone统一了标准,让开发人员可以全身心投入在游戏开发中,而Android游戏开发人员还要经常为考虑适应不用的硬件标准而头疼,或许CPU,GPU,内存的问题我们还能够接受,但是屏幕的大小不一,对开发人员来说完全就是一种折磨,也就是说,如果我们的游戏是基于480*800的分辨率开发的,那么在320*480的屏幕上面会显示不完所有的内容,但是如果我们基于320*480开发,那么在大分辨率屏幕上会出现黑框甚至图像扭曲,当然这些问题,我们前期可以不用考虑,但是以后也是必须要面对的,我这里先给大家提个醒。
我首先给大家做一个简单介绍,目前的几种游戏类型,这里因为手机游戏开发很多时候还是会被硬件限制,所以我只给大家说明,手游中常出现的几种游戏类型,让大家以后才能明确知道自己在做什么类型的游戏,游戏类型主要分为:
ACT、FTG、STG、FPS、SLG、RTS、RTT、RPG、AVG、SIM、SPG、RAC、PUZ、MUG、ETC等其他类型。
我会在下面给大家介绍几种目前手游主流类型,大家下来可以在网上多查询了解。
ACT最经典的应该是红白机上的超级玛丽了,当然现在的经典就是波斯王子,刺客信条,战神等等。
所以ACT类型的游戏就是即时动作冒险游戏。
当然这里让我再多插一句,市面上其实很多游戏已经把类型综合的无法却分,比如曾经的辉煌经典魂斗罗,很多人还在为它是ACT还是STG而争论不休,所以我在这里只能给大家抛砖引玉,希望大家见谅。
FTG是指格斗类游戏,例如经典的街头霸王,拳皇,侍魂。
STG是指横版飞行射击类游戏,例如:
沙罗曼蛇,雷电,彩京,1945。
FPS是指第一人称射击,这个我相信很多人都知道了,最经典的莫过于反恐精英,也就是我们常说的CS。
SLG,策略战棋,这个类型的游戏是目前手游里面最火爆的一种游戏类型,也是相对来说,容易开发和设计的一种类型,最经典的游戏,我一提大家都知道,那就是英雄无敌,三国志,信长之野望,三国群英传。
RTS,即时战略,此类型的经典游戏很多很多,比如红色警戒,星际争霸,魔兽争霸等等。
RPG,角色扮演,此类型因为太火爆,所以通常还需要分离出来几种类型,ARPG动作角色扮演,SRPG策略角色扮演,MMORPG网络角色扮演。
此类型游戏不用介绍,还有人不知道的自己面壁。
AVG,剧情揭秘类型,经典游戏:
生化危机,古墓丽影,神秘岛
SIM,模拟类型,比如模拟养成,模拟经营等等。
SPG体育竞技类型,经典游戏:
FIFA,NBA,实况足球。
RAC赛车类游戏,例如:
极品飞车,GT赛车,摩托英豪。
PUZ益智类游戏,例如:
俄罗斯方块,泡泡龙,宝石方块。
MUG音乐节奏类,例如:
劲舞团,劲乐团。
介绍完游戏的大致类型,以后我们还需要知道,做一个完整的游戏需要额外掌握哪些知识,首先,我们要明白,做一个游戏,不只是靠满天飞的代码就可以实现,我们还需要借助很多工具和框架,一个游戏中,可能需要几种甚至几十种工具才能完成,这里我首先给大家介绍以后开发游戏需要用到的几种类型工具和框架。
地图制作工具,一个游戏的地图不是简简单单通过代码完成,还需要借助这样的工具让我们开发人员能更容易调节地图的显示。
人物制作工具,每一个人物的动作是很多动画或者图片拼凑而成,所以这样的工具也很重要。
任务剧情制作工具,此工具一般由我们开发人员自己编写工具类来实现,它的作用不言而喻,目的就是为了更好的管理,添加和修改游戏的剧情任务。
音乐动画制作工具,当然,如果你觉得一个无声的游戏也一样有趣,那么可以当我没有说过这个东西的存在。
物理引擎,重力感应加速,特效封装,这几样东西也是很重要的,当然,不是每个游戏都一定需要。
游戏框架,一个游戏是否能够适应快速开发,能够方便开发人员以后的维护和更新,框架起到承上启下的作用,我们有足够实力的时候可以开发自己的框架,也使用市面上免费或者收费的框架来更好的开发游戏。
最后,2D,2.5D,3D知识和代码的逻辑思想也是必不可少的,当然这就需要我们开发人员有非常强的编程功底。
好了,大家不要怪我说这么多废话,这些知识决定以后大家开发的游戏是精品还是垃圾,我会首先带大家一步步的学会怎样制作一个2D的游戏,3D游戏因为需要的相关知识内容有点多,我在最后只能给大家抛砖引玉了。
下面,我们就进入Android平台开始我们的游戏开发旅程吧!
Android游戏开发入门
View和SurfaceView游戏必用的视图类介绍
开发游戏的时候,大家一定要注意,我们不会再使用前面的Activity来实现界面的UI显示,而是通过View或者SurfaceView来显示游戏内容,因为游戏界面很多时候,整个手机的画面都需要不断的变化,这对于Activity来说是非常吃力的一种做法,虽然我们前面使用Activity做过类似的小游戏,当时大家还有感觉到,现在我就必须要纠正大家的思想,Activity对于游戏的支持是非常菜的,所以我们开发游戏不会选择Activity,而是选择View或者SurfaceView来负责UI界面显示功能。
View类是Android游戏开发中,显示游戏UI界面的老大,任何与绘制有关系的控件都是它的子类,包括SurfaceView。
SurfaceView和View最本质的区别在于,SurfaceView是在一个新的独立线程中来重新绘制画面而View必须在UI的主线程中更新画面。
大家前面学习了Activity就知道,如果Activity中有方法调用,也算作是Activity同一线程,除了HandlerThread,所以如果某一方法在调用的时候出现耗时比较长的操作,那么Activity也会被阻塞,同样的道理,View是在UI主线程中更新画面,如果更新画面耗时长,那么UI界面也会被阻塞,那么将无法响应按键,触屏等消息,用户会看到游戏界面假死的状态,这样的情况,不管是开发人员还是用户都是不愿意看到的,而使用surfaceView由于是在新的线程中更新画面所以不会阻塞你的UI主线程,也就不会出现屏幕假死状态。
但这也带来了另外一个问题,就是事件同步。
比如用户触屏了一下,你需要surfaceView中的线程来处理,一般就需要有一个事件保存方法来保存touch内容,这会稍稍复杂一点,因为涉及到线程同步。
基于以上的实际情况,根据游戏特点,如果你的游戏不占CPU,例如小型游戏,那么用View就比较好,符合标准Android操作方式,由系统决定刷新的时机。
但可惜的是,大部分时候,你都不可能做到不让你的程序占CPU,所以你就只好使用SurfaceView来强制刷新了。
那么我们就需要有以下的两种准备和判断:
第一种,被动更新画面。
比如战棋类游戏,这种用view就很好。
因为画面的更新是依赖于onTouch事件来更新,可以直接使用invalidate方法就可以做到刷新。
而且这种情况下,每一次Touch相隔的时间会比较长些,不会产生影响。
第二种,主动更新画面。
比如一个人物在一直跑动。
这就需要一个单独的线程来不停的重绘人物状态,避免阻塞主界面UI线程。
我们就需要启动一个新的线程来执行刷新重绘功能,这时候用SurfaceView将会好很多。
因为前面没有太复杂的图形内容显示,所以前面的演示我将会全部使用View来显示UI界面,首先我会给大家讲解View的基本用法,后面,我们会通过两节来看看它们各自的详细用法。
View的使用
View是一个显示UI的重要类,它可以当做原来的layout.xml布局文件一样加载到一个Activity中,而View类我们继承以后,只需要重写onDraw方法就可以实现基本UI设计了,下面的代码演示:
首先我们看到View视图框架的编写,下面我只列出了空的框架,我们要绘制图形,就需要把展现代码添加到onDraw方法中。
publicclassGameViewextendsView{
publicGameView(Contextcontext){
super(context);
}
@Override
publicvoidonDraw(Canvascanvas){
super.onDraw(canvas);
……
}
}
然后由Activity来添加这个View。
publicclassGameActivityextendsActivity{
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
GameViewview=newGameView(this);
setContentView(view);
}
}
通过上面两个类的实现,我们就做成一个基本的图形显示框架了,这是我们首先必须要知道的内容,记住这个结构,因为当Activity启动并且显示出来的时候,View类会首先调用自身的构造函数,然后自动执行onDraw方法,所以我们后面的图形类都将编写到onDraw方法中。
如果我们的View类要不断的刷新界面图像,那么就需要用到postInvalidate方法和invalidate方法,此方法会重新绘制界面的图像的内容,当然,我们在没有改变图像显示的时候,调用此方法是没有用的,而且我们不能直接调用它,而是应该启动一个线程隔几毫秒就调用一次,这样如果图像发生改变,postInvalidate就会及时更新界面的图像内容,所以我们基于此规则,制作了下面的一个新框架结构:
publicclassGameViewextendsViewimplementsRunnable{
publicGameView(Contextcontext){
super(context);
newThread(this).start();
}
@Override
publicvoidonDraw(Canvascanvas){
super.onDraw(canvas);
}
publicvoidrun(){
while(!
Thread.currentThread().isInterrupted()){
try{
Thread.sleep(100);
}catch(InterruptedExceptione){
e.printStackTrace();
}
postInvalidate();
}
}
这样设计的作用,是启动一个新线程来不断调用postInvalidate方法,起到及时更新的作用,当然,这是前期我们展现一种办法,但并不是最终的解决方法,后面我会详细说明,前面因为我并不想把问题搞复杂,所以我会以最简单的模式给大家演示。
注意一点:
在调用postInvalidate方法的时候,我们检查一下,onDraw方法是否在不断的执行。
注意:
下面的知识点需要大家先把Graphics相关知识学完以后再来学习,否则可能有很多内容看不懂。
View的双缓冲自定义设计
前面已经给大家说过View在刷新图形方面是比不上SurfaceView的,一个最简单的例子就是,我们现在在屏幕上以非常快的速度展现一帧一帧的动画,可能会出现的情况是前面一帧动画没有结束,后面的动画就抢着显示出来,那这样的结果就会让玩家看到动画是闪烁的状态,动画显示不完整。
那么我们有没有办法可以稍稍提升一下它的效率呢,让每一帧动画都可以显示完整并且不会出现闪烁呢?
答案是可以的,那就是我们要实现双缓冲技术,SurfaceView默认就是实现了此技术的,所以处理图像的能力比View要强很多,所以我们以后再用到SurfaceView的时候,不用考虑是否需要实现双缓冲技术,我们现在来看看View怎样实现双缓冲技术。
注:
双缓冲技术是把要显示的图片首先存储到内存中处理,然后再显示到屏幕上面。
Activity保持不管,修改View的代码:
publicclassGameViewextendsViewimplementsRunnable{
Bitmapbitmap=null;
BitmapbitmapBuffer=null;
Paintpaint=null;
intx=0;
inty=0;
//构造函数中创建图片对象-->创建图片缓冲区-->创建画布-->创建画笔-->把缓冲区装在到画布中-->画布绘制图片
publicGameView(Contextcontext){
super(context);
bitmap=((BitmapDrawable)getResources().getDrawable(R.drawable.feiji)).getBitmap();
bitmapBuffer=Bitmap.createBitmap(320,480,Config.ARGB_8888);
Canvascanvas=newCanvas();
paint=newPaint();
canvas.setBitmap(bitmapBuffer);
canvas.drawBitmap(bitmap,x,y,paint);
System.out.println("GameViewConstructor");
newThread(this).start();
}
//画布绘制缓冲区
@Override
publicvoidonDraw(Canvascanvas){
super.onDraw(canvas);
System.out.println("GameViewonDraw");//检查
canvas.drawBitmap(bitmapBuffer,x,y,paint);
}
publicvoidrun(){
while(true){
try{
Thread.sleep(100);
}catch(InterruptedExceptione){
e.printStackTrace();
}
x++;
y++;
postInvalidate();
}
}
}
运行代码,效果就会出来,图片会非常流畅在移动,这样的运行效率会比原来直接画出来移动的效率要高不少,当然还是比不上SurfaceView的效率。
SurfaceView的使用
手机游戏开发中,游戏复杂度比较高,动画显示内容比较快,比较多的时候,通常使用的SurfaceView,而不是View。
我们通过结构图可以看出,SurfaceView是View的一个子类,SurfaceView就是为游戏开发而生的。
根据官方的解释,SurfaceView内嵌了一个专门用于绘制的Surface。
你可以控制这个Surface的格式和尺寸。
SurfaceView控制这个Surface的绘制位置。
SurfaceView提供了一个可见区域,只有在这个可见区域内的Surface部分内容才可见,可见区域外的部分不可见。
SurfaceView变得可见时,Surface被创建,SurfaceView隐藏前,Surface被销毁,这样可以节省资源。
如果你想自己来处理Surface创建和销毁,可以重写surfaceCreated(SurfaceHolder)和surfaceDestroyed(SurfaceHolder)两个方法(必须重写)。
SurfaceView的核心在于提供了两个线程:
UI线程和渲染线程。
这里应注意:
所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。
渲染线程所要访问的各种变量应该做同步处理,由于Surface可能被销毁,它只在
SurfaceHolder.Callback.surfaceCreated(SurfaceHolder)
和
SurfaceHolder.Callback.surfaceDestroyed(SurfaceHolder)
之间有效,所以要确保渲染线程访问的是合法有效的Surface。
我们使用SurfaceView的时候,需要监听它的创建,销毁,状态改变,所以我们需要实现一个SurfaceHolder.Callback接口,通过SurfaceHolder接口访问这个Surface,在代码中,我们可以通过getHolder()方法来得到SurfaceHolder接口对象,并且需要通过addCallBack来添加回调函数。
注意:
SurfaceView和View最本质的区别在于,SurfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。
Surfaceview中会继承View的onDraw方法,但是SurfaceView不像View会自动调用的,所以我们需要自己开发一个onDraw方法并且由自己来调用。
SurfaceView通常都是需要同步SurfaceHolder对象来完成动画,同步会增加处理的时间,但是会让整个游戏系统变得更加的平滑和稳定。
SurfaceView对于游戏开发的优势在于可以在主线程之外的线程中向屏幕上绘图。
这样可以避免画图任务繁重的时候造成UI主线程阻塞,从而提高了程序的反应速度。
对于Surface相关类,Android底层还提供了GPU加速功能,所以一般实时性很强的应用中主要使用SurfaceView而不是直接从View构建。
说了这么多,下面我们基于演示代码来看看怎样使用SurfaceView
上面是一个标准的SurfaceView内部结构图,onDraw方法是我自定义的,因为SurfaceView是不会自动调用View的onDraw方法。
我在代码中,分别基于View和SurfaceView来实现了同一个动画的播放,大家可以通过代码来比较它们之间的不同。
因为SurfaceView本身就是双缓冲的,所以建议大家在开发游戏的时候,优先选择SurfaceView。
完整的代码演示请查看thinkmoregamesurfaceview项目
屏幕的高宽,旋转,全屏
这个是实现一个游戏的基本,当然实现起来也是非常的容易,代码的写法是固定的,所以只需要记住就可以,我们开发人员必须知道分辨率,还要控制屏幕的旋转,并且需要在用户玩游戏的时候,隐藏掉标题栏然后全屏,代码如下:
publicclassGameActivityextendsActivity{
/*
*全屏模式,自动获取屏幕分辨率
*/
intscreen=0;//屏幕翻滚
intlayout=0;//屏幕全屏
intfeature=0;//标题栏
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);//设置屏幕显示无标题,必须启动就要设置好,否则不能再次被设置
setContentView(R.layout.main);
DisplayMetricsdm=newDisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
intwidth=dm.widthPixels;
intheight=dm.heightPixels;
TextViewtext=(TextView)findViewById(R.id.text);
text.setText("宽度:
"+width+"高度:
"+height);
//下面这三行是更简单的显示高宽方法,大家可以自行选择。
//Displaydisplay=getWindowManager().getDefaultDisplay();
//intwidth=display.getWidth();
//intheight=display.getHeight();
}
publicvoidclickScreen(Viewview){
switch(view.getId()){
caseR.id.one:
screen=ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;break;//右转横屏
caseR.id.two:
screen=ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;break;//左转横屏
caseR.id.three:
screen=ActivityInfo.SCREEN_ORIENTATION_BEHIND;break;//恢复屏幕
}
setRequestedOrientation(screen);//设置显示方式
}
publicvoidclickScreen2(Viewview){
switch(view.getId()){
case0x7f050003:
layout=WindowManager.LayoutParams.FLAG_FULLSCREEN;break;//全屏
case0x7f050004:
layout=WindowManager.Layout