Android游戏开发详解(txt+pdf+epub+mobi电子书下载)


发布时间:2020-08-05 17:46:15

点击下载

作者:[美] James S Cho 乔伊

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Android游戏开发详解

Android游戏开发详解试读:

前言

作为对编程知之甚少或者毫无所知的初学者,开始学习Android游戏开发,可能会觉得就像是穿越陌生的星际的旅程。有太多的事情要尝试,太多的知识要学习,令人遗憾的是,还有如此之多的方式令人陷入迷途。

究其原因之一,可能是Android游戏开发给人以很简单的错觉。这个术语给人的感觉是,只需要学习和掌握一个主题就够了,实际上,Android游戏开发包括各种不同的主题,其中的一些如下所示。● 编程基础;● Java编程语言;● 面向对象设计原理;● 游戏开发;● 代码优化;● Android应用程序开发。

如果你不了解这些主题,也不必惊讶!这正是需要指南的地方。本书是为初学者而编写的,作者也曾经是初学者,不知道从何处开始学习。本书将引导你经历构建自己的Android游戏的每一个步骤。如果这正是你的学习目标,那么,这本书很适合你。

本书并不会对读者做太多假设。当然,我们假设你有基本的数学知识,并且知道如何在计算机上安装程序或应用,但是,并不会假设你之前编写程序,或者有物理学的学位。

如果你是第一次开始编写代码,肯定会遇到一些问题。这没事。实际上,当你遇到难处,请访问本书的配套网站并寻求帮助。无论是编辑、Kilobolt的工作人员或者是陌生人,都会乐意帮助你解答问题或解决问题。

学习本书过程中,你将会阅读和编写很多代码。一些章节的整个篇幅都是学习如何编写代码,并且很少讨论游戏开发。其背后的思路是,如果你能够脱离游戏开发的环境去理解和编写代码,那么,在创建图形和游戏的时候,你可以很容易地应用这些知识。

通过从头到尾依次阅读,你将会从本书中获益良多。尽管如此,如果你记得对某个主题非常熟悉的话,跳过它也没问题。周期性的知识点检查,允许你下载工作项目的最新版本,并且从一个部分或一章的中间开始工作。

此外,要力图保持积极。你的学习旅程不会像穿越未知的星际那样紧张、刺激,但是,我期望它同样能够令人兴奋。有本书作为你的指导,你立刻就可以创建自己的游戏。

尽管本书的编写尽量全面,但是,一本书恐怕不足以涵盖Android游戏开发的主题。尽管如此,本书会随着配套网站一起完善。如果你觉得某个概念的介绍不够全面,请通过jamescho7. com/book/feedback反馈给我们。作者很高兴能够更详细地介绍一些重要的概念。致谢

我想要感谢Glasnevin出版社的Helen McGrath博士,她给了我编写本书的机会。在整个过程中,她给予了巨大的帮助,没有她的话,不可能有这本书。

接下来,我要感谢Dr. Bryan Mac Donald、Kyle Yu、Vignesh Sivashanmugam以及所有其他不厌其烦地编辑我的书稿,使其尽可能减少错误的人们。得益于他们的努力,本书才能够成为那些想要学习Android游戏开发的人们的合适的指南。

感谢Racheal Reeves为本书封面做出的精彩设计。由于Racheal的努力工作,本书才如此完美。最后感谢Ling Yang无尽的耐心。Ling的爱支持和激励我在很多不眠之夜努力工作以完成这本书,我希望Ling有一天能够读到它。Web资源

本书中给出的Java和Android代码,以及其他附加资源,都可以通过本书的配套站点获取:http://www.jamescho7.com。

对本书的任何评论、建议和勘误,欢迎通过以下电子邮件联系:

info@glasnevinpublishing.com。作者简介

James有多年的游戏开发经验。他最早在笔记本上开始了自己的游戏开发职业,最终创建了Kilobolt,这是一家位于美国的独立游戏工作室。此外,他还教授一系列流行的编程课程,并且在杜克大学学习计算机科学的同时担任助教。

除了编写代码,阅读科学研究相关的文献,James还是曼联球迷,并且不断探索新的美食。第1部分Java基础知识第1章 程序设计基础

无论是何种情况,你离成为一名程序员都还相去甚远。本章将为你打下很好的基础,以便你能够成长为一名善于思考的、成功的Java程序员,从而能够编写高效的代码并构建优秀的游戏。我们从第2章开始,才会真正地编写程序,因此,现在你还不需要计算机。1.1 什么是编程

从最基本的层面看,编程是让计算机执行以代码(code)的形式给出的一系列的任务。让我们来看一些示例代码,看看程序员能够提供什么样的指令。现在,还不要关心每个符号和每行代码背后的含义。我们将在本书中详细介绍这些。现在,先尝试理解其逻辑。阅读每行代码前面的注释,尝试搞清楚后面的代码的意图。

