作者:Robert Green
如果你对开发Android平台游戏感兴趣,那么你需要了解很多东西。我开发过《Light Racer》、《Light Racer 3D》、《Antigen》、《Deadly Chambers》和《Wixel》,这些游戏在Android Market上都可以找到。在开发过程中,我学到了许多有关编写Android游戏的知识,我愿意同每个人分享。如果你有游戏开发经验,那么转向手机平台不会很困难。你只需要学习框架和API即可。如果你是游戏开发新手,我在这篇文章中列举了许多起步必须了解的知识。它们可以运用到许多不同类型的游戏中,包括动作、战略、模拟和解谜。
Android是个基于Java的环境。这对新开发者来说是个好消息,相对比C++来说,Java语言因其较为简单而广泛被人采用,成为目前手机开发的常 用语言,也是目前我自己使用的语言。Google在编写API和提供范例方面的工作做得很好。该公司提供了一个展示API几乎所有功能的范例,称为 “API Demos”。如果你熟悉Java而且已经使用过Eclipse,那么让你的首款应用成功运转应该是相当简单的事情。如果你此前从未接触过代码编写,那么 你需要先掌握很多知识才能继续前进,但是也不要因此灰心。如果你有些许开发经验,想要以C++开发跨平台游戏或表现出色的Android游戏,可以查看 BatteryTech,这是个我编写的目前用于游戏开发的平台。
android-development(from android-video-player.com)
获得SDK
开发Android平台的首个步骤是获得Android SDK(游戏邦注:即软件开发工具包)。SDK包含核心库、模拟器、工具和代码范例。我强烈推荐使用Eclipse和Android Eclipse插件。如果你只面向Android平台,那么专门供Java Developers使用的Eclipse IDE是个很好的工具。如果这是你的首个Java开发项目,你可以下载整个Java SE Development Kit(游戏邦注:简称“JDK”),因为它包含你需要用于应用认证和部署的工具。
学习应用程序架构
理解Android应用程序架构也是件非常重要的事情。如果你不学习这个方面的内容,可能会使游戏完成后问题的修改变得很困难。你需要理解应用程序、活动、意图以及它们之间的相互联系。Google在架构方面已经提供了许多有价值的信息。真正重要的是,要理解游戏为什么需要包含不止一个活动以及这对设计良好用户体验的意义。我们接下来要探讨的就是活动生命周期。
学习活动生命周期
活动生命周期由Android操作系统管理。你的活动将根据操作系统的指令创建、回访、暂停和摧毁。正确处理这些事件对构建有着良好行为的应用程序非常重要,这样应用才能正确地满足用户的意图。在你开始设计游戏之前,有必要先知道所有这些内容的运转方式,这会减少你将来调试和重新设计的时间。对于多数应用程序来说,使用默认设置就可以了。但是对游戏来说,你可能需要考虑打开SingleInstance功能。当处在默认设置下时,Android会在合适的时候自动创建新活动实例。对于游戏来说,你可能只想要单个游戏活动实例。这也等于提示你需要如何来管理内容状态,但是对我来说,它解决了某些资源管理问题,所以应当考虑入列。
主循环
是否拥有主循环取决于你编写的游戏类型。如果你的游戏与时间无关,或者如果游戏只会对用户的行为做出反应,没有用户输入视觉场景就不会发生改变,那么你或许不需要主循环。如果你编写的是动作游戏或带有动画、计时器或其他自动运转内容的游戏,那么你应当认真考虑使用主循环。
游戏的主循环指以特定顺序运转子系统,通常会尽可能提升每秒主循环的次数。你的主循环需要在它自己的线程上运行。原因在于,Android有个主UI线程,如果主循环不在自己的线程上运行,那么UI线程就会受游戏影响,导致Android OS无法完成普通的更新任务。执行顺序通常是:状态、输入、AI、物理、动画、音效和视频。
更新状态意味着管理状态改变,比如游戏结束、角色选择或下个关卡。通常情况下,你需要在一个状态上等待数秒钟时间,状态管理的任务应当是处理这个延迟并设置时间过后的下个状态。
输入是指来自用户的任意按键、滚动或触碰。在处理物理前完成这个方面的内容是很重要的,因为输入往往会影响到物理效果,所以先处理输入会让游戏显得更为灵敏。在Android中,输入事件来自于主UI线程,所以你必须通过代码来缓冲输入,这样你的主循环才能适时将其捕获。这并不是个很困难的任务。所有需要做的就是为下次用户输入确定区域,用onKeyPressed或onTouchEvent将下次用户动作设置到该区域中。在特定游戏状态下,所有的有效输入都需要进行输入更新,让物理端处理针对该输入的响应问题。
AI更新类似于用户决定接下来要“按”的按键。学习如何编写AI不是这篇文章的主题,但基本想法是,AI将像用户那样按动按键。这也将被物理更新捕捉并做出响应。
物理更新可能是真正的物理,也可能不是。对于动作游戏而言,要点在于同时考虑上次更新时间、此次更新时间、用户输入和AI输入,决定游戏中所有内容的位置以及是否有碰撞发生。对于你可以看到对象抓取和滑动的游戏,物理更新还需要处理对象的互动或者让它下落到指定的位置。对于问答游戏,它还需要决定答案是否正确。或许你使用的是其他的名称,但是每款游戏的游戏引擎中都需要有处理上述内容的部分,在这篇文章中我将其称为“物理”。
动画并不只是在游戏中加入gif这么简单。你需要让游戏在恰当的时候播放每帧动画。但是,它也不像听起来那么难。要保持isDancing、danceFrame和lastDanceFrameTime等状态区域允许动画更新以决定是否转向下一帧。这就是动画更新所做的所有工作。真正负责呈现动画改变的是视频更新。
音效更新负责触发音效、暂停音效、改变音量和音调。通常在编写游戏时,音效更新会生成一连串字节传输给音效缓冲器,但是Android自行管理音效,所以针对游戏开发,你可以使用SoundPool或MediaPlayer。它们都有一点敏感,但是要知道,由于存在某些低层次的执行细节,小而低位速率的OGG也能产生最棒的运行表现和稳定性。
视频更新要考虑游戏状态、玩家位置、分数和状况等内容,在屏幕绘制所有内容。如果使用主循环,那么你可以考虑使用SurfaceView,进行“推送”绘制。如果使用其他视图,视图本身能够调用绘制运转,这样主循环就无需负责这项工作。SurfaceView能够提供最高的每秒帧数,最适合带有动画或在屏幕上有移动物体的游戏。视频更新应该做的工作是,获取游戏状态,并及时绘制在屏幕上。除此之外,其他的自动化内容最好由其他更新任务来完成。
以下是个代码范例:
public void run() {
while (isRunning) {
while (isPaused && isRunning) {
sleep(100);
}
update();
}
}
private void update() {
updateState();
updateInput();
updateAI();
updatePhysics();
updateAnimations();
updateSound();
updateVideo();
}
在你开始开发游戏前,你需要决定是制作3D还是2D游戏。2D游戏要学习的内容较少,通常更容易获得良好的表现。3D游戏需要更多的深层次数学技能,如果不注意的话,可能会产生表现问题。如果你想要添加比方形和圆圈更加复杂的形状,那么无论选择3D或2D,都需要使用3D Studio和Maya等模型工具。Android支持使用OpenGL进行3D编程,网络上有许多很不错的OpenGL教程可供阅读。
构建简单且高质量方法
开发开始时,确保不要编写又大又长的方法。如果你采用我在上文中描述的主循环样式,这样得出的方法应当较为简单。你编写的每个方法都应当能够完成某项特定任务,而且不可发生错误。比如,如果你需要在游戏中洗牌,那么就应当编写名为“shuffleCards”的方法,而且这个方法就是用来完成洗牌这个动作。
这是个可用于所有软件开发的编程方法,但是在游戏开发中显得特别重要。在状态化的即时系统中,调试会变得非常困难。要保持方法简单轻巧,最好是保证每个方法只有1个目标。如果你需要为场景绘制背景,那么你可能需要名为“drawBackground”的方法。这样会让你的游戏开发变得像搭建方块一般,你可以随时根据自己的需要添加新方块,同时不会让代码变得难以理解。
效能是关键
运行效果是所有游戏遇到的主要问题。我们的目标是让游戏的反应速度尽可能快,游戏的运行看起来尽可能流畅。Canvas.drawLine等某些方法可能执行较慢。而且,在每帧的主画布上绘制全屏位图也会耗费大量时间。要让应用实现最好的表现,平衡这些动作就成了必要之举。确保对资源进行良好的管理,使用各种技巧,实现用最少的CPU完成任务。如果表现不好,即便是最棒的游戏也显得乏味无趣。通常情况下,人们不会对反应缓慢的应用抱有好感。
技巧
看看SDK中的《LunarLander》范例。它使用的是SurfaceView,这对需要每秒帧数达到最高值的游戏来说是个合适的视图。如果你想要制作3D游戏,可以看下GLSurfaceView。它利用了OpenGL设备初始化,提供渲染机制。对于《LightRacer》,我需要优化游戏中所有内容绘制的方法,否则帧率会相当低。我只在视图初始化时用位图绘制单次背景。轻轨的位图会随赛车手的移动而获得更新。这两个位图每帧都会绘制在画布上。这种技术能让游戏以可玩的流畅度运行。
如果可以的话,将位图大小设置为与在屏幕上绘制的意向大小相同。这样,就无需对位图进行缩放,从而节省了CPU的使用。
在整个游戏中使用一致性的位图配置(游戏邦注:如RGBA8888)。这可以节省用于转换不同格式的图像库CPU。
如果你决定开发3D游戏,但没有3D的相关知识,你可以先阅读一两本有关3D游戏编程的书籍,学习线性代数。最少,你必须理解点积、叉积、矢量、单位矢量、常数、矩阵和转换。我见过的阐述游戏相关数学内容的最棒书籍是《Mathematics for 3D Game Programming and Computer Graphics》。
保持音效容量较小且码率较低。加载的内容越少,加载的速度就越快,游戏使用的内存也就越少。
要用OGG作为音效格式,用PNG作为图像格式。
当活动结束后,确保关闭所有媒体播放器并移除所有资源。这将确保垃圾收集器能够获得所有东西,在游戏的两次开启间不会出现内存泄露问题。
加入Android Google小组,寻求社区的支持。社区中有许多人会帮助你解决许多问题。
此外,花时间对游戏进行重复测试,确保游戏中所有内容的运转都与你的预期相同。润色游戏是开发过程中最漫长和最艰难的阶段。如果你匆匆将游戏推向市场,它的表现可能会让你失望,你或许也会觉得自己的艰辛都付之东流。你不可能让100%的用户都喜欢你的游戏,但是你至少应当努力呈现最高质量的作品。
游戏邦注:本文发稿于2008年5月11日,所涉时间、事件和数据均以此为准。(本文为游戏邦/gamerboom.com编译,拒绝任何不保留版权的转载,如需转载请联系:游戏邦)
Getting Started in Android Game Development
Robert Green
If you’re interested in developing a game for the Android platform, there is a lot you need to know. I’m the developer of Light Racer, Light Racer 3D, Antigen, Deadly Chambers and Wixel, which are currently available on the Android Market. I’ve developed games before but the original Light Racer was my first Android application and I learned quite a bit about writing Android games that I’d like to share with everyone. I even wrote an online book detailing the development of Light Racer 3D, which is full of how-tos and useful code snippets. If you have previous experience with game development, moving over to the mobile platform won’t be all that difficult. You will mostly just need to learn the architecture and API. If you’re new to game development, I have assembled a list of must-knows for getting started. They apply to many different types of games, including action, strategy, simulation and puzzle.
Android is a Java-based environment. This is nice for new developers as Java is widely accepted as a much easier language to get started in than C++, which is the norm for mobile development and is what I use now. Google has also done an excellent job with documenting the API and providing examples to use. There is an example to show functionality for almost 100% of the API, called API Demos. If you’re familiar with Java and have already used Eclipse, getting your first app working should be fairly simple. If you’ve never coded anything in your life before, you will have a lot to absorb as you move forward, but don’t get discouraged. If you have some experience and are wanting to develop a cross-platform game or high-performance Android game in C++, check out BatteryTech, which is a platform I wrote and am currently using for game development.
Get the SDK
The first step in getting started with the Android platform is to get the Android SDK (Software Development Kit). The SDK has the core libraries, an emulator, tools and sample code. I highly recommend using Eclipse and the android eclipse plugin. Eclipse IDE for Java Developers is fine if you are just doing Android. If this is your first Java development project, you will want to download the full Java SE Development Kit (JDK) as it contains tools you will need for signing and deploying your application.
Learn the application architecture
As tempting as it may seem to just dive right in, it’s very important to understand the android application architecture. If you don’t learn it, you may design things in such a way that will make it very difficult to fix problems with your game down the line. You will want to understand Applications, Activities, Intents and how they are all related to each other. Google has provided good information on the architecture here. The really important thing is to understand why your game may need to consist of more than one Activity and what that means to designing a game with good user experience. This is where things tie in to the Activity lifecycle.
Learn the activity lifecycle
The activity lifecycle is managed by the Android OS. Your activity will be created, resumed, paused and destroyed as the OS dictates. Handling these events correctly is very important to having an application that behaves well and does what the user perceives as correct. It’s very good to know how all of this works before you start designing your game because you will save yourself debugging time and costly redesign time later on. For most applications, the default settings will work but for games, you may want to consider turning the SingleInstance flag on. When set as default, android will create new instances of the activity as it sees fit. For a game, you may only want to have 1 instance of the game activity. This has some implications for how you need to manage the state of things but for me it solved some resource management issues and it should be considered.
The main loop
Depending on what type of game you are writing, you may or may not have a main loop. If your game is not time-dependent or if it only responds to what the user does and will wait forever for user input without making any kind of visual changes, you may not need a main loop. If you are writing an action game or a game that has animations, timers or any kind of automation, you should seriously consider using a main loop.
The main loop of a game is the part that “ticks” sub systems in a specific order and usually as many times per second as possible. Your main loop will need to run on its own thread. The reason for this is that Android has a main UI thread and if you don’t run your own thread, the UI thread will be blocked by your game which will cause the Android OS to not be able to handle any of its normal update tasks. The order of execution is usually as follows: State, Input, AI, Physics, Animation, Sound and Video.
Updating State means to manage state transitions, such as a game over, character select or next level. Often times you will want to wait a few seconds on a state and the State management is the part that should handle this delay and setting the next state after the time has passed.
Input is any key, scroll or touch from the user. It’s important to handle this before processing Physics because often times input will affect the physics so processing input first will make the game more responsive. In Android, the input events come in from the main UI thread and so you must code to buffer the input so that your main loop can pick it up when the time comes. This is not a difficult task. Defining a field for the next user input and having the onKeyPressed or onTouchEvent set the next user action into that field is all that will be required. All the Input update needs to do at that point is determine if it is valid input given the state of the game and let the Physics side handle responding to it.
The AI update is analagous to a user deciding what they are going to “press” next. Learning how to write AI is out of the scope of this article but the general idea is that the AI will press buttons just like the user does. This will also be picked up and responded to by the Physics update.
The Physics update may or may not be actual physics. For action games, the point of it is to take into account the last time it was updated, the current time it is being updated at, the user input and the AI input and determine where everything needs to be and whether any collisions have occured. For a game where you visually grab pieces and slide them around, it will be the part that is sliding the piece or letting it drop into place. For a trivia game, it would be the part deciding if the answer is right or wrong. You may name yours something else, but every game has a part that is the red meat of the game engine and for this article, I’m referring to it as Physics.
Animations aren’t as simple as just putting an animated gif into your game. You will need to have the game draw each frame at the right time. It’s not as difficult as it sounds. Keeping state fields like isDancing, danceFrame and lastDanceFrameTime allows for the Animation update to determine if its time to switch to the next frame. That’s all the animation update really does. Actually displaying the change of animation is handled by the video update.
The Sound update handles triggering sounds, stopping sounds, changing volumes and changing the pitch of sounds. Normally when writing a game, the sound update would actually produce a stream of bytes to be delivered to the sound buffer but Android manages its own sounds so your options for games are to use SoundPool or MediaPlayer. They are both a little sensitive but know that because of some low level implementation details, small, low bitrate OGGs will yield the best performance results and the best stability.
The Video update takes into account the state of the game, the positions of players, scores, statuses, etc and draws everything to screen. If using a main loop, you will want to use the SurfaceView and do a “push” draw. With other views, the view itself will call the draw operation and the main loop won’t have to do it. SurfaceView gives the highest frames per second and is the most appropriate for games with animation or moving parts on screen. All the video update should do is take the state of the game and draw it for this instance in time. Any other automation is better handled by a different update task.
What’s this code look like? Here’s an example.
3D or 2D?
Before you start on your game, you need to decide if you’re going to go 3D or 2D. 2D games have a much lower learning curve and generally are easier to get good performance on. 3D games require much more in-depth math skills and may have performance issues if you are not very careful. They also require the ability to use modeling tools like 3D Studio and Maya if you intend to have shapes more complex than Boxes and Circles. Android supports OpenGL for 3D programming and there are many good tutorials on OpenGL that one can find to learn it.
Build simple, high quality methods
When getting started, make sure that you avoid writing one big long monolithic method that is “the game.” If you follow the main loop pattern that I described above, this should be fairly easy. Each method you write should accomplish one very specific task and it should do so error-free. For example, if you need to shuffle a deck of cards, you should have a method called “shuffleCards” and that should be all it does.
This is a coding practice that applies to all software development but it’s particularly important in game development. Debugging can get very difficult in a stateful, real-time system. Keep your methods small and the general rule of thumb is that each method should have 1 and only 1 purpose. If you’re going to programatically draw a background for a scene, you may want a method called “drawBackground.” Things like that will make it so that you develop your game in terms of building blocks and you will continue to be able to add what you need without making it too complex to understand.
It’s all about efficiency!
Performance is a major issue for any game. The goal is to make the game as responsive as possible and to also look as smooth as possible. Certain methods like Canvas.drawLine are going to be slow. Also drawing an entire screen-sized bitmap onto the main canvas every frame will also be costly. Balancing things like that is necessary to achieve the best performance. Make sure to manage your resources well and use tricks to use the least amount of CPU to achieve your task. Even the best game will not be very fun if it can’t perform well. People in general have little tolerance for choppiness or poor response.
Tips and Tricks
Take a look at the example for LunarLander in the SDK. It uses a SurfaceView and that would be the appropriate view to use for a game that needs the highest number of frames per second possible. If you’re going 3D, take a look at GLSurfaceView. It takes care of the OpenGL device initialization and provides a mechanism for rendering. For LightRacer, I had to optimize the way I have everything drawn or else the framerate would be drastically lower. I drew the background to a Bitmap only once which was when the view is initialized. The light trails are in their own bitmap which gets updated as the racers move. Those two bitmaps are drawn to the main canvas every frame with the racers drawn on top and then finally an explosion. This technique made the game run at a playable rate.
It’s also a good practice to have your bitmaps be the exact size you intend to draw them on screen, if applicable. This makes it so that no scaling is needed and will save some CPU.
Use a consistent Bitmap Configuration (like RGBA8888) throughout the game. This will save the graphics library CPU in having to translate the different formats.
If you’re determined to develop a 3D game but have no 3D knowledge, you will want to pick up a book or two on 3D game programming and study up on linear algebra. At a bare minimum, you must understand dot products, cross products, vectors, unit vectors, normals, matrixes and translation. The best book I have come across for this math is called Mathematics for 3D Game Programming and Computer Graphics.
Keep the sound small and at a low bitrate. The less there is to load, the faster loading times will be and the less memory the game will use.
Use OGGs for sound, PNGs for graphics.
Make sure to release all media players and null out all of your resources when the activity is destroyed. This will ensure that the garbage collector gets to everything and that you don’t have any memory leaks between launches of the game.
Join the Android Google group and find community support. There will be people that can help you along the way.
Above all, spend time testing and retesting and making sure that every little thing works exactly the way you would expect it to. Polishing the game up is the longest and hardest part of development. If you rush it out to market, you will probably have a disappointed crowd and you may feel that all your hard work is wasted. It’s not possible to have 100% of people love what you write but you should at least try to put out the highest quality work that you can.
Google has excellent documentation for getting started here.
Find working game code samples and how-tos in the Light Racer 3D Development Journal
Need a book recommendation? Try Beginning Android Games by Mario Zechner (Author of libgdx and friend of mine).
Finally, Battery Powered Games offers pro Android (and iOS) game development consulting services so if your company has a need to contract out mobile game development, that’s the place to go! (Source: Robert Green’s DIY)
转自:http://gamerboom.com/archives/53217