程序清单1.1 程序员的指令01 // Instruct the computer to create two integer variables called a and 02 // b, and assign values 5 and 6, respectively.03 int a = 5;04 int b = 6;05 // Create another integer variable called result using a + b. 06 int result = a + b;07 // Print the result (Outputs the value of result to the Console).08 print("The value of a + b is " + result);

程序清单1.1展示了程序员输入到像Notepad(Windows)或TextEdit (Mac)这样的一个文本编辑器中的内容。计算机在控制台所产生的输出如下所示。

The value of a + b is 11

好了,我们看完了Java代码的一个小示例。在继续学习之前,这里有一些需要记住的关键知识点。

关键知识点代码执行的基本规则

代码是从上到下一行接着一行地执行的。这是一个简化的说

明,但是,现在很适合我们。稍后,我们会给这条规则添加

内容。注释( // )

在Java中,两条斜杠后面的内容是注释。注释是为人类而编

写的(在这里是我向你描述代码的方式),因此,Java虚拟

机(Java Virtual Machine,稍后详细介绍Java虚拟机)不会

执行注释。行号

我们可以通过行号来引用代码。在确定行号的时候,必须把

注释和空行都算在内。例如,在程序清单1.1中,如下的代

码出现在第3行。

int a = 5;

正如程序清单1.1所示,我们可以让计算机把值存储为变量,并且我们可以对这些值执行数学计算和连接(连接是将文本和整数组合起来,参见程序清单1.1第8行)。我们甚至可以在控制台显示这些运算的结果。这只是冰山一角。稍后,我们可以绘制一个视频游戏角色,并且实现它在屏幕上移动的动画,它每走一步还会发出脚步声。看上去如下所示(注意,下面只是一个示例。在学习完本书的几章之后,你将能够编写自己的代码)。

程序清单1.2 更复杂的指令的示例while (mainCharacter.isAlive()) {  mainCharacter.updatePosition();  mainCharacter.animate(time);   if (mainCharacter.getFoot().collidesWith(ground)) {  footstepSound.play(volume);   }  screen.render(mainCharacter); }1.2 数据类型1.2.1 基本类型

在前面的示例中,我们看到了数据类型(data type)的例子。例如,在程序清单1.1中,我们使用了整数值(integer value)5和6,这两个都是数值数据的例子。我们来看看其他的数据类型,先介绍其他的数值类型。● 可以使用4种类型来表示整数(Integer),每种类型都用不同的

大小。在Java中,我们有8位的byte、16位的short、32位的int和

64位的long。4种类型中的每一种,都可以保存正的和负的整数

值。● 有两种类型可以表示小数值(Decimal,如3.14159):32位的

float和64位的double。● 可以使用char表示一个单个的字符或符号。

这些是Java中主要的基础数据类型,我们称之为基本数据类型(primitive type)。在后面各章中,我们将会看到很多使用基本数据类型的例子。1.2.2 字符串

字符串(String)指的是一系列的字符。正如其名称所示,我们可以使用字符串将多个字符保存到一起(而基本类型char只能够保存一个字符)。char firstInitial= 'J';char lastInitial = 'C';String name = "James";

注意,这里关键字String的首字母大写了,而基本数据类型char的首字母没有大写。这是因为,字符串属于对象(object)一类,而不属于基本数据类型。我们稍后要花很多时间讨论这些对象,它们在Java编程中扮演重要的角色。现在,我们只需要将字符串当作基本数据类型一样对待就行了。1.3 声明和初始化变量

所有的基本数据类型(和字符串)都可以表示为变量。它们都是使用相同的基本语法来声明(创建)的。

创建一个新的变量的时候,我们总是要声明两件事情:变量的数据类型(data type)和变量的名称(variable name)。在大多数情况下,我们还使用赋值运算符(assignment operator,即=)给变量指定一个初始值。有两种方法做到这点。第一种方法是指定一个字面值(literal value),例如,图1-1所示的'J'。第二种方法是,指定一个计算值的表达式(expression),例如,图1-1所示的35 + 52(这个表达式在赋值之前计算)。图1-1 变量声明的示例

赋值运算符(=)不是在声明相等性。这一点很重要。正如其名称所示,我们使用赋值运算符把一个值(在等号的右边)赋给(assign)一个变量(在等号的左边)。例如,考虑如下两行代码。int a = 5;a = a + 10;

在这个例子中,我们不是要表示a和a + 10的对等关系。我们直接将a + 10的值赋值给一个已有的变量a。进行区分的一种较好的方法是,将等号读作“获得”。因此,图1-1应该读作,“int类型的num获得了表达式35 + 52的结果”。

作为一个练习,浏览一下程序清单1.3的6行代码中的每一行,并且尝试将其读出声,说出每行的含义。记住,要区分字面值(literal value)和表达式(expression)(如果忘记了,再回顾一下图1-1)。第1行应该读作“short类型的num获得了15”。记住,这意味着,“声明了一个类型为short、名为num的变量,并且将字面值15赋值给它”。

程序清单1.3 声明各种变量1  short numberOfLives = 15;2  long highScore = 21135315431 - 21542156; // uses an expression;3  float pi = 3.14159f;4  char letter = 'J';5  String J = "James";6  boolean characterIsAlive = true;1.3.1 变量名和字面值

注意,当我们讨论字符和字符串的时候,使用了‘ ‘和“ ”将字面值和具有相同名称的变量(variable)区分开来。例如,在程序清单1.3中,变量名J引用“James”,而字面值‘J’指的是它自己。1.3.2 初始化或不初始化

在以上的每个示例中,我们在声明过程中都使用了一个初始值来初始化(initialized)变量。然而,正如我在本节开始所介绍的,声明一个变量的时候初始化它(分配一个初始值),这本身并不是必须要做的。例如,我们可以这么做。int a, b, c;a = 5;b = 6;c = 7;

上面的第1行代码声明了3个整数类型,分别名为a、b和c。没有明确地赋给其初始值。接下来的代码行分别用值5、6和7初始化了这3个整数。

尽管这么做是允许的,我们通常也将声明变量并初始化它们,就像在前面程序清单1.3中所做的那样。

关键知识点声明变量

当创建一个新的变量的时候,我们把一个值存储到计算机的

内存中以便随后使用。我们可以使用该变量的名称来引用它。

打个比方,可以把变量看作一个盒子。当我们输入int a = 5

的时候,是告诉Java虚拟机创建一个相应大小的盒子,并且

把我们的值放进去。引用变量

一旦创建了变量,在引用它的时候,我们不应该声明其类型。

提供变量的名称就足够了。复制值

考虑如下所示的代码。

int x = 5; // declare a new integer called x

int z = x; // assign the value of x to a new integer z

z = z + 5; // increment z by 5

[End of Program]

你能告诉我,在程序结束的时候,x和z分别是什么值吗?如

果你的回答是5和10,那么你答对了!

如果不是,也不必担心。很多初学者都不能正确地理解第2

行代码。在第2行代码中,我们不是说int x和int z引用相同的

盒子(变量)。相反,我们创建了一个名为int z的新盒子,

并且将int x的内容复制后赋给它。

这对我们来说意味着什么呢?这意味着,当我们在第3行将z

和5相加的时候,z变成了10,而x仍然是5。1.4 关于位的一切(位和字节的简单介绍)

在我们继续深入之前,值得先细致地介绍如何具体把值存储到变量中。我前面提到,不同的基本数据类型具有不同的位大小。例如,一个int有32位而一个long有64位。你可能会问,那么,到底什么是位?

位(bit)是一个二进制位的简称。换句话说,如果你有一个只有0和1的二进制数,每个数字就是1位。达到8位的时候,例如,(10101001),你就有了1字节。

对于位,你需要记住的一点是:拥有的位越多,所能表示的数值也越多。为了说明这一点,让我们问一个问题。十进制的1位能够表示多少个数字?当然是10个(0,1,2,3,4,5,6,7,8和9)。两位呢?100个(00,01……99)。我们看到,每增加一个位数,都会使得我们所能表示的数值增多到原来的10倍。对于二进制数字来说,也是如此,只不过每次增加一位,所能表示的数值的数量是原来的两倍。

在计算中,位是很重要的,因为我们所操作的机器是由细小的电路组成,而这些电路要么是开,要么是关。数据表示的挑战,完全由此而引发。我们不能使用这些电路来直接表示“hello”这样的单词。我们必须使用任意某种系统将单词“hello”和某些电路的开关组合联系起来。

这就是我们应该了解的和变量相关的知识。通过声明一个新的变量,我们在内存中分配了特定数目的位(根据声明的类型),并且将某些数据的一个二进制表示存储起来,以便随后使用。在数据类型之间转换

在Java中,可以将一种数据类型转换为另一种类型。例如,我们可以接受一个int值并且将其存储到一个long变量中。之所以能这样,是因为long变量保存了64位,可以很容易地容纳来自较小的类型int(32位)中的数据而不会遇到麻烦。但是,如果我们接受一个64位的long数字,并且试图将其放入到一个32位的int的“容器”中,将会发生什么呢?会有丧失精度的风险。这64位中的32位,必须删除掉,然后我们才能将数字放置到int变量中。

规则是这样的:如果从一个较小的类型转换为一个较大的类型,这是安全的。如果要从一个较大的类型转换为一个较小的类型,应该小心以避免丢失重要的数据。稍后,我们将详细介绍如何从一种类型转换为另一种类型。1.5 运算

我们前面看到了,变量可以用来存储值,并且变量可以在运算中用作运算数,如图1-2所示。图1-2 变量可以用来存储值,也可以用作运算数1.5.1 算术运算

表1-1所列内容是你必须知道的5种算术运算。在了解示例的过程中,请记住如下两条规则。

规则 #1  涉及两个整数的一个运算,总是会得到一个整数的结果(整型变量中不允许有小数值)。

规则 #2  至少涉及一个浮点数(小数值)的运算,其结果总是浮点数。表1-1  必须知道的5种运算运算符说明示例/值+(加3 + 10 = 13 4.0f + 10 = 将加号两边的运算数相加法)14.0f−(减从第一个运算数中减去第16 − 256 = -240法)二个运算数*(乘将乘号两边的运算数相乘4.0f * 3 = 12.0f法)用第一个运算数除以第二6/4 = 1 记住规则#1,我们/(除个运算数 前面提到的两条将其向下舍入到最近的整法)规则在这里特别重要数 6.0f/4 = 1.5f 记住规则#2%(求10 % 2 = 0 (执行10/2,然余数、计算除法运算的余数后计算余数,也就是0) 7 模除)% 4 = 31.5.2 运算顺序

在执行运算的时候,使用标准的运算顺序。计算机将会按照如下的顺序执行运算。

1.圆括号(或方括号)。

2.指数。

3.乘法/除法/余数。

4.加法/减法。

如下的示例说明了运算顺序的重要性。print(2 + 5 % 3 * 4);——输出“10”。print((2 + 5) % 3 * 4);——输出“4”。1.5.3 关系/布尔运算

现在来看看在两个值之间进行比较的关系运算符,如表1-2所示。注意,在下面的示例中,算术运算在关系运算之前执行。如下所有的计算,都得到一个true或false值(布尔)。表1-2  关系运算符用来确定一个值与另一个值进行比较的结果运算符说明示例/值(3 + 10 == 13)  = == (等检查运算符两边的两个值是否相true (true == false)于)等  = false!=(不等检查运算符两边的两个值是否不(6/4 != 6.0f/4)  = 于)相等true>(大判断第一个运算数是否比第二个6 > 5 = true于)运算数大<(小判断第二个运算数是否比第一个6 < 5 = false于)运算数大>=(大于或等含义明显6 >= 6 = true于)<=(小于或等含义明显10 <= 9 + 1 = true于)!(取将一个布尔值取反。这是一个一!true = false !false 反)元运算符(只需要一个运算数)= true

关键知识点赋值和比较

注意,==运算符和=运算符不同。前者(==)用来比较两个值,

并且输出一个true或false值。后者(=)用来将一个值赋值给一

个变量。

下面的程序清单1.4展示了使用这些关系运算符的另外两个示例。我已经给每一条print语句加上了标签,以便你可以看到相应的输出。

程序清单1.4 关系运算符01  print(1 == 2); // #1 (equal to)02  print(!(1 == 2)); // #2 (inverse of print # 1)0304  int num = 5;05  print(num < 5); // #3 (less than)0607  boolean hungry = true;08  print(hungry); // #4 09  print(hungry == true); // #5 (equivalent to print #4)10  print(hungry == false); // #6 11  print(!hungry); // #7 (equivalent to print #6)

程序清单1.4的输出如下所示。

true

false

true

true

false

false

下面几个小节将会假设你理解关系运算符如何工作,因此,确保你理解每条打印代码行中发生了什么。仔细看一下程序清单1.4中的示例#5和示例#6,理解为什么我们要省略==运算符。1.5.4 条件运算符

两个主要的条件运算符是|| (OR)和&& (AND)。如果|| (OR)运算符任意一边的布尔值为真,该运算符将求得真。只有&& (AND)运算符两边的布尔值都为真时,该运算符才会求得真。

我们假设你想要判断一个给定的数字是否是正的偶数。要做到这一点,必须检查两个条件。首先,我们必须确定该数字是正的。其次,我们必须检查该数字是否能够被2整除。程序清单1.5给出了我们可能为此而编写的代码的一个示例。

程序清单1.5 条件运算符1  // Remember to evaluate the RIGHT side of the = operator before 2  // assigning the result to the variable.3  int number = 1353; 4  boolean isPositive = number > 0; // evaluates to true5  boolean isEven = number % 2 == 0; // evaluates to false6  print(isPositive && isEven); // prints false7  print(isPositive || isEven); // prints true1.6 函数(在Java中称为“方法”更好)

让我们将目前为止所学到的所有内容组合起来,并且讨论编程的一个重要方面,即函数。

函数是一组规则。特别地,函数应该接受一个值并且输出一个相应的结果。以一个数学函数为例。

f(x)=3x +2

输入是任意的数值x,输出是3x +2的结果

例如,f(1)=3(1)+2=5

在Java中,我们可以定义一个非常类似的函数。如下的函数将接受一个float类型的输入,并且输出计算3x+2的结果。

程序清单1.6 Java函数1  float firstFunction (float x) {2    return 3*+ 2; 3  }

现在,我们来进一步看看如何编写一个Java函数(也叫作方法,具体原因我们在下一章中介绍)。要编写一个Java函数,首先声明返回值的类型。还要给函数一个名称,例如,firstFunction。在函数名称后面的圆括号中,列出所有必需的输入。

开始花括号和结束花括号,表明函数从哪里开始以及函数在哪里结束。如果这还不够形象化,这么做会有所帮助:想象一下,以花括号作为对角线形成一个矩形,将函数包围起来,如图1-3所示。这有助于你确定每个函数从哪里开始以及从哪里结束。图1-3 深入了解如何编写函数

程序清单1.7展示了如何在代码中使用函数。注意,我们假设在代码中某处定义了一个名为firstFunction的函数,并且其行为就像程序清单1.6所描述的那样。

程序清单1.7 使用函数1  // 1. declare a new float called input2  float input = 3f; 3  // 2. declare a new float called result and initialize it with the 4  // value returned from firstFunction(input);5  float result = firstFunction(input); 6  // 3. print the result7  print(result);

程序清单1.7的输出如下。

11.01.6.1 函数调用概览

程序清单1.7的第5行有着某种魔力。让我们具体讨论这里发生了什么。通常,我们总是必须先计算赋值操作符的右边。计算这个表达式,涉及调用程序清单1.6中所定义的函数。当调用firstFunction的时候,程序将会进入到程序清单1.6中的函数定义,传入参数input。在firstFunction中,接受input的值并且将其复制到一个名为x的临时的局域变量(local variable)中,并且该函数向调用者(caller)返回3x + 2的值(在第5行)。这个返回值可以存储为一个变量,这正是我们使用result所做的事情。然后程序继续进行,打印出该返回值。1.6.2 参数的更多讨论

函数可能接受多个输入,甚至是没有输入。在函数定义中,我们必须列出想要让函数接受的所有的输入,通过为每个想要的输入声明一个临时的局域变量来做到这一点。这些必需的输入,每一个都可以称为参数(parameter),其示例参见程序清单1.8。

程序清单1.8 函数声明1  // Requires three integer inputs.2  int getScore(int rawScore, int multiplier, int bonusScore) {3   return rawScore * multiplier + bonusScore;4  }56  // Requires no inputs.7  float getPi() {8   return 3.141592f;9  }

无论何时调用一个函数,你都必须传入在圆括号之间列出的所有的参数。例如,在程序清单1.8中,函数getScore声明了3个整型变量。你必须传入相应的值,否则的话,程序将无法运行。类似地,只有当你不传入任何参数的时候,函数getPi才会工作。

如前面所述,当我们把一个变量当作参数传递给函数的时候,只有其值(value)可以供函数使用(这个值是复制的)。这意味着,下面的程序清单1.9和程序清单1.10都将打印出相同的值15 700(根据程序清单1.8第3行所给出的公式)。

程序清单1.9 使用变量来调用getScore1  int num1 = 5000;2  int num2 = 3;3  int num3 = 700;4  print(getScore(num1, num2, num3));

程序清单1.10 使用直接编码的值来调用getScore1  print(getScore(5000, 3, 700));

在程序清单1.9中,我们使用变量调用了getScore函数。注意,由于我们通过值来传递参数,参数的变量名无关紧要。它们不一定必须要和函数定义中的局域变量的名称一致。程序清单1.10没有使用变量,而是传递了直接编码(hardcoded)的值。

当然,在我们编写的大多数程序中,像getScore这样的函数,其参数都会根据用户执行和使用的习惯而改变,因此,我们通常要避免直接编码字面值。1.6.3 函数小结

总的来说,要使用一个函数,我们必须做两件事情:首先,必须声明函数定义(如程序清单1.6所示);其次,必须调用该函数(如程序清单1.7所示)。如果想要让函数访问某些外部的值,我们会传递参数。函数返回的值拥有某种类型,这在声明函数的时候必须明确地声明,并且,可以使用相应的变量类型和赋值运算符来存储该值。

让我们再来看一个函数。

程序清单1.11 还活着吗?1  boolean isAlive (int characterHealth) {2    return characterHealth > 0;3  }

作为练习,请尝试回答如下的问题(答案在后面给出)。

Q1:  程序清单1.11中的函数的名称是什么?          。

Q2:  程序清单1.11中的函数返回一个什么类型的值?           。

Q3:  程序清单1.11中的函数接受几个输入?           。

Q4:  列出该函数的所有的输入的名称:           。

Q5:  isAlive(5)的结果是true还是false?           。

Q6  isAlive(-5) 的结果是true还是false?           。

Q7:  isAlive(0) 的结果是true还是false?           。

如果你感到迷惑,不要失望!需要花一些时间,才能够完全理解函数。如果你对函数还不是完全清楚,随着在本章中看到更多的示例,以及在第2章中开始编写自己的函数,你会对函数有更深的认识。

上述问题的答案是:Q1: isAlive,Q2: boolean,Q3: 一个,Q4: characterHealth,Q5: true,Q6: false,Q7: false。1.7 控制流程第1部分——if和else语句

我们现在把注意力转向控制流程(control flow ,也称为流程控制,flow control),这指的是代码行将要按照什么样的顺序执行。还记得代码执行的基本规则吧,它是说代码要从上到下地执行。在最简单的程序中,代码真的是按照线性方式从上向下执行的。然而,在任何有用的程序中,我们可能会看到,根据某些条件,会跳过一些代码行甚至重复执行一些代码行。让我们来看一些例子。1.7.1 if-else语句块

if-else语句块用来在代码中创建分支或多条路径。例如,我们可以检查如characterLevel > 10这样的条件来判断一个字符串内容,如图1-6所示。根据characterLevel的值,游戏可以执行不同的指令。你可以看到图1-4中有3条路径。图1-4 一个if-else语句块包含了一条if语句、一条else-if语句和一条else语句

我们可以创建比上面的例子具有更多或更少分支的if-else语句块。实际上,我们甚至可以把if语句嵌套在其他的if语句中,以允许“内嵌的”分支。1.7.2 if, else-if和else

无论何时,当你写下关键字if的时候,就开始了一个新的if-else语句块,如图1-6所示。你可以编写一个没有任何else-if或else语句的if语句块。这绝对没问题。

在你开始一个新的if-else语句块之后,每一个额外的else-if都表示一个新的分支。else语句是表示“我放弃”的分支,并且它将会为你处理所有的剩下的情况。

在给定的if-else语句块中,你只能选取一个分支。注意,在图1-6中,如果character Level是11,if和else-if语句中的条件似乎都满足。你可能会认为,这将会导致characterTitle变成“King”,随后很快又变成“Knight”。然而,不会发生这种情况,因为在if-else语句块中,你的代码只能选取一个分支,如图1-5所示。图1-5 if-else语句块包含一条if语句、一条else-if语句和一条else语句1.7.3 函数和if-else语句块

再回来看看函数。实际上,我们可以通过if-else语句块使得函数更为强大。if-else语句块还是像前面所介绍的那样工作,但是现在,我们将其包含到函数中,这意味着,我们要留意更多的花括号。看看下面的示例函数,看能否确定哪个开始花括号对应哪个结束花括号。第一个示例中已经为你标识清楚了。

示例1String theUltimateAnswer(boolean inBinary) {  String prefix = “The answer to life the universe and everything:”;  if (inBinary) {  return prefix + 101010;  } else {  return prefix + 42;  }}

示例2boolean isLessThanTen(int num) {  if (num < 10) {  return true;  } else {  return false;  }}

示例3boolean isEven(int num) {  if (num % 2 == 0) {  return true;  } else {  return false;  }}

示例4String desertSecurity(boolean hasGun, boolean hasRobots) {  if (hasGun) {  return "I've got a bad feeling about this.";  } else if (hasRobots) {  return "These are NOT the droids we are looking for."  } else {  return "Move along."  }}1.7.4 嵌套的if-else语句块

现在,我们必须掌握通过读取花括号来判断每个代码块从哪里开始以及从哪里结束的方法,让我们采取一些步骤。假设我们想要编写一个函数,它告诉我们一个人是否能够看一部限制级的电影(我们将根据资格返回true和false)。我们将设置如下所示的条件。● 如果一个人拥有伪造的ID,他可以看该电影(不管其年龄多大)。● 如果一个人有父母陪伴,他可以看该电影(不管其年龄多大)。● 如果一个人没有伪造的ID或者没有父母陪伴:● 如果这个人年龄达到了最小年龄,他可以看该电影。● 如果这个人年龄尚未达到最小年龄,他不可以看该电影。

因此,我们必须将if-else语句嵌套(nest)到一个更为通用的条件之中,才能够处理没有伪造的ID或没有父母陪伴的人的情况。让我们来看看代码,从3个主要分支开始。

程序清单1.12 我能看电影吗(不完整版本)1 boolean canWatch(int age, int minimumAge, boolean fakeID, boolean withParent) {2  if (fakeID) {3     return true; 4  } else if (withParent) {5     return true; 6  } else {7     // Nested if statements go here.8  }9 }

现在,在第3个分支中(else语句)添加两种特定的情况。

程序清单1.13 内部分支if (age >= minimumAge) {  return true; } else {  return false; }

现在,我们可以将程序清单1.12和程序清单1.13放到一起,组成程序清单1.14。

程序清单1.14 我能看电影吗(完整版)01 boolean canWatch(int age, int minimumAge, boolean fakeID, boolean withParent) {02    if (fakeID) { 03     return true; 04    } else if (withParent) {05     return true; 06    } else {07     if (age >= minimumAge) {08      return true; 09     } else {10      return false; 11     }  12    }13 }1.7.5 简化布尔语句

尽管程序清单1.14中的代码能够很好地运行,我们还是可以进行一些优化,如程序清单1.15所示。

程序清单1.15 我能看电影吗(简化版#1)01 boolean canWatch(int age, int minimumAge, boolean fakeID, boolean withParent) {02   if (fakeID || withParent) { // Two cases were combined into one if statement.03    return true; 04   } else {05    if (age >= minimumAge) {06       return true; 07    } else {08       return false; 09    }  10   }11 }

注意,在程序清单1.15中,我们在第2行使用“OR”运算符||将两种情况组合到一条if语句中。我们将所有的“true”的情况组合起来,以继续简化该函数,如程序清单1.16所示。

程序清单1.16 我能看电影吗(简化版#2)01 boolean canWatch(int age, int minimumAge, boolean fakeID, boolean withParent) {02   if (fakeID || withParent || age >= minimumAge) { 03    return true; 04   } else {05    return false; 06   }07 }

不管你是否相信,我们可以完全去除掉if-else语句块而只是返回(fakeID || withParent || age >= minimumAge)的值,从而更进一步简化,参见程序清单1.17。

程序清单1.17 我能看电影吗(简化版#3)1 boolean canWatch(int age, int minimumAge, boolean fakeID, boolean withParent) {2    return (fakeID || withParent || age >= minimumAge); 3 }

编写这样整洁的代码,就使得你(以及你的同事)能够更加高效地工作,而不需要使用诸如程序清单1.14那样复杂的逻辑。在整本书中,我们将学习到更多编写整洁代码的技巧。1.8 控制流程第2部分——while和for循环

在前面的小节中,我们介绍了使用if和else语句块来产生代码分支。现在,我们来介绍两种类型的循环:while循环和for循环。循环允许我们执行重复性的任务。循环特别重要,没有它们,游戏将无法运行。1.8.1 while循环

假设你想要编写一个函数打印出所有的正整数,直到达到给定的输入n。解决这个问题的策略(算法)如下。

1.  创建一个新的整型,将其值初始化为1。

2.  如果该整数小于或等于给定的输入n,打印其值。

3.  将该整数增加1。

4.  重复步骤2和步骤3。

我们已经学习了如何执行该算法的前3步。让我们写下已经知道的内容。

程序清单1.18 计数器(非完整版)1 ????? countToN(int n) {2  int counter = 1; // 1. Create a new integer, initialize it at 0.3  if (counter <= n) { // 2. If this integer is less than or equal to the input4  print(counter); // Print the value5  counter = counter + 1; // 3. Increment the integer by 16  }7 }

我们必须在代码中解决两个问题。首先,函数应该返回什么类型(通过程序清单1.18的第1行中的问号来表示)?它应该是一个int类型吗?实际上,在我们的例子中,甚至没有一条return语句;该函数并不会产生任何可供我们使用的结果。当没有返回任何值的时候,就像前面的函数那样,我们说返回类型是void。

其次,如何让这段代码重复步骤2和步骤3?这实际上很简单。我们使用一个while循环,只要某个条件能够满足,就会让这个循环保持运行。在我们的例子中,所需要做的只是用关键字“while”替代关键字“if”。完整的函数如程序清单1.19所示(修改的代码突出显示)。

程序清单1.19 计数器(完整版)1 void countToN(int n) {2  int counter = 1; // 1. Create a new integer, initialize it at 0.3  while (counter <= n) { // 2. If this integer is less than or equal to the input4  print(counter); // Print the value5  counter = counter + 1; // 3. Increment the integer by 16  }7 }

让我们一行一行地来看看该函数(参见程序清单1.19)。

第1行声明了函数的返回类型(void)、函数名称(countToN)和输入(n)。

第2行声明了一个名为counter的新的整型,并且将其值初始化为1。

第3行开始一个while循环,只要条件(counter <= n)满足,它就会运行。

第4行打印出counter变量的当前值。

第5行将counter增加1。

当到达第5行的时候(第6行的花括号表示循环结束),代码将再次执行第3行。这里会重复,直到counter变得比n大,此时,会跳出while循环。要看看这是如何工作的,让我们在代码中的任意地方调用该函数。print(“Initiate counting!”); countToN(5); // Call our countToN() function with the argument of 5.print(“Counting finished!”);

相应的输出如下所示。

Initiate counting!

1

2

3

4

5

Counting finished!

这就是while循环。只是编写一条if语句,并且将关键字“while”放到那里,代码就可以重复一项任务了。

关键知识点while循环

只要给定的条件计算为true,while循环就将继续迭代。如果

我们有一个条件总是为true,例如,while (5 > 3) …,while

循环将不会结束。这就是一个无限循环。1.8.2 for循环

程序清单1.19中的计数逻辑的使用如此频繁,以至于人们为此专门设计了一个循环。它叫作for循环。for循环的语法考虑到了各种问题的较为整洁的解决方案,使得我们能够节省代码行。如图1-6所示。图1-6 for循环有3个主要组成部分:初始化、终止条件和自增

for循环需要做3件事情。必须初始化计数器变量,设置终止条件,然后定义一个自增表达式。该循环将持续迭代(重复),直到终止条件计算为假(在上面的示例中,就是直到i大于6)。每次迭代之后,i都会按照自增表达式中给出的规则来递增。

在程序清单1.19中使用一个for循环来计数重新编写代码的话,可以得到程序清单1.20。

程序清单1.20 计数器(for循环版)1 void countToN(int n) {2  for (int i=1; i<=n; i++) {3   print(i); 4  }5 }

一旦掌握了语法,编写for循环比编写while循环要快很多。for循环很快将会变为我们的无价之宝,并用来干从移动精灵到渲染动画的每一件事情。1.9 训练到此结束

如果你已经学到了这里,恭喜你!你已经完成了进入美丽的、复杂的并且偶尔令人沮丧的编程世界的第一步。但是,在编写一些Java代码之前,你还不能自称为一名Java程序员。因此,快打开你的计算机并且开始学习第2章,在那里,我们要构建一些Java程序了。第2章 Java基础知识

第1章内容完全是成为Java程序员的准备工作。在本章中,你将编写自己的第一个Java程序(包括一款简单的游戏),并学习如何把游戏的角色、加血(power-up)以及其他实体表示为Java对象。2.1 面向对象编程

Java是一种面向对象编程语言。在面向对象的范型中,我们以对象的形式来表示数据,以帮助我们形成概念并沟通思路。例如,在构建视频共享Web应用程序的时候,我们可能要创建一个User对象来表示每个用户账户(及其所有的数据,例如,用户名、密码、上传的视频等)。使用一个Video对象来表示每一个上传的视频,其中的很多视频都组织到一个Playlist对象中。

考虑到整洁、健壮的代码更容易阅读和理解,面向对象编程允许我们将相关的数据组织到一起。为了了解这一思路,我们来编写自己的第一个Java程序。

关键知识点访问本书的配套站点

本书中的所有代码示例、勘误文档,以及额外的补充内容,

都可以通过本书的配套站点jamescho7.com来获取。

Java的安装可能颇有些技巧。如果在本章的任何地方,你有

不明白之处,请访问配套站点,那里有视频指南可以帮助你

开始安装Java。2.2 设置开发机器

在开始编写简单点的Java程序和构建令人兴奋的游戏之前,我们必须在自己的机器上安装一些软件。然而,这个过程有点枯燥且颇费时间,但是,为了让第一个程序开始运行,这些代价都是值得的。2.2.1 安装Eclipse

我们将利用一个集成开发环境(Integrated Development Environment,IDE)来编写Java/Android应用程序。IDE是一种工具的名称,它能够帮助我们轻松地编写、构建和运行程序。

我们将要使用的IDE叫作Eclipse,这是一款强大的开源软件。然而,我们将下载Google改进版的Eclipse,即Android Developer Tools (ADT) Bundle,而不是安装单纯的Eclipse。我们稍后再介绍所有这些术语的含义。

要构建Android应用程序,必须先安装Android SDK(软件开发工具包)。通常,你需要单独下载它(和下载Eclipse的过程分开),并且用一个插件(为Eclipse提供额外功能的一个插件)来集成它;然而,Google允许你下载包含了Eclipse和Android SDK的一个包(即ADT包),从而使得这个过程更加容易。

按照如下的步骤来准备用于Java/Android开发的机器。

① 下载ADT包,请访问如下的站点。

http://developer.android.com/sdk/index.html

② 应该会看到图2-1所示的页面。图2-1 Android SDK下载页面

一旦看到了这个页面,点击“Download Eclipse ADT”按钮。该站点将会自动检测你的操作系统,以便你能够下载正确的版本。

③ 你将会看到图2-2所示的界面。

根据你的操作系统的类型,下载32位或者64位的版本。不确定应该选择哪个版本?可以通过如下方式搞清楚。图2-2 32位还是64位在Windows上查看操作系统类型

在Windows上,鼠标右键点击“我的电脑”(My Computer)并且点击“属性” (Properties)。或者,可以导航到“控制面板”(Control Panel)并查找“系统”(System)。将会看到图2-3所示的窗口。图2-3 Windows系统信息

如果你的机器是32位的,将会看到32-bit Operating System或x86-based processor。否则,你应该会看到64-bit Operating System。记住这个版本,并且下载相应的ADT。在Mac OS X上查看操作系统类型

要查看使用的是32位还是64位的操作系统,必须检查处理器的类型。如下所示的页面告诉你如何判断以及解释这些信息。

http://support.apple.com/kb/HT3696

记住操作系统的版本,并且下载相应的ADT版本。

④下载的是一个很大的.zip文件(在编写本书的时候,文件大概有350MB)。直接将这个文件解压缩到一个便于使用的目录中。不必安装它。

解压之后,应该会看到两个文件夹和一个名为SDK Manager的文件。现在,你只需要关心Eclipse文件夹,因为在本章后面我们才会用到Android。2.2.2 安装Java开发包

Eclipse是用Java构建的。这意味着,你需要在自己的机器上安装一个Java运行时环境(Java Runtime Environment,JRE),才能运行Eclipse。由于我们将运行Java程序并且会开发Java程序,我们将安装JDK(Java Development Kit),其中包含了一个JRE和各种开发工具。

要安装JDK,导航到如下所示的页面。

http://www.oracle.com/technetwork/java/javase/downloads/

index.html

在编写本书的时候,JDK的最新版本是JDK 8。考虑到兼容性,我们将使用JDK 7,以便在Android开发中不会遇到问题。

向下滚动页面,直到看到Java SE 7uNN,其中,NN是Java 7最近的两位更新编号。如图2-4所示,当前的版本是Java SE 7u55。根

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载