Java8 游戏开发入门手册(一)

协议:CC BY-NC-SA 4.0

一、设置 Java 8 游戏开发环境

欢迎阅读《Java 8 游戏开发入门》一书!让我们从创建本书使用的坚实的开发软件基础开始。这个基础的核心将是 Java SDK(软件开发工具包)8,也称为 JDK (Java 开发工具包)8。我还将为您设置 NetBeans IDE 8.0(集成开发环境),这将使编写 Java 8 游戏变得容易得多。之后,我将向您介绍最新的开源新媒体内容创作软件包,用于数字插图(Inkscape)、数字成像(GIMP [GNU 图像处理器])、数字视频(EditShare Lightworks)、数字音频(Audacity)以及 3D 建模和动画(Blender)。在本章的最后,我还会推荐一些其他的专业级软件包,你应该考虑把它们添加到你将在本章的课程中创建的专业游戏开发工作站中。

为了从所有这些免费的专业级软件中获得最佳效果,您将需要一个现代化的 64 位工作站,至少具有 4GB 的系统内存(6GB 或 8GB 更好)和一个多核处理器(中央处理器[CPU]),如 AMD FX-6300(六核)、AMD FX-8350(八核)或英特尔 i7(四核)。诸如此类的工作站已经成为商品,可以在沃尔玛或 Pricewatch.com 以实惠的价格购买。

在本章中,您要做的第一件事是确保您已经删除了任何过时的 Java 版本,如 Java 7 或 Java 6,或者任何过时的 NetBeans 版本,如 NetBeans 7 或 NetBeans 6。这包括从您的工作站卸载(移除或完全删除)这些较旧的开发软件版本。

您将使用 Windows 程序管理实用程序程序和功能来完成此操作,这些程序和功能可以在 Windows 操作系统管理实用程序的 Windows 操作系统(OS)控制面板套件中找到。在 Linux 和 Mac 平台上也有类似的工具,如果你碰巧使用了这些不常用的操作系统。因为大多数开发人员使用 Windows 7、8 或 9,所以对于本书中的示例,您将使用 Windows 64 位平台。

接下来,我将向您展示在互联网上的确切位置可以获得这些软件包,所以请准备好启动您的快速互联网连接,以便您可以下载近 1g 的全新游戏内容制作软件!下载所有这些软件的最新版本后,您将安装编程和内容开发包,并对它们进行配置以用于本书。

执行这些软件安装的顺序很重要,因为 Java JDK 8 和 Java 8 运行时环境(JRE)构成了 NetBeans IDE 8.0 的基础。这是因为 NetBeans IDE 8.0 最初是使用 Java 编程语言编写的,所以您会看到使用这种语言的软件是多么的专业。因此,Java 8 软件将是您安装的第一个软件。

安装 Java 8 后,您将安装 NetBeans 8.0,以便在 Java 编程语言之上拥有一个图形用户界面(GUI),这将使 Java 软件开发工作过程更容易。安装这两个主要的软件开发工具后,您将获得大量新的媒体内容创建软件包,可以与 Java 8 和 NetBeans 8.0 结合使用来创建 2D 和 3D 游戏。

为 Java 8 游戏开发准备工作站

假设你已经有一个专业级的工作站用于新媒体内容开发和游戏开发,你需要删除所有过时的 JDK 和 ide,并确保你有最新的 V8(不是饮料,傻瓜!)Java 和 NetBeans 软件已安装在您的系统上,随时可以使用。如果你是新手,没有适合游戏的工作站,去沃尔玛或 Pricewatch.com,购买一台经济实惠的多核(使用 4 核、6 核或 8 核)64 位计算机,运行 Windows 8.1(或 9.0,如果有),至少有 4GB、6GB 或 8GB 的 DDR3 (1333 或 1600 内存访问速度)系统内存和 750GB,甚至 1TB 的硬盘驱动器。

删除旧软件的方法是通过 Windows 控制面板及其一组实用程序图标,其中一个是程序和功能图标(Windows 7 和 8),如图 1-1 所示。请注意,在 Windows 的早期版本中,该实用程序图标的标签可能会有所不同,可能是“添加或删除程序”之类的标签。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-1。

Use the Programs and Features utility icon to uninstall or change programs on your computer workstation

单击“程序和功能”链接,或者在以前版本的 Windows 中双击图标,以启动该实用程序。然后,向下滚动查看您的工作站上是否安装了任何旧版本的 Java 开发工具(Java 5、Java 6 或 Java 7)。请注意,如果您有一个全新的工作站,您应该会发现您的系统上没有预装的 Java 或 NetBeans 版本。如果您确实找到了它们,请归还系统,因为它以前可能已经被使用过了!

如图 1-2 所示,在我的 Windows 7 HTML5 开发工作站上,我安装了一个旧版本的 Java,Java 7(2013 年 11 月 29 日),占用了 344MB 的空间。要删除某个软件,请通过单击选择它(它将变为浅蓝色),然后单击图顶部显示的卸载按钮。我留下了屏幕截图中显示的工具提示,“卸载该程序”,这样您就可以看到,如果您将鼠标悬停在程序和功能实用程序中的任何内容上,它会告诉您该功能的用途。

单击卸载按钮后,该实用程序将删除旧版本的 Java。如果您想要保留旧的 Java 项目文件,请确保备份您的 Java 项目文件文件夹(如果您还没有这样做的话)。确保定期备份工作站的硬盘驱动器,以免丢失任何工作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-2。

Select any version of Java older than the current version (Java 8), and click the Uninstall button at the top

还要确保卸载所有版本的 Java 在我的例子中,有 64 位 Java 7 update 45 和 Java SDK 7u45,用于运行或执行 ide,如 NetBeans(或 Eclipse),它们是用 Java 编程语言编写的。

接下来,您需要确定您的工作站上是否有任何旧版本的 NetBeans IDE。在我的例子中,如图 1-3 所示,我的 64 位 Windows 7 工作站上确实安装了 NetBeans 7 IDE。我选择了要删除的,然后单击了卸载/更改按钮,如左边所示,这将弹出一个自定义卸载摘要对话框,如右边所示。

制造商(在本例中是 NetBeans 开发团队)可以为他们的产品创建自定义的卸载摘要对话框,以便在卸载过程中使用,正如您在此处看到的。此对话框允许您选择是否要卸载 GlassFish Server 4 和 NetBeans UserDir 配置文件夹。因为您正在安装 NetBeans 和 GlassFish 的新版本,所以请选中这两个复选框,然后单击“卸载”按钮。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-3。

Find and select any version of NetBeans that is older than version 8.0; also, uninstall old GlassFish versions

下载 Java JDK 8 和 NetBeans 8.0

既然已经从您的工作站上删除了 Java 和 NetBeans 的过时版本,那么您将需要访问 Internet,分别访问 Oracle 和 NetBeans 网站,以获得最新的开发 SDK 和 ide。在写这本书的时候,我将向你展示如何使用谷歌的搜索引擎(我使用这种方法是为了防止下载链接或 URL 发生变化)以及演示当前的直接下载 URL。

让我们先来看看 Java 8,因为它是你阅读本书时将要做的所有事情的基础。谷歌搜索 Java JDK 8 会给你甲骨文 Java 下载页面的搜索结果,该页面位于甲骨文技术网部分,如图 1-4 截图顶部所示。此页面的 URL 当前为 www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 。值得注意的是,这个网址可能会在未来的任何时候改变,你可以随时使用谷歌搜索找到最新的。在下载 64 位 Windows 7/8 的 170MB SDK 安装程序文件之前,您需要单击 Java 8 下载表左上角显示的接受许可协议选项旁边的单选按钮。一旦您接受许可协议,这 11 个特定于操作系统的链接将被激活使用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-4。

Google the term “Java JDK 8,” open the JDK 8 Downloads page, and select Accept License Agreement

确保下载的 Java JDK 8 软件符合您的操作系统和位级别(x86 表示 32 位级别的操作系统)。大多数现代工作站使用 64 位 Linux、Mac、Solaris (Oracle)、Windows 7 或 Windows 8 操作系统。这将用操作系统名称后的 x64 描述来指定。

要找出操作系统的位级别,在 Windows 7 上,打开“开始”菜单,右键单击计算机条目,然后选择上下文菜单底部的“属性”选项。在 Windows 8 上,单击开始(如果您处于 Windows 7 桌面模式,则是桌面左下角的窗口窗格图标),然后单击左下角的向下箭头图标,再单击电脑设置紫色齿轮图标,最后单击屏幕左下角的电脑信息条目。在这两个用例中,都应该有一个文本条目,说明系统类型和 32 位操作系统或 64 位操作系统。

现在您已经下载了 Java JDK 8 安装程序,接下来您需要做的是下载 NetBeans IDE 8.0。在谷歌上搜索 NetBeans 8.0,如图 1-5 顶部所示,点击下载搜索结果选项,将会进入 NetBeans IDE 8.0.1 下载页面(目前为 https://netbeans.org/downloads )。如果您想像我一样在浏览器中保持两个选项卡都打开,那么右键单击下载链接,并选择在新选项卡中打开链接选项。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-5。

Google the term “NetBeans 8.0,” open the NetBeans IDE 8.0.1 Download page, and download all versions

进入 NetBeans IDE 8.0 下载页面后,从页面右上角的下拉菜单中选择您正在使用的语言和平台(OS)。我选了英语和 Windows。现在,您可以单击页面底部三个下载按钮中的一个来下载支持 JavaFX 8 新媒体(因此将支持游戏开发)编程语言(应用编程接口[API])的 NetBeans IDE 8.0。当我详细讲述 Java 编程语言时,你会在第三章中了解到更多关于 API 的知识。

如果你只打算开发面向个人的 Java SE(标准版)和 JavaFX 应用(游戏),那么点击第一个按钮。如果你要开发 Java EE(企业版)和 JavaFX 应用(游戏)用于企业(商务),那么点击第二个按钮。如果您打算同时开发 JavaFX 和 HTML5 应用(游戏),这也是我为自己的业务所做的,那么您可以单击第五个下载按钮,下载 NetBeans IDE 8.0 的“全部”版本。该版本将允许您使用 NetBeans 支持的所有编程语言进行开发!

因为 NetBeans IDE 是免费的,并且您的工作站硬盘驱动器可以处理大量数据,所以我建议您安装这个 204MB All 版本的 IDE,以防您需要 NetBeans IDE 8.0 作为软件开发人员能够为您提供的任何其他功能(Java EE、Java ME、PHP、HTML5、Groovy、GlassFish、Tomcat、C++)。如果您要安装客户端或 Java SE IDE 版本,这需要额外的 120MB 磁盘空间,但是如果您要安装服务器端或 Java EE IDE 版本,这需要不到 20MB 的额外磁盘空间。

单击下载按钮后,软件下载将开始。完成后,您就可以安装 Java 8 和 NetBeans IDE 8.0 了。最后,为了完成全面的 Java 8 游戏开发工作站的设置,您将获得一些辅助的新媒体内容工具。当你通读这本书时,你将能够使用工作站来创建可交付的 epic Java 8 游戏!越来越令人兴奋了!

安装 Java 8 软件开发环境

NetBeans IDE 8.0 需要安装 Java 才能运行,因此您需要先安装 JDK 和 JRE。因为你想用最新的、功能最丰富的 Java 版本开发游戏,所以你要安装 2014 年发布的 Java 8。安装最新版本的软件可以确保您拥有最新的功能和最少的错误。确保经常检查您是否使用了所有软件包的最新版本;毕竟,这些都是开源的,可以免费下载、升级和使用!

第一步是找到您将安装程序文件下载到系统中的位置。默认值应设置为 Windows 中的下载文件夹。我把我的下载到一个C:/Clients/Java8文件夹,如图 1-6 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-6。

Find the JDK 8 install file on your hard disk drive, right-click it, and select Run as administrator

该文件将使用格式 jdk-version-platform-bitlevel 命名,因此要找到最新的版本(在本例中,它是jdk-8u25-windows-x64)。右键单击它,并选择 Run as administrator 选项,这样安装程序就拥有了创建文件夹、向其中传输文件等所需的所有操作系统“权限”。

启动安装程序后,您会看到欢迎对话框,如图 1-7 (左)所示。点击下一步按钮进入选择要安装的功能对话框,如图 1-7 (右图)所示,并接受默认值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-7。

Click Next in the Welcome dialog to advance to the Select Features to Install dialog, and then click the Next button

如你所见,安装程序会将 180MB 的软件安装到你工作站上的C:\ProgramFiles\Java\jdk1.8.0_25文件夹中。单击下一步按钮开始安装过程,安装过程将提取安装文件,然后使用动画进度条将它们复制到您的系统上,如图 1-8 (左图)所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-8。

Java 8 installation will extract and copy install files (left) and then suggest the installation directory (right)

在你的系统上安装了 Java SDK 之后,你会看到 JRE 安装对话框,如图 1-8 (右图)所示。请确保您接受此 JRE 的默认安装位置;它应该安装在\Java\jre8文件夹中。最好允许 Oracle (Java SDK)将软件放在行业标准的文件夹位置,因为您将使用的使用此 JRE 的其他软件包(如 NetBeans IDE 8.0)将首先在那里查找它。单击“下一步”按钮安装 JRE。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-9。

During installation a progress bar shows you what is installing (left) and then gives you a completed dialog (right)

安装过程中会显示一个进度条,如图 1-9 (左图)所示。完成后会显示安装成功对话框,如图 1-9 (右图)所示。如果您想要访问教程、API 文档、开发人员指南、版本发布说明等等,您可以单击“后续步骤”按钮。

安装 NetBeans IDE 8.0

现在,你已经准备好安装 NetBeans 了,所以找到你的netbeans-8.0-windows文件(见图 1-6 )。右键单击它,并选择“以管理员身份运行”选项来启动安装程序。一旦启动,你会看到如图 1-10 所示的对话框,它给你一个定制按钮,你可以用它来定制安装。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-10。

The Welcome to the NetBeans IDE 8.0 Installer dialog

单击下一步按钮开始默认(完全)安装,您将看到 NetBeans IDE 8.0 许可协议对话框,如图 1-11 (左图)所示。选中“我接受许可协议中的条款”复选框,并单击“下一步”按钮前进到“JUnit 许可协议”对话框,如图 1-11 (右图)所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-11。

Accept the terms of the license agreement, click the Next button (left), and then do the same for JUnit (right)

在 JUnit 许可协议对话框中,如图 1-11 (右图)所示,单击我接受许可协议声明中的条款旁边的单选按钮,然后单击下一步按钮继续安装。如图 1-12 所示,接下来的两个安装程序对话框将允许您指定 NetBeans 8.0 和 GlassFish 4.0 在系统上的安装位置。我建议也接受这两个对话框中的默认安装位置。您会注意到,NetBeans 安装程序也在默认位置找到了您的 Java 安装。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-12。

Accept the default installation directory suggestions for NetBeans IDE (left) and GlassFish 4.0 (right)

一旦您接受了这些默认的安装位置,并单击 Next 按钮在这些对话框中前进,您将得到一个摘要对话框,如图 1-13 (左)所示。此对话框包含一个“安装”按钮,该按钮将触发您在前面五个 NetBeans IDE 8.0 安装对话框中设置的安装。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-13。

Select the Check for Updates check box, and click the Install button (left) and the Finish button (right)

在安装过程中,您会看到安装对话框及其进度条,如图 1-14 所示,它会告诉您安装已完成的确切百分比,以及当前正在您的工作站上提取和安装哪些 IDE 文件。

当安装过程完成时,您将看到设置完成对话框,如图 1-13 (右图)所示。现在,您可以在您的工作站上开发 Java 8 和 JavaFX 应用(游戏)了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-14。

The Installation progress dialog, showing the percentage of install complete

接下来,让我们下载五个最流行的免费开源新媒体内容开发软件包,这样您就拥有了 Java 8 游戏开发业务所需的所有工具!

之后,您将会看到我在工作站上使用的其他一些令人印象深刻的开源软件。这样,如果您愿意,甚至在完成本章之前,您就可以组装出终极软件开发工作站,仅用硬件(和操作系统)的成本就可以创建一个非常有价值的内容制作工作站!

安装新媒体内容制作软件

JavaFX 支持许多新媒体元素或资产的“类型”, Java FX 是 Java 8(和 Java 7)中的新媒体引擎,也是 Java 8 游戏开发的基础。新媒体的主要类型包括数字插图、数字图像、数字音频、数字视频和 3D,您将在本章的剩余部分安装领先的开源软件。

下载并安装 Inkscape

因为 JavaFX 支持数字插图软件包(如 Adobe Illustrator 和 FreeHand)中常用的 2D(或矢量)技术,所以您将下载并安装流行的开源数字插图软件包 Inkscape。

Inkscape 适用于 Linux、Windows 和 Mac 操作系统,就像你在本章中安装的所有软件包一样,所以你可以使用任何你喜欢的平台来开发游戏!

在网上找 Inkscape 软件包,去 Google 搜索,输入 Inkscape,如图 1-15 ,左上方。单击下载链接(或右键单击,并在单独的选项卡中打开),然后单击代表您正在使用的操作系统的图标。企鹅代表 Linux(最左边的图标),窗口代表 Windows(中间的图标),风格化的苹果代表 Mac(最右边的图标)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-15。

Google the term “InkScape,” go to the Inkscape Download page, and click the icon that matches your OS

如果您想使用 64 位 Windows 版本的 Inkscape,请向下滚动,查看这三个图标下面的文本链接,以访问特定的操作系统下载。下载完软件后,右键单击它并以管理员身份运行,然后在您的工作站上安装软件。如果您有以前版本的 Inkscape,安装程序会将其升级到最新版本。您不需要使用本章前面使用的程序和功能实用程序来卸载 SDK 和 ide,它们不会像新媒体制作软件包那样升级以前的版本。

安装软件后,在任务栏上创建一个快速启动图标,这样只需单击鼠标即可启动 Inkscape。接下来,您将安装一个流行的数字图像软件包 GIMP,它允许您以 JavaFX 支持的 JPEG、PNG 或 GIF 数字图像文件格式为您的游戏创建“光栅”或基于像素(位图)的艺术作品。光栅图像不同于矢量,或形状,插图,所以你需要 GIMP。

下载和安装 GIMP

JavaFX 还支持使用光栅图像技术的 2D 图像,该技术将图像表示为像素阵列,常用于数字图像合成软件包,如 Adobe Photoshop 和 Corel Painter。在本节中,您将下载并安装流行的开源数字图像编辑和合成软件包 GIMP。该软件适用于 Linux、Windows、Solaris、FreeBSD 和 Mac 操作系统。

在网上找 GIMP 软件,去 Google 搜索,输入 GIMP,如图 1-16 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-16。

Google the term “GIMP,” go to the GIMP Downloads page, and click the Download GIMP link

单击下载链接(或右键单击,并在单独的选项卡中打开它),然后单击下载 GIMP 2.8.14(或代表您正在使用的操作系统的最新版本)。下载页面将自动检测您正在使用的操作系统,并为您提供正确的操作系统版本;对我来说,是 Windows。下载并安装最新版本的 GIMP,然后为您的工作站任务栏创建一个快速启动图标,就像您为 Inkscape 所做的那样。接下来,您将安装一个强大的数字音频编辑和音频效果软件包,名为 Audacity。

下载并安装 Audacity

JavaFX 支持使用数字音频技术的数字音频序列。数字音频通过采集数字音频样本来表示模拟音频。数字音频内容通常使用数字音频合成和序列器软件包创建,如 Propellerhead Reason 和 Cakewalk Sonar。在本节中,您将下载并安装流行的开源数字音频编辑和优化软件包 Audacity。Audacity 可用于 Linux、Windows 和 Mac 操作系统,因此您可以使用任何您喜欢的操作系统平台来为基于 Java 8 和 JavaFX 的游戏创建和优化数字音频。

要在网上找到 Audacity 软件包,使用谷歌搜索引擎,输入 Audacity,如图 1-17 左上角所示。单击下载链接(或者右键单击,并在单独的选项卡中打开),然后单击 Audacity for Windows(或者代表您正在使用的操作系统的版本)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-17。

Google the term “Audacity,” go to the Audacity Download page, and click a link matching your OS

下载并安装 Audacity 的最新版本(目前是 2.0.6),然后为您的工作站任务栏创建一个快速启动图标,就像您为 Inkscape 和 GIMP 所做的那样。接下来,您将安装一个强大的数字视频编辑和特效软件包,名为 EditShare Lightworks。

下载并安装 EditShare Lightworks

JavaFX 还支持数字视频,它使用基于光栅像素的运动视频技术。光栅将视频表示为一系列帧,每个帧包含一个基于像素阵列的数字图像。数字视频资产通常是使用数字视频编辑和特效软件包创建的,如 Adobe After Effects 和 Sony Vegas。在本节中,您将下载并安装名为 Lightworks 的开源数字视频编辑软件。

EditShare 的 Lightworks 曾经是一个付费软件包,直到它被开源。您必须在 Lightworks 网站上注册才能下载和使用该软件。该软件包适用于 Linux、Windows 和 Mac 操作系统。要在网上找到 Lightworks,进入谷歌搜索,输入 Lightworks,如图 1-18 所示,在左上方。单击下载链接(或右键单击,并在单独的选项卡中打开),然后单击相应的下载按钮和代表您正在使用的操作系统的选项卡。下载页面将自动检测您正在使用的操作系统,并选择正确的操作系统选项卡;在我的情况下,Windows。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-18。

Google the term “Lightworks,” go to the Lightworks Downloads page, and click the tab that matches your OS

如果您还没有注册,请在 Lightworks 网站上注册。一旦获得批准,您就可以下载并安装最新版本的 Lightworks。安装软件,并为您的任务栏创建一个快速启动图标,就像您对其他软件所做的那样。接下来,您将安装一个名为 Blender 的 3D 建模和动画包。

下载和安装 Blender

JavaFX 最近开始支持在 JavaFX 环境之外创建的 3D 新媒体资产,这意味着您将能够使用第三方软件包创建 3D 模型、纹理和动画,例如 Autodesk 3D Studio Max 或 Maya 和 NewTek Lightwave 3D。在本节中,您将下载并安装流行的开源三维建模和动画软件包 Blender。Blender 适用于 Linux、Windows 和 Mac 操作系统,因此您可以使用任何您喜欢的操作系统平台来创建和优化 3D 模型、3D 纹理映射和 3D 动画,以便在 Java 8 和 JavaFX 游戏中使用。

要在网上找到 Blender 软件,使用谷歌搜索引擎,输入 Blender,如图 1-19 所示。点击正确的下载链接下载并安装 Blender,然后创建快速启动图标。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-19。

Google the term “Blender,” go to the Blender Download page, and click the tab for your OS

其他感兴趣的开放源码软件包

我在我的新媒体内容制作业务中使用了许多其他的专业级开源软件包,我想我应该让你知道一下,以防你没有听说过它们。这将为您到目前为止构建的新媒体制作工作站增加更多功能和多样性。值得注意的是,您已经为自己节省了数千美元,否则在进行所有这些大量下载和安装的过程中,您将花费在类似的付费内容制作软件包上。我想你可能会说我的座右铭是,“第一次就做对,并确保一直做下去”,所以让我告诉你一些其他免费的,甚至一些更实惠的新媒体内容制作软件包,我已经安装在我自己的内容制作工作站上。

除了过去售价高达六位数的 EditShare Lightworks 软件包之外,开源软件的最佳价值之一是一个商业生产力软件套件,Oracle 在收购 Sun Microsystems 后将其开源。甲骨文将其 OpenOffice 软件套件转移到流行的 Apache 开源项目中。OpenOffice 4.1 是一个完整的办公效率软件套件,包含六个成熟的商务效率软件包!因为您的内容制作代理实际上是一个成熟的企业,您可能应该了解这个软件,因为它是一个非常可靠的开源软件产品。可以在 www.openoffice.org 找到;这个流行的商业软件包已经被像你这样精明的专业人士下载了超过一亿次,所以正如他们所说的,这不是一个玩笑!

Audacity 数字音频编辑软件的一个很好的补充是 Rosegarden MIDI sequencing 和 music composition and scoring 软件,它可以用于音乐创作和打印音乐出版的结果乐谱。玫瑰园,目前在 14.02 版本,正在从 Linux 移植到 Windows,可以通过谷歌搜索或在 www.rosegardenmusic.com 找到。

另一个令人印象深刻的音频、MIDI 和声音设计软件包是 Qtractor 如果您运行的是 Linux 操作系统,请务必通过谷歌搜索或前往 https://Qtractor.SourceForge.net 下载并安装这个专业级数字音频合成软件包。

对于 3D 角色建模和动画,有机会一定要去看看 DAZ Studio 的 3D 软件包( www.daz3d.com )。DAZ Studio Pro 目前的版本是 4.6,没错,是免费的!你必须登录并注册,就像你在 EditShare Lightworks 上做的那样,但这只是小小的代价!这个网站上还有一个免费的 3D 建模软件包,名为 Hexagon 2.5,还有一个不到 20 美元的流行地形生成软件包,名为 Bryce 7.1 Pro。DAZ Studio 网站上最贵的软件是 Carrara (150 美元)和 Carrara Pro (285 美元)。DAZ 工作室的大部分收入来自销售各种类型的角色模型,所以看看吧,因为它是 3D 内容(虚拟)世界中不可忽视的力量!

另一个令人印象深刻(基本版免费)的世界级软件包是英国 Planetside Software 公司的 Terragen 3.2。你可以从 https://planetside.co.uk 下载基础版,也可以加入它的论坛。我已经在我的几本 Android 应用开发书中使用过这个软件,所以我知道它对多媒体应用和游戏很有效。它也被专业电影制作人使用,因为它的质量水平是原始的。

Caligari TrueSpace 7.61 也是非常优秀的免费 3D 建模和动画软件。节目,也就是“自由而活着!”根据 Caligari 的网站( https://Caligari.us ),你仍然可以从那里下载它,当它最初由 Caligari 公司的创始人罗曼·奥曼迪(后来被微软收购)开发时,它曾花费近 1000 美元。一个专业级的 3D 建模和动画软件包,这个程序在全盛时期拥有数百万用户。这是一个非常酷的软件,有一个有趣的用户界面,所以一定要抓住它!

另一个你应该看看的 3D 渲染软件是 POV-Ray(视觉光线跟踪器的持久性),它可以与任何 3D 建模和动画软件包配合使用,使用高级光线跟踪渲染算法来生成令人印象深刻的 3D 场景。POV-Ray 网站上的最新版本(www.povray.org)是 3.7,与 64 位和多核(多线程)兼容,可以免费下载!

Bishop3D 是一个很酷的 3D 建模软件包,专门设计用于 POV-Ray。该软件可用于创建自定义 3D 对象,然后可将其导入 POV-Ray(然后导入 JavaFX)以在您的游戏中使用。最新的版本是 Windows 7 版的 1.0.5.2,下载量为 8MB。该软件可以在 www.bishop3d.com 找到,目前可以免费下载!

另一个值得研究的免费 3D 建模软件是 Wings 3D。这个软件可以用来创建自定义的 3D 对象,然后可以导入到 JavaFX 中,在您的游戏中使用。最新版本是 64 位、16MB 的下载版本,是 1.5.3,于 2014 年 4 月发布,适用于 Windows 7、Mac OS X 和 Ubuntu Linux。该软件可以在 www.wings3d.com 找到,目前可以免费下载!

对于 UI 设计原型,Evolus 的免费软件包 Pencil 2.0.6 允许您在用 Java、Android 或 HTML5 创建 UI 设计之前,轻松地进行原型设计。该软件位于 http://pencil.evolus.vn ,可用于 Linux、Windows 和 Mac OSs。

接下来,您将看到我是如何在任务栏上组织一些基本的操作系统实用程序和开源软件的。

在任务栏区域组织快速启动图标

对于某些操作系统实用程序,如计算器、文本编辑器(记事本)和文件管理器(资源管理器),我会在任务栏上创建快速启动图标,因为这些实用程序在编程和新媒体内容开发工作流程中经常使用。我还将各种新媒体开发、编程和办公效率应用作为快速启动图标。图 1-20 显示了一打这样的程序,包括你刚刚安装的所有程序,按照你安装的顺序,还有一些其他的程序,比如 OpenOffice 4.1,DAZ Studio Pro 4.6 和 Bryce 7.1 Pro。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-20。

Make taskbar Quick Launch icons for key system utilities, NetBeans 8.0, and new media production software

有几种方法可以创建这些快速启动图标:您可以将程序从“开始”菜单拖放到任务栏上,或者右键单击桌面上或资源管理器文件管理器中的图标,然后从上下文菜单中选择“将该程序固定到任务栏”。一旦图标出现在任务栏上,你可以简单地通过向左或向右拖动来改变它们的位置。

恭喜您,您已经建立了一个高度优化的新媒体 Java 8 游戏开发工作站,它将允许您创建您或您的客户可以想象的任何新媒体 Java 8 游戏!

摘要

在第一章中,我确保您拥有开发出色的 Java 8 游戏所需的一切,包括最新版本的 Java 8、JavaFX 和 NetBeans 8.0 以及所有最新的开源新媒体软件。

您首先下载并安装了最新的 Java JDK 8 和 NetBeans IDE 8.0 软件。然后,你对大量专业开源新媒体工具做了同样的事情。

在下一章中,我将向您展示如何使用 NetBeans 8.0 创建一个 Java 8 项目。

二、设置 Java 8 IDE:NetBeans 8.0 简介

让我们从第二章的开始,考虑 NetBeans IDE 8.0,因为它是您将用来创建 Java 8 游戏的主要软件。尽管 Java JDK 8 是 Java 8 游戏和 NetBeans 8.0 的基础,但您将从了解 NetBeans 开始您的旅程,因为它是“前端”,是您查看 Java 游戏项目的窗口。

NetBeans 8.0 是 Java JDK 8 的官方集成开发环境,因此,它将是你在本书中使用的。这并不是说您不能使用另一个 IDE,例如 Eclipse 或 IntelliJ,它们分别是 Android 4.x (32 位)和 Android 5.x (64 位)的官方 IDE,但是我更喜欢使用 NetBeans 8.0 来开发我的新媒体应用以及 Java 8、JavaFX 8、HTML5、CSS3(级联样式表 3)和 JavaScript 软件开发标记和编程范例的游戏开发。

这不仅是因为 NetBeans 8.0 集成了 JavaFX Scene Builder,您将在本书的第五章中了解到这一点,还因为它也是一个 HTML5 IDE,我使用 Java 8、JavaFX 8、Android 4.x 或 Android 5.x 以及 HTML5 为我的客户创建我设计的所有东西。我这样做是为了让内容可以在封闭的或专有的操作系统和平台上工作。正如你在第一章中观察到的,我更喜欢开源软件和平台。

首先,您将了解 NetBeans 8.0 的新增功能。该版本 NetBeans 与 Java 8 同时发布,版本号同步并非巧合。您将会发现为什么您希望使用 NetBeans 8.0,而不是较旧的 NetBeans 版本,例如 NetBeans 7.4 或更早的版本。

接下来,您将研究 NetBeans IDE 8.0 的各种属性,这些属性使它成为 Java 8 游戏开发的宝贵工具。您将无法获得本章中所有特性的实际操作经验,但是您将在本书的过程中探索它能为您做的所有很酷的事情(您将需要将一个高级代码库放在适当的位置,以真正锻炼一些特性)。

最后,您将学习如何使用 NetBeans 8.0 创建您的 Java 8 和 JavaFX 项目,以便在阅读本书的过程中创建您将要开发的 Java 8 游戏。

NetBeans 8.0 的主要属性:智能 IDE

假设您已经为新媒体内容和游戏开发准备好了专业级工作站,您需要删除所有过时的 JDK 和 ide,并确保您的系统上安装了最新的 V8 Java 和 NetBeans 软件,并准备就绪。如果你是新手,没有适合游戏的工作站,去沃尔玛或 PriceWatch.com,购买一台经济实惠的多核(使用 4 核、6 核或 8 核)64 位计算机,运行 Windows 8.1(或 9.0,如果有),至少有 4GB、6GB 或 8GB 的 DDR3 (1333 或 1600 内存访问速度)系统内存和 750GB,甚至 1TB 的硬盘驱动器。

NetBeans 8.0 很聪明:将您的代码编辑放入 Hyperdrive

虽然 IDE 确实像一个文字处理器,只是适合于编写代码文本而不是创建业务文档,但是像 NetBeans 这样的编程集成开发环境为您的编程工作过程所做的工作比文字处理器为您的文档创作工作过程所做的工作多得多。

例如,您的文字处理器不会就您为业务编写的内容提出实时建议,而 NetBeans IDE 会在您编写代码时查看您正在编写的内容,并帮助您编写代码语句和结构。

NetBeans 要做的事情之一是为您完成代码行,并对代码语句应用颜色以突出不同类型的构造(类、方法、变量、常量、引用等)(有关更多详细信息,请参见第三章)。NetBeans 还将应用代码缩进的行业标准,以使您的代码更易于阅读(对于您自己和游戏应用开发团队的其他成员来说)。

此外,NetBeans 将提供匹配的代码结构括号、冒号和分号,以便您在创建复杂、深度嵌套或异常密集的编程结构时不会迷路。从 Java 8 game 初学者到 Java 8 game developer,您将创建这样的结构,我将指出您遇到的密集、复杂或深度嵌套的 Java 8 代码。

NetBeans 还可以提供引导代码,例如您将在本章稍后创建的 JavaFX 游戏应用引导代码(请参见“创建您的 Java 8 项目:InvinciBagel”一节),以及代码模板(您可以填写和自定义)、编码提示和技巧以及代码重构工具。随着您的 Java 代码变得越来越复杂,它也成为代码重构的更好候选,这可以使代码更容易理解,更容易升级,并且更高效。NetBeans 还可以自动重构您的代码。

如果你想知道,代码重构是改变现有计算机代码的结构,使其更有效或可伸缩,而不改变其外部行为,即它完成的任务。例如,您可以使用 Java 8,通过实现 Lambda 表达式,获得 Java 6 或 Java 7 代码并使其更高效。

此外,NetBeans 提供了各种类型的弹出帮助器对话框,其中包含方法、常量、资产引用(请参见第三章),甚至是关于如何构造代码语句的建议,例如,何时使用强大的新 Java 8 Lambda 表达式功能来使您的代码更加简化并与多线程兼容可能是合适的。

NetBeans 8.0 是可扩展的:用多种语言进行代码编辑

您的文字处理器不能做的另一件事是允许您向它添加功能,而 NetBeans 可以使用其插件体系结构做到这一点。描述这种类型的体系结构的术语是可扩展的,这意味着如果需要,它可以扩展以包括附加的特性。因此,例如,如果您想扩展 NetBeans 8.0 以允许您使用 Python 编程,您可以这样做。NetBeans 8.0 也可以以这种方式支持较旧的语言,如 COBOL 和 BASIC,尽管目前大多数流行的消费电子设备都使用 Java、XML、JavaScript 和 HTML5,但我真的不知道为什么有人愿意花时间这样做。不过,我在谷歌上搜索了一下,有人在 NetBeans 8.0 中用 Python 和 COBOL 编写代码,所以有现实证明 IDE 确实是可扩展的。

可能是因为它的可扩展性,NetBeans IDE 8.0 支持许多流行的编程语言,包括客户端的 C、C++、Java SE、JavaScript、XML、HTML5 和 CSS,以及服务器端的 PHP、Groovy、Java EE 和 JavaServer Pages (JSP)。客户端软件在终端用户持有或使用的设备上运行(在 iTV 的情况下);服务器端软件在服务器上远程运行,当软件在服务器上运行时,它通过互联网或类似的网络与最终用户对话。客户端软件效率更高,因为它位于运行它的硬件设备的本地,因此更具可伸缩性:随着越来越多的人在任何给定的时间点使用该软件,不需要服务器经历过载。

NetBeans 8.0 是高效的:有组织的项目管理工具

一个好的编程 IDE 需要能够管理可以变得非常大的项目,包括包含在项目文件夹层次结构中的数百个文件夹中的超过一百万行代码,以及数千个文件和新媒体资产。因此,项目管理功能在任何主流 IDE 中都必须非常健壮。NetBeans 8.0 包含大量的项目管理功能,允许您以多种不同的方式查看 Java 8 游戏开发项目及其相应的文件以及它们之间的相互关系。

有四种主要的项目管理视图或“窗格”,可以用来查看项目中不同类型的相互关系。(我称它们为窗格,因为整个 IDE 都在我称之为窗口的地方)。我跳到前面(跳到这一章的末尾,一旦你的 Java 8 游戏项目已经创建好了)并创建了图 2-1 中的截图。这个屏幕截图显示了在这个新项目中打开的四个项目管理窗格,以便您可以准确地看到它们将向您显示什么。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-1。

Project management panes, at the left of the IDE, include Projects, Files, Services, and Navigator

屏幕左侧的项目窗格显示了构成您的(游戏)项目的 Java 源代码包和库。下一个窗格是文件窗格,它包含硬盘上的项目文件夹和文件层次结构。服务窗格包含数据库、服务器、存储库和构建主机,如果它们在项目中使用的话(这些主要是服务器端技术,以及开发团队使用的技术,所以我不打算详细讨论这些)。

项目窗格应该一直保持打开状态(如图 2-7 到 2-21 所示)。项目窗格为您提供了 Java 8 游戏项目中所有项目源代码和资源(内容)的主要访问点。“文件”窗格不仅显示项目文件夹和文件层次结构,还显示每个文件中的数据和 FXML 标记(JavaFX)或 Java 8 代码层次结构。

导航窗格(底部)显示了 Java 代码结构中存在的关系。在这种情况下,它们是InvinciBagel类、.start()方法和.main()方法(更多信息,参见第三章)。

NetBeans 8.0 是用户界面设计友好的:UI 设计工具

NetBeans 8.0 还为大量平台设计了 GUI 拖放设计工具,包括 Java SE、Java EE、Java ME、JavaFX 和 Java Swing 以及 C、C++、PHP、HTML5 和 CSS3。NetBeans 提供了可视编辑器,可以为您编写应用的 UI 代码,因此您所要做的就是让屏幕上的可视内容看起来像您希望它在游戏应用中的样子。由于游戏使用 JavaFX 新媒体(游戏)引擎,您将在本书的第五章中了解 JavaFX Scene Builder,这是一种基于 FXML 的高级可视化设计编辑器。

JavaFX 拥有 Prism 游戏引擎和 3D(使用 OpenGL ES[OpenGL for Embedded Systems])支持,因此我将重点介绍 JavaFX 场景图和 JavaFX APIs。这里的假设是,你可能想要构建最先进的 Java 8 游戏,利用 JavaFX 引擎(现在是 Java 8 的一部分,还有 Lambda 表达式)将是实现这一目标的方法。开发游戏的最快方法是利用 Java 8 和 JavaFX 环境慷慨提供的高级代码和编程结构,用于创建包含强大新媒体元素的尖端应用(在这里是游戏)。

NetBeans 8.0 对错误不友好:用调试器来消除错误

所有的计算机编程语言都有一个假设,即“bug”或不完全符合您要求的代码对您的编程项目的负面影响,会随着它保持未修复状态的时间越长而越大,因此 bug 必须在它们“出生”时就被消灭。NetBeans bug 查找代码分析工具,集成的 NetBeans 调试器,以及与第三方 FindBugs 项目的集成,正如您现在从经验(Audacity)中了解到的,可以在 SourceForge 网站( http://findbugs.sourceforge.net )(如果您想要独立版本),所有这些都补充了我前面讨论的实时“随键入”代码纠正和效率工具(请参见“NetBeans 8.0 是智能的:将您的代码编辑放入 Hyperdrive”一节)。

您的 Java 代码不会很复杂,直到本书的稍后部分,所以一旦您的知识库稍微高级一点,我将介绍当您需要使用这些工具时它们是如何工作的。

NetBeans 8.0 是一个速度狂:用分析器优化代码

NetBeans 还有一个叫做 Profiler 的东西,它会在 Java 8 代码运行时查看代码,然后告诉您它使用内存和 CPU 周期的效率。这允许您优化代码,使其更有效地使用关键系统资源,这对 Java 8 游戏开发非常重要,因为这将影响在功能不太强大的系统上(例如,在单核和双核 CPU 上)玩游戏的流畅度。

这个分析器是一个动态的软件分析工具,因为它在 Java 代码运行时查看您的代码,而 FindBugs 代码分析工具是一个静态的软件分析工具,因为它只是在编辑器中查看您的代码,而您的代码并没有在系统内存中编译和运行。NetBeans 调试器允许您在代码运行时逐句通过代码,因此可以将该工具视为从静态(编辑)到动态(执行)代码分析模式的混合体。

在创建了 Java 8 (JavaFX)游戏引擎的基础之后(在以下几节中),您将运行 Profiler 来查看它在 NetBeans IDE 8.0 中是如何工作的。我将在前面尽可能多地介绍 NetBeans 的关键特性,以便您能够熟悉这个软件。

创建您的 Java 8 游戏项目:InvinciBagel

让我们言归正传,为你的游戏创造基础。我将演示如何创建一个原创游戏,以便您可以看到开发一个尚不存在的游戏所涉及的过程,这与大多数游戏编程书籍相反,它们复制了市场上已经存在的游戏。我得到了我的客户 Ira Harrison-Rubin 的许可,他是 BagelToons 系列的漫画家/作家/幽默作家,让读者在这本书的过程中看到他的 InvinciBagel 卡通游戏的创作过程。

单击任务栏上的快速启动图标(或双击桌面上的图标)启动 NetBeans 8.0,您将看到 NetBeans 启动屏幕,如图 2-2 所示。此屏幕包含一个进度条(红色),将告诉您如何配置 NetBeans IDE 以供使用。这包括将 IDE 的各种组件加载到您的计算机系统内存中,以便在开发过程中可以流畅地实时使用它们。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-2。

Launch NetBeans 8.0, using the Quick Launch icon

将 NetBeans IDE 8.0 加载到系统内存后,屏幕上将显示 NetBeans 8.0 起始页,如图 2-3 所示。单击“起始页”选项卡右侧的“x”关闭此页面。

这将显示我称之为处女 IDE,没有项目活动。现在就享受吧,因为你很快就会在这个 IDE 中填满你的项目组件的窗格(你可以在图 2-4 中看到这个空 IDE 的一部分,它包含菜单和快捷图标,除此之外没什么)。

如果您想知道,每次启动 NetBeans IDE 时都会显示起始页,如果您想稍后打开起始页选项卡,也许是为了浏览媒体库部分(演示)和教程,您可以这样做!要随时打开起始页,可以使用 NetBeans IDE 8.0 的“帮助”菜单和“起始页”子菜单。为了将来参考,我通常这样标注菜单顺序:帮助➤开始菜单。

在 NetBeans IDE 8.0 中,您要做的第一件事就是创建一个新的 InvinciBagel 游戏项目!为此,您将使用 NetBeans 8.0 新项目系列对话框。这是我之前提到的那些有用的 Java 编程特性之一(参见“NetBeans IDE 8.0 是智能的:将您的编辑放入 Hyperdrive”一节),它使用正确的 JavaFX 库、.main().start()方法以及导入语句创建一个引导项目(有关更多详细信息,请参见第三章)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-3。

Close the Start Page tab, at the top left of the screen, by clicking the “x” at the right of the tab to reveal NetBeans IDE 8.0

点击 DE 左上角的文件菜单,如图 2-4 (左图),然后选择新建项目(第一个菜单项)。注意,在这个选项的右边,有一个键盘快捷键(Ctrl+Shift+N),以防你想记住它。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-4。

Showing virgin NetBeans 8.0 IDE (left) and a JavaFX New Project dialog (right)

如果您想要使用此键盘快捷方式来调出新的项目系列对话框,请按住键盘上的 CTRL 和 Shift 键(同时按住),并在按住它们的同时按下 N 键。这将做同样的事情使用文件➤新项目菜单序列。

系列中的第一个是选择项目对话框,如图 2-4 (右图)所示。因为您将在游戏中使用强大的 JavaFX 新媒体引擎,所以从“类别”窗格的编程语言类别列表中选择 JavaFX,并且因为游戏是一种应用,所以从“项目”窗格中选择 JavaFX 应用。

请记住,Oracle 使 JavaFX 成为 Java 7 和 Java 8 的一部分,因此 JavaFX 游戏也是 Java 游戏,而在 Java 7 之前(在 Java 6 中),JavaFX 是它自己独立的编程语言!JavaFX 引擎必须重新编码为 Java (7 和 8) API(一组库),才能成为 Java 编程语言的无缝部分。JavaFX API 取代了 AWT (Abstract Windowing Toolkit)和 Swing,虽然这些旧的 UI 设计库仍然可以在 Java 项目中使用,但它们通常只由遗留(旧的)Java 代码使用,以便这些项目可以在 Java 7 和 8 中编译和运行。在本章的稍后部分,您将编译并运行您在这里创建的新项目。

请注意,在其他窗格下面有一个描述窗格,它会告诉您您的选择会给你带来什么。在这种情况下,这将是一个启用了 JavaFX 特性的新 Java 应用;这里,“enabled”表示 JavaFX API 库将包含(并启动)在 Java 应用项目的类和方法中,您将很快在代码中看到这一点(有关代码含义的更多信息,请参见第三章)。

点击下一个按钮,进入系列中的下一个对话框,即查找特征对话框,如图 2-5 所示。该对话框在“激活 JavaFX 2”时显示进度条,这相当于在项目代码基础结构中安装 JavaFX API 库。你会发现有时候 JavaFX 8 还是被称为 JavaFX 2 (2.3 是人们开始使用 JavaFX 8 这个名字之前 JavaFX 的最新版本,可能是为了和 Java 8 同步)。我也看到了关于 JavaFX 3 的讨论,它现在被称为 JavaFX 8,因为 JavaFX 现在是 Java 8 的一部分,所以在本书中我将简称它为 JavaFX。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-5。

Step 2: Finding Feature dialog, showing the progress bar for the process of activating JavaFX

一旦 Finding Feature 对话框为你的游戏项目激活了 JavaFX,你将得到 Name and Location 对话框,如图 2-6 所示。将项目命名为 InvinciBagel,保留默认的项目位置、项目文件夹、JavaFX 平台,并按照 NetBeans 8.0 的配置方式创建应用类设置。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-6。

Name the project InvinciBagel, and leave the other settings as they are

让 NetBeans 8.0 为您做事通常是个好主意。如您所见,NetBeans 在您的用户文件夹和我的文档子文件夹中为项目位置数据字段创建了逻辑C:\Users\user\My Documents\NetBeansProjects文件夹。

对于您的项目文件夹数据字段,NetBeans 同样会在 NetBeansProjects 文件夹下创建一个名为 InvinciBagel 的子文件夹,就像您自己所做的一样。

对于 JavaFX 平台下拉菜单,NetBeans 8.0 默认为最新的 JDK 8,也称为 JDK 1.8,并具有最新的 JavaFX 8(应该是 JavaFX 3.0)。

因为您不会创建共享库的多个应用,所以请不要选中“使用专用文件夹存储库”复选框。最后,选择 Create Application Class,它将被命名为 invincibagel,并将位于 InvinciBagel 包中;因此,完整的路径和类名如下:invincibagel.InvinciBagel(遵循packagename.ClassName Java 命名范例和风格)。

(您将在第三章中了解更多关于包、类和方法的信息,但您最终将在这里接触到其中的一些信息,因为 NetBeans 8.0 将编写一些引导 Java 代码,这些代码将为您的 InvinciBagel Java 8 游戏提供基础。我将查看图 2-7 中所示的 Java 代码的一些基本组件,但在本章中我将主要关注 NetBeans IDE 8.0,并在第三章中关注 Java 8 编程语言。)

如图所示,NetBeans 编写了 package 语句、七个 JavaFX import 语句、类声明以及.start().main()方法。NetBeans 8.0 将 Java 关键编程语句单词涂成蓝色,注释涂成灰色。数据值为橙色,输入/输出为绿色。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-7。

Examine the bootstrap JavaFX code that NetBeans created for you, based on the New JavaFX Application dialog

在运行此引导代码之前,为了确保 NetBeans 8.0 为您编写的代码能够正常工作,您需要将其编译为可执行格式,并在系统内存中运行。

在 NetBeans 8.0 中编译您的 Java 8 游戏项目

在向您展示如何在运行(测试)Java 8 代码之前编译它的过程中,我在这里展示了“漫长的道路”,这样您就可以了解编译/运行 Java 8 代码测试过程的每一步。点击运行菜单,然后选择编译文件(第十一个菜单项)来编译你的 Java 代码,或者使用 F9 键盘快捷键,如选择右侧所示,如图 2-8 所示。现在您的项目已经准备好运行了!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-8。

Click the Run menu, at the top of the IDE, and then select Compile File, or press the F9 function key

图 2-9 展示了编译进度条,在编译过程中它会出现在 IDE 的底部。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-9。

The Compile progress bar is shown at the bottom of the screen, along with expand and collapse icon functionality

这里还需要注意的是,当您使用“文件”“保存”菜单序列(或 CTRL-S 键盘快捷键)时,NetBeans 将编译项目代码,因此,如果您在创建引导代码后立即使用 NetBeans IDE 的“保存”功能,您就不必执行我刚才向您展示的编译过程,因为该过程是在每次保存游戏项目时“自动地”(而不是手动地)完成的。

图中还显示,在编译进度条的正上方,突出显示了一段代码,这段代码在图 2-7 中是可见的,但我已经使用代码编辑器窗格左侧的减号图标将其折叠。您可以在代码编辑器窗格的中间看到三个未折叠的减号图标(在 InvinciBagel 类下),在代码编辑器窗格的顶部看到三个折叠的图标,分别代表两个注释和 import 语句代码块。减号图标会变成加号图标,以便可以展开折叠的代码视图。现在,您已经了解了如何在 NetBeans 中编译项目,以及如何折叠和展开项目代码的逻辑块(组件)视图,现在是运行代码的时候了。

在 NetBeans 8.0 中运行 Java 8 游戏项目

现在您已经创建并编译了您的 bootstrap Java 8/JavaFX 游戏项目,是时候运行或执行 bootstrap 代码,看看它做了什么。您可以通过使用运行➤运行项目菜单序列来完成此操作(参见图 2-8 ,或者您可以使用 IDE 顶部的快捷图标(类似于视频传输播放按钮),如图 2-10 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-10。

Click the Run Project shortcut icon (green play button), at the top middle of the IDE (tool tip pop-up shown)

一旦你运行了编译好的 Java 代码,一个窗口将会打开,你的软件在其中运行,在屏幕的右边,如图 2-11 所示。目前,该程序使用流行的“Hello World!”示例应用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-11。

Drag the separator bar upward to reveal the Compile Output area of the IDE (running the application seen at right)

单击代码编辑器窗格和底部输出选项卡之间的分隔线,按住鼠标按钮,向上拖动分隔线,显示输出选项卡的内容,如图 2-11 所示。

“输出”选项卡将包含 NetBeans 中不同类型的输出,例如 Ant 的编译操作输出、运行操作输出(如图所示)、探查器操作输出(您将在下一节中探讨),甚至是应用本身的输出。

您可能已经注意到,在图 2-10 中,这个 bootstrap Java 8/JavaFX 应用的代码在第 25 行包含了一个(System.out.println("Hello World!"); Java 语句,所以如果您想将当前正在运行的应用打印到输出窗格(有时在编程界称为输出控制台),请单击“Hello World!”中的“Hello World”按钮应用(运行在 IDE 之上)。

一旦你点击这个按钮,“你好,世界!”将出现在 Output 选项卡中,在红色文本下面,表示它正在执行 InvinciBagel.jar 文件。一个.jar (Java 归档)文件是 Java 应用的可分发格式。编译过程的一部分是创建这个文件,所以如果您的编译版本工作正常,您就可以准备好分发.jar文件,如果您的应用设计和编程已经完成的话!

一个.jar文件并不包含您实际的 Java 8 代码,而是一个压缩的、加密的“Java 字节流”版本的应用,JRE 可以执行和运行它(就像 NetBeans 8.0 现在正在做的那样)。附加在InvinciBagel.jar文件前面的路径告诉您编译后的.jar文件驻留在哪里,以及 NetBeans 当前从哪里访问它来运行它。在我的系统上,这个位置是 C:\ Users \ user \ Documents \ netbeans projects \ InvinciBagel \ dist \ run 1331700299 \ InvinciBagel . jar。

让我们看看其他一些输出选项卡文本,看看 NetBeans 做了什么来达到可以为这个项目运行.jar文件的程度。首先,编译器删除并重建 build-jar-properties 文件,该文件位于\NetBeansProjects\InvinciBagel\build文件夹中,基于游戏应用的独特属性。

接下来,Ant 创建一个\NetBeansProjects\InvinciBagel\dist\分发文件夹来保存项目.jar文件,然后检测 JavaFX 的使用情况,启动ant-javafx.jar来向 Ant 构建引擎添加 JavaFX 功能,这将创建.jar文件。最后,您将看到一条警告,要求将manifest.custom.codebase属性从星号值(这意味着“一切”)更改为特定值。我可能会在本书的后面进入应用开发的清单和权限领域,在您更深入一点之后。然后启动 JavaFX,并构建.jar文件。

Ant 是创建您的.jar文件的构建引擎或构建工具。其他构建引擎,如 Maven 和 Gradle,也可以在 NetBeans 中使用,因为正如您现在所知道的,NetBeans 是可扩展的!

Ant 也在 Eclipse IDE 中使用,并且是一个已经存在很长时间的 Apache 开源项目。要了解更多关于 Ant 构建系统及其功能的信息,请访问 Ant 网站( http://ant.apache.org )

接下来,您将探索 NetBeans 8.0 中的分析功能,它可以在运行时分析您的代码,并让您知道您的 Java 8 代码运行的效率如何。这对于游戏来说很重要,尤其是街机游戏或者任何在用户屏幕上实时移动精灵的游戏。你将在本书第六章中学习游戏概念和设计。

在 NetBeans 8.0 中分析您的 Java 8 游戏项目

要启动 Java 8 代码分析实用程序,使用 IDE 顶部的 Profile 菜单,选择 Profile Project (InvinciBagel)(第一个菜单项),如图 2-12 所示,或者使用 Profile Project 快捷图标,该图标在图 2-13 中给出的折叠屏幕视图中可见(您可以通过代码编辑器窗格中的 Java 代码行编号看出我折叠了该屏幕截图,该窗格仅包含第 1 行和第 38 行,即该范围中的第一个和最后一个数字;我用 Photoshop 去掉了第 2-37 行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-12。

Click the NetBeans IDE 8.0 Profile menu, and select the Profile Project (InvinciBagel) menu option

正如您在屏幕顶部的 Profile 菜单和 Profile Project 图标工具提示中所看到的,Profile Project 工具的键盘快捷键是 ALT+F2(按住键盘上的 ALT 键,同时按下键盘左上角的 F2 功能键)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-13。

The shortcut icon for the Profile Project utility, with tool tip (screen collapsed)

剖析 Java 8 游戏应用的 CPU 使用情况

使用 Profile Project 菜单项或快捷图标会打开 Profile InvinciBagel(你的游戏项目名称)对话框,如图 2-14 所示。让我们单击对话框左侧的中央 CPU 按钮,这将使对话框处于分析性能(选择特征)模式。稍后您将看到内存使用情况分析(参见“分析 Java 8 游戏应用内存使用情况”一节)。Monitor (button)选项支持实时线程监控,可以在编写 Java 代码时使用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-14。

Set the filter, using the drop-down menu in the Profile Project dialog, and select the Advanced (instrumented) output setting

在此对话框中,您可以选择快速配置文件或高级配置文件,它们具有可视化显示性能的图形工具。正如您所看到的,这是从 Instrumentation Filter 下拉菜单中选择的选项以及 Profile only project classes 选项。保持选中“使用已定义的分析点”,以使 NetBeans 8.0 尽可能完成最多的分析工作。还要注意对话框底部的顶置量规(指示器),指示 50%的值。

第一次运行 NetBeans 分析工具时,它需要校准您的工作站,因为每个工作站都有不同的特征,例如内存量和 CPU 内核或处理器的数量。

图 2-15 显示校准信息对话框,该对话框提示在校准过程中只有 NetBeans 在您的工作站上运行,并告诉您将来如何再次校准(如果您更改系统硬件配置),使用配置文件➤高级命令➤管理校准数据菜单序列。

还有一个警告,说你应该禁用动态 CPU 频率切换(这通常被称为超频),这是最近常见的功能。

因为我想测试较慢的 CPU 速度,所以我没有这么做,因为这涉及到进入工作站主板上的系统 BIOS(基本输入/输出系统),不是初学者可以随便玩的东西。

最终,测试游戏应用的最彻底的方法是在各种不同的操作系统和硬件配置上进行,但我想向您展示这种评测功能,因为这是获得应用性能良好基线的一种很好的方法,您可以在改进代码时对其进行改进(然后反复运行评测器,将结果与原始基线测量结果进行比较)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-15。

The first time you profile, a calibration is performed

单击“确定”按钮后,NetBeans IDE 8.0 将根据您的系统硬件特征来校准其分析工具,这在快速的现代多核工作站上应该不会花费很长时间。

如果您运行的是 Windows 操作系统(如这里所见,在 64 位 Windows 7 版本中),您可能会得到一个 Windows 防火墙已经阻止了此程序的某些功能的 Windows 安全警告对话框。您希望拥有 NetBeans 8.0 的所有功能,因此接下来让我们看看如何在 Windows 中允许访问 Java SE 8 平台。

通过 Windows 防火墙解除对 Java 8 平台二进制文件的封锁

如果出现可怕的阻止功能网络对话框,如图 2-16 所示,选择允许 Java Platform SE 二进制文件在专用网络(如我的家庭或工作网络)上通信复选框,然后单击允许访问按钮,这将允许 Java 8 platform SE 二进制文件通过 Windows 防火墙进行通信。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-16。

Allow Java features to be used by clicking Allow access

在您允许访问Java 8 platform SE binary之后,NetBeans 8.0 性能分析工具可以(并将)运行,并将生成基本的性能分析遥测结果。在接下来的几节中,您将更深入地了解这些,这几节讨论了如何分析性能分析结果,以及它们揭示了应用如何使用内存和 CPU 资源。

分析 NetBeans IDE 8.0 游戏项目 CPU 分析工具结果

NetBeans Profiler 主要查看内存使用情况和用于执行代码的 CPU 时间。使用的内存越少,CPU 时间越快(相当于执行代码所需的 CPU 处理周期越少),应用的优化就越好。分析器还关注与代码(软件)相关的东西,比如方法调用和线程状态,这些你将在本书的课程中学到。

运行 NetBeans 8.0 Profiler 后,您会看到 IDE 左侧的“项目”、“文件”和“服务”选项卡中添加了一个 Profiler 选项卡,如图 2-17 所示。您已经在本章的前面检查了这三个选项卡(请参见“NetBeans 8.0 是高效的:有组织的项目管理工具”一节),所以现在让我们来研究一下 Profiler 选项卡。

“Profiler”选项卡的顶部是“Controls”部分,带有“Stop(termin ate)Profiled Application”、“Reset Collected Profiling Results Buffer”、“Garbage Collection”、“Modify Profiling Session”和“VM Telemetry Overview”图标。

下面是 Status 部分,显示您选择的分析类型(在本例中是 CPU)、配置(分析性能)和状态(正在运行)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-17。

Profile’s Basic Telemetry section, at the left of the IDE, under the Profile tab, shows methods, threads, and total and used memory

“性能分析结果”部分包含打开“代码编辑器”部分中关于性能分析数据结果(报告)的选项卡的图标,而“视图”部分对虚拟内存(VM)遥测、线程和线程锁争用做同样的事情。在下一节中,当您分析内存使用情况时(您当前正在分析 CPU 使用情况),您将会看到其中的一些。

在代码分析会话期间,您可以在“保存的快照”部分保存不同时间点的快照。基本遥测部分显示关于分析会话的统计信息,包括方法数量、过滤器设置、运行的线程和内存使用情况。

单击性能分析结果部分的实时结果图标,打开一个实时性能分析结果选项卡,如图 2-18 所示,在顶部标有 CPU 时间(2:12:09 pm)。

正如您所看到的,您可以打开您的代码层次结构,包括.main()方法、.start()方法和.handle()方法,并查看它们所用总 CPU 时间的百分比以及实际使用的 CPU 时间(以毫秒为单位),这是 Java 8 和 JavaFX 的 Java 编程中使用的时间值,甚至是 HTML5、JavaScript 和 Android 应用开发中使用的时间值。

最后,正如您在图底部的输出窗格中看到的,还有文本输出,就像这个输出窗格用于显示编译、运行和执行的代码一样,也显示了分析器正在做什么。在“你好,世界!”通过单击应用的“Hello World”按钮,可以看到 Profiler 代理正在初始化、缓存类等等。在 NetBeans 的这个区域中有大量的选项卡和选项,我无法在这一基本的 NetBeans 概述章节中一一介绍,所以您可以随意使用您在屏幕上看到的内容!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-18。

NetBeans Profiler output, shown in the cpu tab, at the top right, and the Output tab, at the bottom right

剖析 Java 8 游戏应用的内存使用情况

接下来让我们看看内存分析。点击 Profile 项目图标,打开分析内存对话框,如图 2-19 所示。正如您所看到的,如果您为分配选择记录堆栈跟踪,分析器将使用更多的系统开销。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-19。

Select the Memory section of the Profile InvinciBagel dialog and select Record stack trace for allocation

一旦内存分析器运行,使用如图 2-20 (顶部)所示的窗口➤分析➤虚拟机遥测概述菜单序列,打开虚拟机遥测概述选项卡(底部)。该选项卡显示分配的内存和使用的内存。您可以将鼠标悬停在可视栏上,以获得任何时间点的准确读数。用编程术语来说,将鼠标悬停在某处将会在代码中使用“鼠标悬停”来访问

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-20。

Use the Window ➤ Profiling menu sequence to access the visual profiling tabs

查看窗口➤分析菜单序列中的一些其他可视报告选项卡。图 2-21 中显示的是线程选项卡,显示所有 11 个线程(参见屏幕左侧的基本遥测窗格),包括每个线程正在做什么(线程正在运行什么代码),以及虚拟机遥测选项卡,显示虚拟内存随时间的使用情况。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-21。

Use the Window ➤ Profiling menu sequence to access the Threads and VM Telemetry tabs

随着时间的推移,您将学会如何使用 NetBeans Profiler,首先是通过实验,然后随着您对 Profiler 功能的熟悉,在您自己的项目变得越来越复杂时使用它,并观察您的代码库在线程、CPU 使用以及内存分配和使用方面的情况。NetBeans Profiler 是一个强大而有用的工具,它将作为 Java 8 游戏开发的代码开发基础。我将它包含在本章中是为了给你一个坚实的概述,因为这个知识库将帮助你利用这个软件,最大限度地发挥它的潜力和能力。

显然,这是一个高级的 IDE 和软件开发工具,不可能在一个简短的章节(也许是一本书;但是,这不是 NetBeans 8.0 游戏开发的标题),所以您将在本书的几乎所有章节中更多地了解 NetBeans 8.0 可以为您做什么,因为 NetBeans 8.0 和 Java 8(以及 JavaFX 8)不可避免地交织在一起。

摘要

在第二章中,您学习了 NetBeans IDE 8.0,它将作为 Java 8 游戏开发工作流程的基础和主要工具。这个 IDE 是编写、编译、运行、测试和调试 Java 8(和 JavaFX 8)代码的地方,也是使用 NetBeansProject 文件夹及其子文件夹存储和引用新媒体(图像、音频、视频、3D、字体、形状等)资源的地方。

您首先了解了 NetBeans 8.0 及其高级特性,这些特性使其成为 Java 8 的官方 IDE,并帮助程序员第一次快速、高效地开发代码(即,使代码没有错误)。在这个概述之后,您创建了您的 Java 8 游戏项目,使用我为一个主要客户开发的真实世界游戏项目作为模型。

您浏览了新的 Java 应用系列对话框,并为您的游戏创建了 JavaFX 框架,这将允许您使用新的媒体资源,如图像、音频、视频和 3D。然后,您探索了如何使用 NetBeans 8.0 编译和运行应用。您还学习了 Output 选项卡,以及如何将它用于编译器输出、运行时输出和概要分析输出,这是您接下来要考虑的。

您研究了 NetBeans 8.0 中的 CPU 分析和内存分析;学习了如何设置和启动分析项目工具;并研究了 NetBeans Profiler 可以根据您的 Java 8 游戏项目为您创建的一些输出、统计和可视化报告。

在下一章中,我将介绍 Java 8 编程语言的概述,以确保您了解 Java 8 的工作原理;一个 Java 入门章节,如果你愿意的话。

三、Java 8 入门:Java 8 概念和原则的介绍

让我们以您在前一章中获得的关于 NetBeans IDE 8.0 的知识为基础,探索 Java 8 编程语言背后的基本概念和原理。Java JDK 8 将是您的 Java 8 游戏以及 NetBeans IDE 8.0 的基础,因此花时间学习本章是很重要的,这是一本 Java 8“初级读本”,它为您提供了这种国际流行的计算机(和设备)编程语言的概述。

当然,在阅读本书的过程中,您会学到更多高级的概念,比如 Lambda 表达式,以及其他 Java 8 组件,比如最近的 JavaFX 多媒体引擎,所以请注意,本章将涵盖最基础的 Java 编程语言概念、技术和原则,涵盖目前在计算机、ITV 和手持设备上广泛使用的三个主要 Java SE 版本。

这些被数十亿用户使用的 Java 版本包括 Java 6,用于 32 位 Android 4.x 操作系统和应用;Java 7,用于 64 位 Android 5.x 操作系统和应用;以及 Java 8,它在许多流行的操作系统中使用,如微软 Windows、苹果 OS X、Oracle Solaris 和大量流行的 Linux“发行版”或发行版(定制的 Linux 操作系统版本,如 SUSE、Ubuntu、Mint、Mandrake、Fedora 和 Debian)。

您将从最简单的概念(Java 的最高级别)开始,并逐步学习更难的概念(Java 编程结构的核心)。您将从学习 Java 语法或行话开始,包括什么是 Java 关键字,Java 如何界定其编程结构,以及如何注释您的代码。首先检查这一点将使您在阅读 Java 代码方面有一个良好的开端,因为能够从关于代码的注释(通常由 Java 代码的作者使用注释编写)中辨别 Java 代码是很重要的。

然后,您将考虑 API 的顶级概念,包是什么,以及如何导入和使用 Java 包提供的预先存在的代码。这些 Java 包是 Java 8 API 的一部分,值得注意的是,您可以创建自己的定制 Java 包,包含您的游戏或应用。

之后,您将考虑这些 Java 包中的构造,它们被称为 Java 类。Java 类是 Java 编程的基础,可用于构建您的应用(在这种情况下,您的 Java 8 游戏)。您将了解这些类包含的方法、变量和常量,以及什么是超类和子类,什么是嵌套类和内部类,以及如何利用它们。

最后,您将发现什么是 Java 对象,并了解它们如何构成面向对象编程(OOP)的基础。您还将了解什么是构造函数方法,以及它如何创建 Java 对象,方法是使用一种特殊的方法,称为构造函数方法,它与包含它的类同名。让我们开始吧——我们有很多内容要谈!

Java 的语法:注释和代码分隔符

关于语法,也就是 Java 如何用它的编程语言写东西,有几件事你需要马上考虑。这些主要的语法规则允许 Java 编译器理解你是如何构建你的 Java 代码的。Java 编译是 Java 编程过程的一部分,在这个过程中,JDK 编译器(程序)将 Java 代码转换成由 Java 运行时引擎(JRE)执行或运行的字节码。这个 JRE,在本例中是 JRE 8,安装在最终用户的计算机系统上。Java 编译器需要知道您的 Java 代码块在哪里开始和结束,您的各个 Java 编程语句或指令在这些 Java 代码块中在哪里开始和结束,您的代码的哪些部分是 Java 编程逻辑,哪些部分是对您自己的注释,或者对您的游戏项目编程团队的其他成员的注释(注释)。

让我们从注释开始,因为这个主题是最容易掌握的,而且你已经在你的 InvinciBagel 游戏 bootstrap Java 代码中看到了注释,在第二章中。有两种方法可以将注释添加到 Java 代码中:单行注释,也称为“行内”注释,放置在一行 Java 代码逻辑之后;多行注释,或“块”注释,放置在一行 Java 代码或一个 Java 代码块(Java 代码结构)之前(或之后)。

单行注释通常用于添加关于那一行 Java 逻辑(我喜欢称之为 Java 编程“语句”)正在做什么的注释,也就是说,那一行 Java 代码在整个代码结构中要完成什么。Java 中的单行注释以双正斜杠序列开始。例如,如果你想在你在第二章中创建的 InvinciBagel 引导代码中注释一个 import 语句,你可以在代码行后添加两个正斜杠。这是你的 Java 代码被注释后的样子(参见图 3-1 ,右下方):

import javafx.stage.Stage // This line of code imports the Stage class from JavaFX.stage package

接下来,让我们看看多行注释,它们显示在图 3-1 的顶部,在包语句的上方(你将在下一节中学习)。如您所见,这些 Java 块注释的处理方式不同,使用星号旁边的单个正斜杠开始注释,以及与此相反,在单个正斜杠旁边的星号结束多行注释。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-1。

Multiline comments (first five lines of code, at the top) and single-line comments (last three lines of code, at the bottom)

正如您在 NetBeans 8.0 的“InvinciBagel.java 代码编辑”选项卡中所看到的,正如我排列单行注释以使其看起来漂亮(酷)且有条理一样,块注释中的 Java 约定也是排列星号,一个作为开始注释分隔符,一个作为结束注释分隔符。

Definition

Java 编程中的“约定”是大多数(如果不是全部)Java 程序员实现 Java 构造的方式。在这种情况下,这就是 Java 代码块注释的样式。

还有第三种类型的注释,称为 Javadoc 注释,您不会在 Java 8 游戏开发中使用它,因为您的代码旨在用于创建游戏,而不是向公众发布。如果您打算编写一个 Java 游戏引擎,供其他人用来创建游戏,这时您应该使用 Javadoc 注释向您的 Java 8 游戏引擎添加文档。JDK 中的 javadoc.exe 工具可以使用 Javadoc 注释,根据您放入 Javadoc 注释中的文本内容,为包含 Javadoc 注释的 Java 类生成 HTML 文档。

Javadoc 注释类似于多行注释,但它使用两个星号来创建开始 Javadoc 注释分隔符,如下所示:

/** This is an example of a Java Documentation (Javadoc) type of Java code comment.

This is a type of comment which will automatically generate Java documentation!

*/

如果您想在 Java 语句或编程结构的中间插入一个注释(作为一名专业的 Java 程序员,您绝不能这样做),请使用多行注释格式,如下所示:

i``mport``/* This line of code imports the Stage class */

这不会产生任何错误,但是会让代码的读者感到困惑,所以不要用这种方式注释代码。但是,在 NetBeans 8.0 中,以下使用双正斜杠注释此代码的单行注释方式会生成编译器错误:

i``mport``// This line of code imports the Stage class

这里,编译器将只看到单词 import,因为单行注释位于行尾,而多行注释则使用块注释分隔符序列(星号和正斜杠)结束。因此,编译器将为第二个未正确注释的代码抛出一个错误,本质上是问“导入什么?”

正如 Java 编程语言使用双正斜杠和斜杠-星号对来分隔 Java 代码中的注释一样,其他一些关键字符也用于分隔 Java 编程语句和整个 Java 编程逻辑块(我经常称之为 Java 代码结构)。

分号在 Java(所有版本)中用来分隔或分开 Java 编程语句,比如图 3-1 中看到的 package 和 import 语句。Java 编译器寻找一个 Java 关键字,该关键字开始一个 Java 语句,然后将该关键字之后的所有内容作为 Java 代码语句的一部分,直到分号(这是告诉 Java 编译器“我已经完成了这个 Java 语句的编码工作”的方式)。例如,在你的 Java 应用的顶部声明 Java 包,你使用 Java 包关键字,你的包的名字,然后一个分号,如下所示(参见图 3-1 ):

package invincibagel;

Import 语句也使用分号分隔,如图所示。import 语句提供 import 关键字、要导入的包和类,最后是分号分隔符,如下面的 Java 编程语句所示:

import javafx.application.Application;

接下来,您应该看看花括号({。。。})分隔符,和多行注释分隔符一样,它有一个左花括号,用来分隔(也就是说,它显示了编译器)Java 语句集合的开始,还有一个右花括号,用来分隔 Java 编程语句集合的结束。花括号允许您在许多 Java 构造中使用多个 Java 编程语句,包括在 Java 类、方法、循环、条件语句、lambda 表达式和接口中,所有这些都将在本书的课程中学习。

如图 3-2 所示,用花括号分隔的 Java 代码块可以相互嵌套(包含),允许更复杂的 Java 代码结构。使用花括号的第一个(最外面的)代码块是 InvinciBagel 类,其他构造嵌套如下:start()方法。setOnAction()方法和 handle()方法。随着本章的深入,您将会看到所有这些代码都做了什么。我想让你现在想象一下(借助图 3.2 中的红色方块)花括号是如何允许你的方法(和类)定义它们自己的代码块(结构)的,每个代码块都是一个更大的 Java 结构的一部分,最大的 Java 结构是 InvinciBagel.java 类本身。请注意,每个左花括号都有一个匹配的右花括号。还要注意代码的缩进,最里面的 Java 代码结构向右缩进得最远。每个代码块额外缩进四个字符或空格。如您所见,该类没有缩进(0),start()方法在。setOnAction()方法在中是 8 个空格,handle()方法在中是 12 个空格。NetBeans 8.0 将为您缩进每一个 Java 代码结构!另请注意,NetBeans 8.0 在 ide 中绘制了非常精细的(灰色)缩进参考线,这样,如果您愿意,就可以直观地排列代码结构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-2。

Nested Java code blocks for the InvinciBagel class, start method, setOnAction method, and handle method

每个红色方块中的 Java 代码以花括号开始,以花括号结束。现在,您已经熟悉了各种 Java 8 代码注释方法,以及 Java 8 游戏编程语句需要如何分隔,无论是单独的还是作为 Java 代码块,接下来您将学习各种 Java 代码结构本身——它们是如何使用的,它们可以为您的应用和游戏做些什么,以及使用哪些重要的 Java 关键字来实现它们。

Java APIs:使用包按功能组织

在一个编程平台的最高层,比如谷歌的 32 位 Android 4,用的是 Java SE 6;64 位 Android 5,使用 Java SE 7;当前的 Oracle Java SE 平台(最近发布为 Java SE 8)有一个包含类、接口、方法和常量的包集合,它们共同构成了 API。应用(在本例中是游戏)开发人员可以使用这些 Java 代码集合(在本例中是 Java 8 API)来创建跨许多操作系统、平台和消费电子设备的专业级软件,这些设备包括计算机、笔记本电脑、上网本、笔记本、平板电脑、iTV 电视机、游戏控制台、智能手表和智能手机。

要安装给定版本的 API 级别,您需要安装 SDK(软件开发工具包)。Java SDK 有一个特殊的名字,JDK (Java 开发工具包)。熟悉 Android(Linux 之上的 Java SE)操作系统开发的人都知道,每次添加一些新特性时,都会发布不同的 API 级别。这是因为这些新的硬件功能需要支持,而不是因为谷歌的高管们觉得每隔几个月就要发布一个新的 SDK。Android 有 24 个不同的 API 级别,而 Java SE 只有 8 个,并且目前只有 3 个 Java 的 API 级别(Java 6、Java 7、Java 8)在使用。

Java SE 6 配合 Eclipse ADT(Android Developer Tools)IDE 使用,为 32 位 Android(1.5 到 4.5 版本)开发;Java SE 7 配合 IntelliJ IDEA 使用,为 64 位 Android(5.0 及以上版本)开发;Java 8 与 NetBeans IDE 配合使用,用于在 Windows、Mac OS X、Linux 和 Oracle Solaris 操作系统上开发 JavaFX 和 Java 8。我有三个不同的工作站,分别针对这些 Java API 平台和 IDE 软件包进行了优化,这样我就可以同时为 Android 4 (Java 6)、Android 5 (Java 7)和 JavaFX (Java 8)开发应用。幸运的是,你只需要花几百块钱就可以在 PriceWatch.com 上获得一台强大的 Windows 8.1 六核或八核 64 位 AMD 工作站!

除了 API 级别(您安装并正在使用的 SDK),Java 编程语言中最高级别的构造是包。Java 包使用 package 关键字在 Java 代码的顶部声明应用的包。这必须是声明的第一行代码,而不是注释(见图 3-1;参见第二章。您在第二章中使用的 NetBeans 中的新项目系列对话框将为您创建您的包,并根据您希望在应用中执行的操作导入您需要使用的其他包。在本例中,这些是 JavaFX 包,因此您可以使用 JavaFX 新媒体引擎。

正如您可能已经从名称中确定的那样,Java 包收集了所有的 Java 编程结构。这些包括与您的应用相关的类、接口和方法,因此 InvinciBagel 包将包含您的所有代码,以及您为使用代码而导入的代码,以创建、编译和运行 invinciBagel 游戏。

当然,Java 包对于组织和包含您自己的所有应用代码很有用,但是对于组织和包含 SDK(API)的 Java 代码更有用,您将使用这些代码以及您自己的 Java 编程逻辑来创建您的 Java 8 应用。通过使用 Java import 关键字,您可以使用作为您的目标 API 的一部分的任何类,该关键字与您想要使用的包和类一起构成了一个 import 语句。

import 语句以 import 关键字开始,后面是完全限定的类名,即包名、任何子包名和作为完整命名引用路径的类名(类的完整专有名称)。分号终止 import 语句。正如您已经在图 3-1 中看到的,用于从 javafx.event 包中导入 JavaFX EventHandler 类的 import 语句应该如下所示:

import javafx.event.EventHandler;

import 语句告诉 Java 编译器,您将使用被引用的类中的方法(或常量),使用 import 关键字,以及该类存储在哪个包中。如果您在自己的 Java 类中使用一个类、方法或接口,如 InvinciBagel 类(见图 3-2 ),并且您还没有使用 import 语句声明要使用的类,Java 编译器将抛出一个错误,直到您在类的顶部添加所需的 import 语句(在 Java 包声明语句之后,在 Java 类声明语句之前)。

Note

可以使用完全限定的类名来代替 Java import 关键字,也就是说,在 Java 代码中,类名的前面加上包名。惯例规定使用 import 语句;然而,如果你想打破标准 Java 编程惯例,图 3-2 中的第 20 行可以写成javafx.scene.control.Button btn = new javafx.scene.control.Button();

Java 类:构建的逻辑 Java 结构

包级别下的下一个逻辑 Java 编程构造是 Java 类级别,正如您在 import 语句中看到的,它引用包含类的包和类本身。正如包组织所有相关的类一样,类也组织所有相关的方法、变量和常量,有时还组织其他嵌套类。

因此,Java 类用于在功能组织的下一个逻辑级别组织您的 Java 代码,因此您的类将包含为您的应用添加功能的 Java 代码构造。这些可能包括方法、变量、常量、嵌套类或内部类。

Java 类也可以用来创建 Java 对象。Java 对象是使用 Java 类构造的,并且与 Java 类和该类的构造方法同名。

正如你在图 3-2 中看到的,你使用一个 Java class 关键字和你的类名来声明你的类。您还可以在声明的前面加上 Java 修饰符关键字,您将在本章的后面学习这些关键字(参见“Java 修饰符关键字:访问控制及其他”一节)。Java 修饰符关键字总是放在 Java class 关键字之前,使用以下格式:

<modifier keywords>``class

Java 类的一个强大特性是,它们可以用来模块化您的 Java 游戏代码,这样您的核心游戏应用特性就可以成为一个高级类的一部分,该高级类可以被子类化以创建该类的更专业的版本。在 Java 类层次术语中,一旦一个类被子类化,它就成为一个超类。一个类总是使用一个 Java extends 关键字来子类化一个超类。如果一个类没有以这种方式扩展给定的超类,那么它会自动扩展 Java master class:Java . lang . object。

使用 Java extends 关键字告诉编译器,您希望将超类的能力和功能添加(扩展)到您的类中,一旦使用该 extends 关键字,该类就成为子类。子类扩展了超类提供的核心功能。要扩展您的类定义以包含超类,您可以使用以下格式添加(或扩展,没有双关的意思)现有的类声明:

<modifier keywords>``class``<your custom classname>``extends

当你用你的类扩展一个超类时,它现在是那个超类的一个子类,你可以在你的子类中使用超类的所有特性(嵌套类、内部类、方法、变量、常量),而不需要把它们都显式地写(编码)在你的类的主体中,那样会是多余的(和混乱的)。

Note

如果您正在扩展的超类(或者,如果您喜欢,子类化)中的任何数据字段或方法已经使用 private access control 关键字声明,则这些变量(或常量)和方法将被保留,仅供该超类使用(或者在该超类中使用),因此您的子类将无法访问它们。同样的规则也适用于嵌套类和内部类;这些类结构不能使用任何在包含它们的 Java 构造中声明为私有的代码(或者在它们之上的代码)。

您的类的主体在花括号内编码(见图 3-2 ,最外面的红框),花括号跟在您的类(在本例中,还有 javafx.application.Application 超类)声明之后。这就是为什么您首先学习了 Java 语法,并且您正在使用类声明和包含类定义(变量、常量、方法、构造函数、嵌套类)结构的 Java 语法来构建它。

如图所示,InvinciBagel 类从 JavaFX 包中扩展了一个应用超类。因此,当前超类到子类层次结构的继承图(我将在整本书中使用该工具,向您展示在整个 Java 和 JavaFX API 模式中事物的来源)将如下所示:

> java.lang.Object

> javafx.application.Application

> invincibagel. InvinciBagel

通过扩展 javafx.application 包及其应用类,您将为 InvinciBagel 类提供托管(或运行)javafx 应用所需的一切。JavaFX 应用类“构造”一个应用对象,以便它可以使用系统内存;打电话给安。init()方法,初始化任何可能需要初始化的东西;并调用一个. start()方法(见图 3-2 ,第二个最外面的红框),该方法将最终启动 InvinciBagel Java 8 游戏应用所需的东西放置到位。

当最终用户使用完 InvinciBagel 游戏应用时,application 类使用 Application()构造函数方法创建的 Application 对象将调用它的。stop()方法并从系统内存中删除应用,从而释放内存空间供最终用户使用。您将很快学习 Java 8 方法、构造函数和对象,因为您正在从高级包和类构造向较低级的方法和对象构造前进,因此您正在从高级概述向较低级移动。您可能想知道 Java 类是否可以相互嵌套,也就是说,Java 类是否包含其他 Java 类。答案是肯定的,他们当然可以(也确实可以)!接下来让我们看看 Java 嵌套类的概念。

嵌套类:存在于其他类中的 Java 类

Java 中的嵌套类是定义在另一个 Java 类内部的类。嵌套类是它所嵌套的类的一部分,这种嵌套意味着这两个类打算以某种方式一起使用。嵌套类有两种类型:静态嵌套类,通常简称为嵌套类;非静态嵌套类,通常称为内部类。

静态嵌套类(我将称之为嵌套类)用于创建与包含它们的类一起使用的实用程序,有时仅用于保存与该类一起使用的常量。开发 Android 应用的人非常熟悉嵌套类,因为它们在 Android API 中非常常用,用于保存实用程序方法或 Android 常量,这些方法或常量用于定义屏幕密度设置、动画运动插值曲线类型、对齐常量和用户界面元素缩放设置等内容。如果你正在寻找关于静态概念的理解,它可以被认为是固定的,或者不能被改变。照片是静态图像,而视频不是静态的。在本书中,我们会经常看到这个概念。

嵌套类使用 Java 中通常所说的点符号来引用嵌套类“脱离”其主类或父类,即包含类。比如大师级。NestedClass 将是引用格式,用于通过主类(包含类)名称引用嵌套类,这里使用泛型类类型名称。如果您创建了 InvinciBagel SplashScreen 嵌套类来绘制 Java 游戏的闪屏,那么它将在 Java 代码中被引用为 InvinciBagel。SplashScreen,使用 Java 8 点符号语法。

例如,让我们看一下 JavaFX 应用类,它包含一个参数嵌套类。这个嵌套类封装或包含您可以为 JavaFX 应用设置的参数。因此,这个应用。参数嵌套类将是与应用类相同的 javafx.application 包的一部分,并且如果使用 import 语句,将被引用为 Java FX . Application . Application . parameters。

类似地,构造函数方法可以写成 Application。参数(),因为构造函数方法必须与包含它的类具有完全相同的命名模式。除非您正在为其他开发人员编写代码,这是嵌套类最常用的时候(如 JavaFX 应用类或许多嵌套的实用程序或常量提供者类,您将在 Android OS 中找到),否则您更有可能使用非静态嵌套类(通常称为 Java 内部类)。

嵌套类可以通过使用 Java static 关键字来声明。Java 关键字有时也被称为 Java 修饰符。因此,如果你要做一个InvinciBagel.SplashScreen嵌套类,InvinciBagel类和它的SplashScreen嵌套类声明(Java 8 编程结构)看起来会像这样:

public class InvinciBagel extends Application {

static class SplashScreen {

// The Java code that creates and displays your splashscreen is in here

}

}

需要注意的是,如果您使用import javafx.application.Application.Parameters来导入一个嵌套类,那么您可以在您的类中引用该嵌套类,只使用参数类名,而不是完整的类名路径,该路径显示了您的类的代码如何通过Application.Parameter (ClassName.NestedClassName)点标记语法引用穿过父类到达它的嵌套类。

正如您将在本书中多次看到的,Java 方法也可以使用点符号来访问。因此,不使用类名。如果您使用 import 语句来导入这个嵌套类,那么只需使用NestedClassName.MethodName。这是因为 Java import 语句已经被用来建立这个嵌套类的完整引用路径,通过它的包含类,所以您不需要提供这个完整路径引用,编译器就能知道您引用的是什么代码构造!

接下来,让我们看看非静态嵌套类,它们通常被称为 Java 内部类。

内部类:不同类型的非静态嵌套类

Java 内部类也是嵌套类,但是它们不是在 class 关键字和类名之前使用 static 关键字修饰符声明的,这就是它们被称为非静态嵌套类的原因。因此,在另一个不使用 static (keyword)修饰符的类中的任何类声明在 Java 中都被称为内部类。Java 中有三种类型的内部类:成员类、本地类和匿名类。在本节中,您将发现这些内部类之间的区别,以及它们是如何实现的。

像嵌套类一样,成员类是在包含(父)类的主体中定义的。您可以在包含类的体中的任何地方声明成员类。如果您想访问属于包含类的数据字段(变量或常量)和方法,而不必提供数据字段或方法(ClassName.DataField or ClassName.Method)的路径(通过点符号),您可以声明一个成员类。成员类可以被认为是不使用 Java static modifier 关键字的嵌套类。

尽管嵌套类是通过其包含类(或顶级类)引用的,使用静态嵌套类的点标记路径,但成员类由于不是静态的,所以是特定于实例的,这意味着通过该类创建的对象(实例)可以彼此不同(对象是类的唯一实例),而静态(固定)嵌套类将只有一个版本,不会改变。例如,私有内部类只能由包含它的父类使用。编码为私有类的内部类看起来像这样:

public class InvinciBagel extends Application {

private class SplashScreen {

// The Java code that creates and displays your splashscreen is in here

}

}

因为这个类被声明为私有的,所以它是供您自己的应用使用的(特别是包含类的使用)。因此,这不是供其他类、应用或开发人员使用的实用程序或常量类。您也可以在不使用 private access 修饰符关键字的情况下声明您的内部类,类似于下面的 Java 编程结构:

public class InvinciBagel extends Application {

class SplashScreen {

// The Java code that creates and displays your splashscreen is in here

}

}

这种级别的访问控制称为包或包私有,是应用于任何类、接口、方法或数据字段的默认访问控制级别,这些类、接口、方法或数据字段在声明时不使用任何其他 Java 访问控制修饰符关键字(public、protected、private)。这种类型的内部类不仅可以被顶级类或包含类访问,还可以被包含该类的包中的任何其他类成员访问。这是因为包含类被声明为 public,内部类被声明为 package private。如果希望内部类在包外可用,可以使用下面的 Java 代码结构将其声明为 public:

public class InvinciBagel extends Application {

public class SplashScreen {

// The Java code that creates and displays your splashscreen is in here

}

}

还可以声明一个内部类 protected,这意味着它只能被父类的任何子类访问。如果在不是类的低级 Java 编程结构中声明一个类,比如方法或迭代控制结构(通常称为循环),从技术上讲,它被称为局部类。局部类只在代码块内部可见;因此,它不允许(或者说使用)类修饰符,比如 static、public、protected 或 private。局部类的用法类似于局部变量,只是它是一个复杂的 Java 编码结构,而不是一个简单的局部使用的数据字段值。

最后,有一种内部类叫做匿名类。匿名类是没有给定类名的局部类。您可能会比本地类更频繁地遇到匿名类。这是因为程序员经常不命名他们的本地类(使它们成为匿名类);本地类包含的逻辑只在本地用于它们的声明,所以这些类实际上不需要名字——它们只是在 Java 代码块内部被引用。

Java 方法:核心 Java 函数代码构造

在类内部,通常有方法和这些方法使用的数据字段(变量或常量)。因为我们是从外部到内部,或者从顶层结构到底层结构,所以接下来我将介绍方法。在其他编程语言中,方法有时被称为函数。图 3-2 提供了一个。start()方法,展示了该方法如何保存创建基本“Hello World!”应用。该方法中的编程逻辑使用 Java 编程语句来创建 Stage 对象和 Scene 对象,在 StackPane 对象中的屏幕上放置一个按钮,并定义事件-处理逻辑,以便当单击按钮时,引导 Java 代码编写“Hello World!”文本到 NetBeans IDE 输出区域。

方法声明以访问修饰符关键字开始,可以是 public、protected、private 或 package private(这是通过根本不使用任何访问控制修饰符来指定的)。如图所示,已经使用公共访问控制修饰符声明了. start()方法。

在这个访问控制修饰符之后,您需要声明该方法的返回类型。这是该方法在被调用后将返回的数据类型。因为。start()方法执行设置操作,但不返回特定类型的值,它使用 void 返回类型,这表示该方法执行任务,但不向调用实体返回任何结果数据。在这种情况下,调用实体是 JavaFX 应用类,因为。start()方法是关键方法之一(其他方法是。停止()和。init()方法)来控制 JavaFX 应用的生命周期阶段。

接下来,您将提供方法名,按照惯例(编程规则),它应该以小写字母(或单词,最好是动词)开头,任何后续的(内部)单词(名词或形容词)都以大写字母开头。例如,显示闪屏的方法将被命名为。showSplashScreen()或。displaySplashScreen()并且因为它执行某些操作但不返回值,所以将使用以下代码进行声明:

public void displaySplashScreen() { Java code to display splashscreen goes in here }

如果您需要传递参数,这些参数是命名的数据值,必须在方法体(花括号内的部分)中进行操作,这些参数放在方法名的括号内。在图 3-2 中。start()方法为您的引导“HelloWorld!”JavaFX 应用使用以下 Java 方法声明语法接收一个名为 primaryStage 的 Stage 对象:

public void start(Stage primaryStage) { bootstrap Java code to start Application goes in here }

您可以使用数据类型和参数名称对来提供任意数量的参数,每对之间用逗号分隔。方法也可以没有参数,在这种情况下,参数括号是空的,左括号和右括号紧挨着,例如。start()和。停止()。

定义方法的编程逻辑将包含在方法体中,如前所述,方法体位于定义方法开始和结束的花括号内。方法中的 Java 编程逻辑可以包括变量声明、程序逻辑语句和迭代控制结构(循环),您将利用所有这些来创建您的 Java 游戏。

在继续之前,让我们关注另一个适用于方法的 Java 概念,即重载 Java 方法。重载一个 Java 方法意味着使用相同的方法名,但是不同的参数列表配置。这意味着,如果您定义了多个同名的方法,Java 可以通过查看传递给被调用方法的参数,然后通过匹配参数列表数据类型和名称以及它们出现的顺序,使用该参数列表来辨别要使用的方法(同名的),从而确定要使用哪个(重载的)方法。当然,为了让这个 Java 方法重载特性正常工作,您的参数列表配置必须都是惟一的。

你将在本书的课程中学习如何使用和如何编写 Java 方法,从第四章开始,所以我在这里不打算花太多时间在它们上面,除了定义它们是什么以及它们在 Java 类中如何声明和使用的基本规则。

然而,我将要详细介绍的一种特殊的方法是构造函数方法。这是一种可用于创建对象的方法。Java 对象是 OOP 的基础,所以接下来您将看一看构造函数方法,因为在学习 Java 对象本身之前这样做是很重要的,您将在本章的后面学习 Java 对象(参见“Java 对象:虚拟现实,使用 Java 构造”一节)。

创建 Java 对象:调用类的构造函数方法

一个 Java 类可以包含一个与该类同名的构造函数方法,该方法可用于使用该类创建 Java 对象。构造函数方法使用它的 Java 类像蓝图一样在内存中创建该类的一个实例,这样就创建了一个 Java 对象。构造函数方法总是返回一个 Java 对象,因此不使用其他方法通常使用的任何 Java 返回类型(void、String 等)。使用 Java new 关键字调用构造函数方法,因为您正在创建一个新对象。

你可以在图 3-2 (ll)所示的引导 JavaFX 代码中看到这样的例子。20、28 和 30),其中通过使用以下对象声明、命名和创建 Java 代码结构,分别创建新按钮、StackPane 和 Scene 对象:

<Java class name> <your object instance name> =``new

以这种方式声明 Java 对象的原因是因为 Java 对象是 Java 类的一个实例,在一个以分号结束的 Java 语句中使用类名、正在构造的对象名、Java new 关键字和类的构造函数方法名(以及参数,如果有的话)。

例如,让我们看一下在当前 Java 代码的第 20 行创建的按钮对象。这里,通过 equals 操作符左侧的 Java 语句部分,您告诉 Java 语言编译器,您想要创建一个名为 btn 的按钮对象,使用 JavaFX 按钮类作为对象蓝图。这将声明 Button 类(对象类型)并给它一个惟一的名称。

因此,创建对象的第一部分称为对象声明。创建 Java 对象的第二部分称为对象实例化,从 equals 操作符的右边可以看出,这部分对象创建过程包括一个构造函数方法和 Java new 关键字。

要实例化一个 Java 对象,需要调用 Java new 关键字,并调用对象构造器方法。因为这发生在 equals 操作符的右边,所以对象实例化的结果放在声明的对象中,该对象在 Java 语句的左边。正如你将在本章稍后看到的,当我讨论操作符时(参见“Java 操作符:在应用中操作数据”一节),这就是 equals 操作符的作用,它是一个有用的操作符。

这就完成了声明(类名)、命名(对象名)、创建(使用 new 关键字)、配置(使用构造函数方法)和加载(使用 equals 操作符)您自己的定制 Java 对象的过程。

值得注意的是,这个过程的声明和实例化部分也可以使用单独的 Java 代码行进行编码。例如,按钮对象实例化(见图 3-2 ,l. 20)可以编码如下:

Button btn;

btn =``new

这一点很重要,因为以这种方式编写对象创建代码允许您在类的顶部声明一个对象,其中类中使用或访问这些对象的每个方法都可以看到该对象。在 Java 中,除非使用修饰符声明,否则对象或数据字段只在声明它的 Java 编程结构(类或方法)中可见。

如果你在你的类中声明一个对象,因此在类中包含的所有方法之外,那么你的类中的所有方法都可以访问(使用)那个对象。类似地,在方法中声明的任何内容都是该方法的局部内容,并且仅对该方法的其他成员可见(方法范围分隔符中的 Java 语句)。如果您想实现这个单独的对象声明(在类中,在方法之外)和对象实例化(在。start()方法)在您当前的 InvinciBagel 类中,InvinciBagel 类的前几行 Java 代码将更改为如下所示的 Java 编程逻辑:

public class InvinciBagel extends Application {

Button btn;

@Override

public void start(Stage primaryStage) {

btn = new Button();

btn.setText("Say 'Hello World'");

// The other programming statements continue underneath here

}

}

当对象声明和实例化被分开时,它们可以根据可见性的需要放在方法内部(或外部)。在前面的代码中,InvinciBagel 类的其他方法可以调用。setText()方法调用显示 Java 编译器没有抛出错误。图 3-2 中按钮对象的声明方式,只有。start()方法可以看到对象,因此只有。start()方法可以使用这个 btn.setText()方法调用。

创建构造函数方法:对对象的结构进行编码

构造函数方法更像是一种在系统内存中创建对象的方法,而其他方法(或函数,如果使用不同的编程语言)通常用于执行某种类型的计算或处理。构造函数方法用于在内存中创建 Java 对象,而不是执行其他一些编程功能,这一点可以通过使用 Java new 关键字来证明,该关键字在内存中创建新对象。因此,构造函数方法将定义对象的结构,并允许调用实体使用构造函数方法的参数列表用自定义数据值填充对象结构。

在本节中,您将创建两个示例构造函数方法,以了解如何实现这一点以及构造函数方法通常包含的内容。假设您正在为您的游戏创建 InvinciBagel 对象,那么您使用以下 Java 代码结构声明一个公共 InvinciBagel()构造函数方法:

public InvinciBagel() {

int lifeIndex = 1000;  // Defines units of lifespan

int hitsIndex = 0;    //  Defines units of damage ("hits" on the object)

String directionFacing = "E";        // Direction that the object is facing

Boolean currentlyMoving = false;  //  Flag showing if the object is in motion

}

当使用InvinciBagel mortimer = new InvinciBagel(); Java 方法调用时,这个构造函数方法创建一个名为 mortimer 的 InvinciBagel 对象,它有 1000 个生命单位,没有命中,面向东方,当前没有移动。

接下来,让我们探讨一下重载构造函数方法的概念,您在前面已经学过了(参见“Java 方法:Java 核心函数代码构造”一节),并创建另一个构造函数方法,该方法具有允许您在创建 InvinciBagel 对象时定义其 lifeIndex 和 directionFacing 变量的参数。此构造函数方法如下所示:

public InvinciBagel(``int lifespan, String direction

int lifeIndex;

int hitsIndex;

String directionFacing = null;

Boolean currentlyMoving = false;

lifeIndex = lifespan;

directionFacing = direction;

}

在这个版本中,顶部的 lifeIndex 和 hitsIndex 变量被初始化为 0,这是一个整数的默认值,因此您不必在代码中使用 lifeIndex = 0 或 hitsIndex = 0。Java 编程语言支持方法重载,所以如果您使用一个InvinciBagel bert = new InvinciBagel(900, "W");方法调用来实例化 InvinciBagel 对象,将会使用正确的构造函数方法来创建该对象。名为 bert 的 InvinciBagel 对象的生命指数为 900 个生命单位,没有生命命中,面向西方,目前不会移动。

您可以拥有任意多的(重载的)构造函数方法,只要它们都是 100%唯一的。这意味着重载的构造函数必须有不同的参数列表配置,包括参数列表长度(参数的数量)和参数列表类型(数据类型的顺序)。如您所见,参数列表(长度、数据类型、顺序)允许 Java 编译器区分重载方法。

Java 变量和常量:数据字段中的值

下一层(从 API、包、类、方法,到 Java 类和方法中操作的实际数据值)是数据字段。数据值保存在一个叫做变量的东西里;如果数据是固定的,或者是永久的,它就叫做常量。常量是一种特殊类型的变量(我将在下一节中介绍),因为正确声明一个常量比声明一个 Java 变量要复杂(高级)一些。

在 Java 行话中,在类的顶部声明的变量被称为成员变量、字段或数据字段,尽管所有的变量和常量都可以被认为是数据字段。在方法中声明的变量或在类或方法中声明的其他低级 Java 编程结构称为局部变量,因为它只能在花括号分隔的编程结构中局部看到。最后,在方法声明或方法调用的参数列表区域中声明的变量被称为参数,这并不奇怪。

变量是一个数据字段,它保存了 Java 对象或软件的一个属性,这个属性会随着时间的推移而改变。可以想象,这对于游戏编程来说尤其重要。最简单的变量声明形式可以通过使用 Java 数据类型关键字,以及您希望在 Java 程序逻辑中使用的变量名称来实现。在上一节中,使用构造函数方法,您声明了一个名为 hitsIndex 的整数变量来保存 InvinciBagel 对象在游戏过程中受到的伤害或命中。您使用以下 Java 变量声明编程语句定义了变量数据类型,并将其命名为:

int hitsIndex; // This could also be coded as: int hitsIndex = 0; (the default Integer is Zero)

正如您在该部分中看到的,您可以使用等号运算符将变量初始化为初始值,以及与声明的数据类型相匹配的数据值:例如:

String facingDirection = "E";

这个 Java 语句声明了一个 String 数据类型变量,并将其命名为 facingDirection,位于 equals 运算符的左侧,然后将声明的变量设置为值“E”,这表示方向是东或右。这类似于对象的声明和实例化,只是 Java new 关键字和构造函数方法被数据值本身所取代,因为现在声明的是变量(数据字段),而不是创建的对象。你将在本章后面了解不同的数据类型(我已经介绍过整数、字符串和对象)(参见“Java 数据类型:在应用中定义数据”一节)。

您还可以在变量声明中使用 Java 修饰符关键字,这一点我将在下一节中介绍,届时我将向您展示如何声明一个不可变的变量,也称为常量,它在内存中是固定的或锁定的,并且不能更改。

既然我已经差不多完成了从最大的 Java 结构到最小的(数据字段)结构的讨论,我将开始讨论适用于 Java 所有层次(类、方法、变量)的主题。这些概念通常会随着您阅读 Java 8 入门章节的结束而变得更加复杂。

在内存中固定数据值:在 Java 中定义数据常量

如果您已经熟悉计算机编程,您会知道通常需要数据字段总是包含相同的数据值,并且在应用运行周期期间不会改变。这些被称为常量,它们是使用特殊的 Java 修饰符关键字定义或声明的,这些关键字用于固定内存中的内容,使它们不能被更改。还有一些 Java 修饰符关键字将限制(或取消限制)对象实例,或者对 Java 类或包内部或外部的某些类的访问(您将在下一节中详细研究)。

要声明固定的 Java 变量,必须使用 Java final 修饰符关键字。“最终”和你父母说某事是最终的意思是一样的:它固定在一个地方,是一个事实,永远不会改变。因此,创建常数的第一步是添加这个 final 关键字,将其放在声明中的数据类型关键字之前。

在声明 Java 常量(以及其他编程语言中的常量)时,一个约定是使用大写字符,每个单词之间带有下划线,这表示代码中的常量。

如果你想为你的游戏创建屏幕宽度和屏幕高度常量,你可以这样做:

final int SCREEN_HEIGHT_PIXELS = 480;

final int SCREEN_WIDTH_PIXELS  = 640;

如果希望类的构造函数方法创建的所有对象都能够看到并使用该常量,可以添加 Java static modifier 关键字,将其放在 final modifier 关键字的前面,如下所示:

static final int SCREEN_HEIGHT_PIXELS = 480;

static final int SCREEN_WIDTH_PIXELS = 640;

如果您只希望您的类以及由此类创建的对象能够看到这些常量,您可以通过在 static modifier 关键字之前放置 Java private modifier 关键字来声明这些常量,使用以下代码:

private static final int SCREEN_HEIGHT_PIXELS = 480;

private static final int SCREEN_WIDTH_PIXELS = 640;

如果您希望任何 Java 类,甚至那些在您的包之外的类(即任何其他人的 Java 类),能够看到这些常量,您可以通过在 static modifier 关键字之前放置 Java public modifier 关键字来声明这些常量,使用下面的 Java 代码:

public static final int SCREEN_HEIGHT_PIXELS = 480;

public static final int SCREEN_WIDTH_PIXELS = 640;

正如您所看到的,为您的类声明一个常量比声明一个简单的变量涉及到更详细的 Java 语句!接下来,您将更深入地了解 Java 修饰符关键字,因为它们允许您控制诸如对类、方法和变量的访问,以及锁定它们以防被修改,以及类似的相当复杂的高级 Java 代码控制概念。

Java 修饰符关键字:访问控制等等

Java 修饰符关键字是保留的 Java 关键字,用于修改主要类型的 Java 编程结构中的代码的访问、可见性或持久性(在应用执行期间内存中存在的时间)。修饰符关键字是第一个在 Java 代码结构之外声明的关键字,因为该结构的 Java 逻辑(至少对于类和方法来说)包含在花括号分隔符内,该分隔符位于类关键字和类名之后,或者方法名和参数列表之后。修饰符关键字可以用于 Java 类、方法、数据字段(变量和常量)和接口。

如您在图 3-2 底部所见,对于。main()方法,由 NetBeans 为您的 InvinciBagel 类定义创建,它使用 public 修饰符,您可以使用多个 Java 修饰符关键字。那个。main()方法首先使用 public 修饰符关键字,这是一个访问控制修饰符关键字,然后使用 static 修饰符关键字,这是一个非访问控制修饰符关键字。

访问控制修饰符:公共、受保护、私有、包私有

让我们先介绍访问控制修饰符,因为它们是首先声明的,在非访问修饰符关键字或返回类型关键字之前,并且因为它们在概念上更容易理解。有四种访问控制修饰符级别适用于任何 Java 代码结构。如果没有声明 access control 修饰符关键字,那么默认的访问控制级别 package private 将应用于该代码结构,这使得它对于 Java 包(在本例中是 invincibagel)中的任何 Java 编程结构都是可见的,因此也是可用的。

其他三个访问控制修饰符级别有自己的访问控制修饰符关键字,包括 public、private 和 protected。这些都是根据它们所做的事情来命名的,所以您可能很清楚如何应用它们来公开共享您的代码或防止它被公开使用,但是让我们在这里详细地讨论每一个,只是为了确保安全,因为访问(安全性)是当今的一个重要问题,无论是在您的代码内部还是在外部世界。我先从最少的访问控制开始!

Java 的 Public 修饰符:允许公众访问 Java 程序结构

Java 公共访问修饰符关键字可以被类、方法、构造函数、数据字段(变量和常量)和接口使用。如果你声明一个公共的东西,它就可以被公众访问!这意味着它可以被世界上任何其他类、任何其他包导入和使用。本质上,您的代码可以在任何使用 Java 编程语言创建的软件中使用。正如您将在 Java 或 JavaFX 编程平台(API)中使用的类中看到的,public 关键字最常用于开源编程 Java 平台或用来创建定制应用(如游戏)的包中。

需要注意的是,如果您试图访问和使用的公共类存在于您自己的包之外的包中(在您的例子中,是 invincibagel),那么 Java 编程约定是使用 Java import 关键字创建一个允许使用该公共类的 import 语句。这就是为什么当您阅读完本书时,您的 InvinciBagel.java 类的顶部将会有几十个 import 语句,因为您将会利用代码库中已存在的 Java 和 JavaFX 类,这些类已经使用 public access control 修饰符关键字进行了编码、测试、精炼和公开,因此您可以随心所欲地使用它们来创建 Java 8 游戏!

由于 Java 中的类继承概念,公共类中的所有公共方法和公共变量都将被该类的子类继承(一旦被子类化,就成为超类)。图 3-2 在InvinciBagel类关键字前面提供了一个公共访问控制修饰符关键字的例子。

Java 的 Protected 修饰符:变量和方法允许子类访问

Java protected access modifier 关键字可由数据字段(变量和常量)和方法(包括构造函数方法)使用,但不能由类或接口使用。protected 关键字允许超类中的变量、方法和构造函数只被其他包(如 invincibagel 包)中该超类的子类访问,或者被包含这些受保护成员的类(Java 构造)的同一个包中的任何类访问。

这个访问修饰符关键字本质上保护了一个类中的方法和变量,该类通过被其他开发人员子类化(扩展)而成为(希望被用作)一个超类。除非您拥有包含这些受保护的 Java 构造的包(事实上您没有),否则您必须扩展超类并从该超类创建您自己的子类,以便能够使用受保护的方法。

您可能想知道,为什么要这样做,以这种方式保护 Java 代码结构?当你在设计一个大的项目时,比如 Android OS API,你通常会希望不要直接在那个类之外或之内使用更高级的方法和变量,而是在一个定义更好的子类结构中使用。

您可以通过保护这些方法和变量构造不被直接使用来实现这种直接的使用预防,这样它们就只成为其他类中更详细的实现的蓝图,而不能被直接使用。本质上,保护一个方法或变量只是把它变成一个蓝图或定义。

Java 的私有修饰符:变量、方法和类只能进行本地访问

Java private access control 修饰符关键字可由数据字段(变量或常量)和方法(包括构造函数方法)使用,但不能由类或接口使用。private 修饰符可以由嵌套类使用;但是,它不能被外部类或主(最顶层)类使用。private access control 关键字允许类中的变量、方法和构造函数只能在该类内部被访问。private access control 关键字允许 Java 实现一个称为封装的概念,在这个概念中,一个类(以及使用该类创建的对象)可以封装自己,可以说对 Java 世界之外隐藏了它的“内部”。封装的 OOP 概念可以在大型项目中使用,以允许团队创建(更重要的是,调试)他们自己的类和对象。这样,其他任何人的 Java 代码都无法破解存在于这些类内部的代码,因为它们的方法、变量、常量和构造函数都是私有的!

access modifier 关键字本质上是将类中的方法或变量私有化,这样它们只能在该类中本地使用,或者由该类的构造函数方法创建的对象使用。除非您拥有包含这些私有 Java 构造的类,否则您不能访问或使用这些方法或数据字段。这是 Java 中最严格的访问控制级别。如果从类内部访问私有变量的公共方法称为公共方法,则可以在类外部访问声明为私有的变量。get()方法调用被声明为公共的,因此提供了通过该公共方法访问私有变量或常量中的数据的路径(或门道)。

Java 的包私有修饰符:包中的变量、方法和类

如果没有声明 Java 访问控制修饰符关键字,那么默认的访问控制级别(也称为包私有访问控制级别)将应用于该 Java 构造(类、方法、数据字段或接口)。这意味着这些 Java 构造对于包含它们的 Java 包中的任何其他 Java 类都是可见的,或者是可用的。这种包私有级别的访问控制最容易与您的方法、构造函数、常数和变量一起使用,因为它只需通过不显式声明访问控制修饰符关键字来应用。

您将在自己的 Java 应用(游戏)编程中经常使用这个默认的访问控制级别,因为通常您是在自己的包中创建自己的应用,供用户在编译后的可执行状态下使用。但是,如果您正在开发游戏引擎供其他游戏开发者使用,您将会使用更多我在本节中讨论的访问控制修饰符关键字来控制其他人如何使用您的代码。

非访问控制修饰符:final、static、abstract、volatile、synchronized

不专门为 Java 构造提供访问控制特性的 Java 修饰符关键字被称为非访问控制修饰符关键字。这些包括经常使用的 final、static 和 abstract 修饰符关键字,以及不经常使用的 synchronized 和 volatile 修饰符关键字,它们用于更高级的线程控制,我不会在这个初级编程标题中讨论它们,除非描述它们的含义和作用,以防您在 Java 世界旅行中遇到它们。

我将按照复杂性的顺序来介绍这些概念,也就是说,从初学者最容易理解的概念到面向对象编程初学者最难理解的概念。面向对象编程就像冲浪,因为它看起来很难,直到你练习多次,然后突然你就明白了!

Java 的最后一个修饰符:不可修改的变量、方法和类

您已经研究了 final 修饰符关键字,因为它与 static 关键字一起用于声明常数。最终数据字段变量只能初始化(设置)一次。final 引用变量是一种特殊类型的 Java 变量,它包含对内存中对象的引用,不能被更改(重新分配)来引用不同的对象;然而,保存在(最终)被引用对象中的数据是可以更改的,因为只有对对象本身的引用才是最终引用变量,最终引用变量实际上是用 Java final 关键字锁定的。

Java 方法也可以使用 final 修饰符关键字来锁定。当一个 Java 方法成为 final 时,如果包含该方法的 Java 类被子类化,那么这个 final 方法不能在子类的主体中被覆盖或修改。这基本上锁定了方法代码结构内部的内容。例如,如果您想要。InvinciBagel 类的 start()方法(如果它曾经被子类化过的话)总是做与 InvinciBagel 超类相同的事情(准备一个 JavaFX 登台环境),您使用下面的代码:

public class InvinciBagel extends Application {

Button btn;

@Override

public``final

btn = new Button();

// The other method programming statements continue here

}

}

这可以防止任何子类(public class InvinciBagelReturns 扩展 InvinciBagel)改变 InvinciBagel 游戏引擎(JavaFX)的初始设置,这就是。start()方法确实适合你的游戏应用(见第四章)。使用 final modifier 关键字声明的类不能被扩展或子类化,从而锁定该类以备将来使用。

Java 的静态修饰符:存在于类中的变量或方法(不在对象中)

正如您已经看到的,static 关键字可以与 final 关键字结合使用来创建一个常量。static 关键字用于创建独立存在的 Java 构造(方法或变量),或者在使用定义静态变量或静态方法的类创建的任何对象实例之外。一个类中的静态变量将强制该类的所有实例共享该变量中的数据,就从该类创建的对象而言,几乎就像它是一个全局变量一样。类似地,静态方法也将存在于该类的实例化对象之外,并将由所有这些对象共享。静态方法不会引用自身外部的变量,例如实例化对象的变量。

一般来说,静态方法有自己的内部(局部或静态)变量和常数,还会使用方法参数列表接收变量,然后根据这些参数和自己的内部(静态局部)常数(如果需要)提供处理和计算。因为 static 是一个应用于类实例的概念,因此比任何类本身的级别都低,所以不能使用 static 修饰符关键字来声明类。

Java 的抽象修饰符:要扩展和实现的类和方法

Java abstract modifier 关键字更多的是保护您的实际代码,而不是运行时放在内存中的代码(对象实例和变量等等)。abstract 关键字允许您指定如何将代码用作超类,也就是说,一旦代码被扩展,它如何在子类中实现。因此,它仅适用于类和方法,不适用于数据字段(变量和常量)。

使用 abstract modifier 关键字声明的类不能被实例化,它旨在用作超类(蓝图)来创建(扩展)其他类。因为 final 类不能扩展,所以不能在类级别同时使用 final 和 abstract 修饰符关键字。如果一个类包含任何使用 abstract modifier 关键字声明的方法,则该类本身必须声明为抽象类。然而,抽象类不必包含任何抽象方法。

使用 abstract modifier 关键字声明的方法是声明用于子类但没有当前实现的方法。这意味着它的方法体中没有 Java 代码,如你所知,在 Java 中是用花括号描述的。任何扩展抽象类的子类都必须实现所有这些抽象方法,除非该子类也被声明为抽象,在这种情况下,抽象方法被传递到下一个子类级别。

Java 的 Volatile 修饰符:对数据字段的高级多线程控制

Java volatile modifier 关键字在开发多线程应用时使用,在基本的游戏开发中不打算这样做,因为您希望对游戏进行足够好的优化,以便它只使用一个线程。volatile 修饰符告诉运行应用的 Java 虚拟机(JVM)将声明为 volatile 的数据字段(变量或常量)的私有(线程的)副本与系统内存中该变量的主副本合并。

这类似于 static modifier 关键字,区别在于静态变量(数据字段)由多个对象实例共享,而可变数据字段(变量或常量)由多个线程共享。

Java 的 Synchronized 修饰符:对方法的高级多线程控制

Java synchronized 修饰符关键字也在开发多线程应用时使用,在这里您不会为基本的游戏开发这样做。synchronized 修饰符告诉运行应用的 JVM,声明为 synchronized 的方法一次只能被一个线程访问。这个概念类似于同步数据库访问的概念,它可以防止记录访问冲突。synchronized 修饰符关键字同样可以防止访问您的方法(在系统内存中)的线程之间的冲突,方法是将访问序列化为一次一个,这样就不会出现多个线程并行(同时)访问内存中的一个方法的情况。

既然您已经学习了主要的 Java 构造(类、方法和字段)和基本的修饰符关键字(public、private、protected、static、final、abstract 等等),现在让我们进入花括号,了解用于创建 Java 编程逻辑的工具,这些逻辑将最终定义您的游戏应用的游戏玩法。

Java 数据类型:在应用中定义数据类型

因为您已经了解了一些 Java 数据类型中遇到的变量和常量,所以接下来让我们来研究这些变量和常量,因为这对于您当前从简单到复杂的主题的进展来说并不太难!

Java 中有两种主要的数据类型分类:原始数据类型,如果您使用过不同的编程语言,这是您最熟悉的数据类型;引用(对象)数据类型,如果您使用过另一种 OOP 语言,如 Lisp、Python、Objective-C、C++或 C# (C Sharp),您就会知道这种数据类型。

原始数据类型:字符、数字和布尔值(标志)

Java 编程语言中有八种原始数据类型,如表 3-1 所示。您将在本书中使用它们来创建您的 InvinciBagel 游戏,所以我现在不打算详细介绍它们中的每一个,只是说 Java 布尔数据变量用于标志或开关(开/关),char 用于 Unicode 字符或创建字符串对象(char 数组),其余的用于保存不同大小和分辨率的数值。整数值保存整数,而浮点值保存分数(小数点值)。对于变量的使用范围,使用正确的数值数据类型是很重要的,因为,正如你在表 3-1 的二进制大小一栏中看到的,大数值数据类型比小数值数据类型多使用八倍的内存。

表 3-1。

Java Primitive Data Types, Along with Their Default Values, Size in Memory, Definition, and Numeric Range

数据类型默认二进制大小定义范围
布尔错误的1 位真值或假值0 到 1(假或真)
\u000016 位Unicode 字符\u0000 到\ uffff
字节Zero8 位有符号整数值–128 到 127(总共 256 个值)
短的Zero16 位有符号整数值–-32768 到 32767(总共 65,536 个值)
(同 Internationalorganizations)国际组织Zero32 位有符号整数值–2147483648 转 2147483647
长的Zero64 位有符号整数值–9223372036854775808 转 922337203685
漂浮物Zero32 位IEEE 754 浮点值1.4E-45 至 3.4028235E+38
两倍Zero64 位IEEE 754 浮点值4.9E-324 至 1.7976931348623157E+308

引用数据类型:对象和数组

(OOP 语言也有引用数据类型,它在内存中提供对另一个包含更复杂数据结构的结构的引用,比如对象或数组。这些更复杂的数据结构是使用代码创建的;在 Java 中,这是一个类。有各种类型的 Java 数组类可以创建数据数组(如简单的数据库)以及 Java 类中的构造函数方法,它可以在内存中创建对象结构,包含 Java 代码(方法)和数据(字段)。

Java 操作符:操纵应用中的数据

在本节中,您将了解 Java 编程语言中一些最常用的运算符,尤其是那些对游戏编程最有用的运算符。这些包括算术运算符,用于数学表达式;关系运算符,用于确定数据值之间的关系(等于、不等于、大于、小于等);逻辑运算符,用于布尔逻辑;赋值运算符,它执行算术运算,并在一次紧凑运算中将值赋给另一个变量(运算符);以及条件运算符,也称为三元运算符,它根据真或假(布尔)计算的结果为变量赋值。

还有概念上更高级的按位运算符,用于在二进制数据(零和一)级别执行运算,其逻辑超出了本书的初学者范围,并且在 Java 游戏编程中的使用不像这些其他更主流类型的运算符那样常见,在本书的过程中,您将使用其中的每一种运算符来完成游戏逻辑中的各种编程目标。

Java 算术运算符

Java 算术运算符是编程中最常用的,尤其是在街机类型的游戏中,游戏中的东西在屏幕上以离散的像素数量移动。从小学到大学,你已经在数学课上学过,使用这些基本的算术运算符可以创建许多更复杂的方程。

表 3-2 中显示的算术运算符中,您可能不太熟悉的是模运算符,它将在除法运算完成后返回余数(剩余的部分),以及递增和递减运算符,它们分别从一个值中加 1 或减 1。这些用于实现您的计数器逻辑。计数器(使用递增和递减操作符)最初用于循环,(我将在下一节介绍);然而,这些递增和递减运算符对游戏编程也非常有用(点数、寿命损失、游戏棋子移动和类似的进展)。

表 3-2。

Java Arithmetic Operators, Their Operation Type, and a Description of the Arithmetic Operation

操作员操作描述
加号+添加将运算符两边的操作数相加
减号–减法从左操作数中减去右操作数
相乘*增加将运算符两边的操作数相乘
划分/分开用左操作数除以右操作数
模数%剩余物将左操作数除以右操作数,返回余数
增量++添加 1将操作数的值增加 1
减量-减去 1将操作数的值减 1

要实现算术运算符,请将希望接收算术运算结果的数据字段(变量)放在等于赋值运算符的左侧,将希望执行算术运算的变量放在等号的右侧。以下是添加 x 和 y 变量并将结果赋给 z 变量的示例:

Z = X``+

如果你想从 x 中减去 y,你用减号而不是加号;如果你想把 x 和 y 值相乘,你用星号而不是加号;如果你想用 x 除以 y,你要用正斜杠而不是加号。这些操作如下所示:

Z = X``-

Z = X``*

Z = X``/

你会经常用到这些算术运算符,所以在你读完这本书之前,你会得到一些很好的练习。接下来让我们更仔细地看看关系运算符,因为有时您会想要比较值而不是计算它们。

Java 关系运算符

在某些情况下,Java 关系运算符用于在两个变量之间或者变量和常量之间进行逻辑比较。这些应该是你在学校熟悉的,包括等于、不等于、大于、小于、大于或等于和小于或等于。在 Java 中,equal to 在被比较的数据字段之间使用两个等号,并在等号前使用一个感叹号来表示“不等于”表 3-3 显示了关系运算符,以及每个运算符的示例和描述。

表 3-3。

Java Relational Operators, an Example in Which A = 25 and B = 50, and a Description of the Relational Operation

操作员例子描述
==不正确两个操作数的比较:如果它们相等,那么条件等于真
!=(答!= B)为真两个操作数的比较:如果它们不相等,则条件等于真
>不正确两个操作数的比较:如果左操作数大于右操作数,则等于真
<(A < B)为真两个操作数的比较:如果左操作数小于右操作数,则等于真
>=(A >= B)不正确比较两个操作数:如果左操作数大于或等于右操作数等于真
<=(A <= B)为真比较两个操作数:如果左操作数小于或等于右操作数,则等于真

大于符号是向右的箭头,小于符号是向左的箭头。它们用在等号前,分别创建大于或等于和小于或等于关系运算符,如表 3-3 底部所示。

这些关系运算符返回布尔值 true 或 false,因此在 Java 的控制(循环)结构中使用得相当多,在游戏编程逻辑中也用于控制游戏将采取的路径(结果)。例如,假设你想确定游戏屏幕的左边缘在哪里,这样当不可战胜的怪物向左移动时,他就不会离开屏幕。使用这种关系比较:

boolean changeDirection = false ; // Create boolean variable changeDirection, initialize

changeDirection =``(invinciBagelX <= 0)``; //  boolean changeDirection is``TRUE

请注意,我使用了< =小于或等于(是的,Java 也支持负数),因此,如果 invincibegel 越过了屏幕的左侧(x=0),changeDirection 布尔标志将被设置为 true 值,sprite 移动编程逻辑可以通过改变移动方向(因此 invincibegel 从墙上弹开)或完全停止移动(因此 invincibegel 粘在墙上)来处理这种情况。

在本书中,你将会接触到大量的关系操作符,因为它们在创建游戏逻辑时非常有用,所以我们很快就会从中获得很多乐趣。接下来让我们看看逻辑运算符,这样我们就可以处理布尔集合,分组比较事物,这对游戏也很重要。

Java 逻辑运算符:

Java 逻辑运算符类似于布尔运算(并集、交集等。),并允许您确定两个布尔变量是否具有相同的值(和),或者其中一个布尔变量是否与另一个不同(或)。还有一个 NOT 运算符,它反转任何比较的布尔操作数的值。表 3-4 显示了 Java 的三个逻辑操作符,以及每个操作符的例子和描述。

表 3-4。

Java Logical Operators, an Example in Which A = True and B = False, and a Description of Logical Operation

操作员例子描述
&&(A && B)是假的当两个操作数的值相同时,逻辑 AND 运算符等同于 true。
||(A || B)是真的当两个操作数的值相同时,逻辑 OR 运算符等同于 true。
!(A && B)是真的逻辑 NOT 运算符会反转应用它的运算符(或集合)的逻辑状态。

让我们使用逻辑运算符来增强上一节中的游戏逻辑示例,包括 InvinciBagel 在屏幕上移动的方向。现有的 facingDirection 字符串变量将控制 InvinciBagel 面对的方向(如果在运动,还会向内移动)。现在,您可以使用以下逻辑运算符来确定 InvinciBagel 是否面向左侧(W 或 West);如果 travelingWest 布尔变量为 true 如果屏幕左侧的 hit(或 passed)布尔变量 hitLeftSideScrn 也等于 true。为此,修改后的代码将包括另外两个布尔变量声明和初始化,如下所示:

boolean changeDirection = false ; // Create boolean variable changeDirection, initialize

boolean hitLeftSideScrn = false ; // Create boolean variable hitLeftSideScrn, initialize

boolean travelingWest = false ;   // Create boolean variable travelingWest, initialize

hitLeftSideScrn =``(invinciBagelX <= 0)``; //  boolean hitLeftSideScrn is``TRUE

travelingWest =``(facingDirection == "W")``// boolean travelingWest is``TRUE``if facingDirection="``W

changeDirection = (hitLeftSideScrn && travelingWest) // Change Direction, if both equate to TRUE

为了查明 InvinciBagel 是否面向西方(或者如果也在移动,则正在行进),您创建了另一个 travelingWest 布尔变量,并将其初始化(将其设置为 equal)为 false(因为您的初始 facingDirection 设置为 East)。然后,创建一个名为 hitLeftSideScrn 的布尔变量,将其设置为(invinciBagelX <= 0)关系运算符语句。

最后,用travelingWest = (facingDirection == "W")逻辑创建一个关系操作符语句,然后准备将 changeDirection 布尔变量用于新的逻辑操作符。该逻辑运算符将使用changeDirection = (hitLeftSideScrn && travelingWest)逻辑运算编程语句,确保 hitLeftSideScrn 和 travelingWest 布尔变量都设置为真。

现在,您已经开始练习声明和初始化变量,并使用关系和逻辑操作符来确定主要游戏棋子的方向和位置(在街机游戏中称为精灵;关于游戏设计术语的更多信息,请参见第六章。接下来,让我们看看赋值操作符。

Java 赋值运算符

Java 赋值运算符将赋值运算符右侧的逻辑构造中的值赋给赋值运算符左侧的变量。最常见的赋值运算符也是 Java 编程语言中最常用的运算符,即等号运算符。等号运算符可以以任何算术运算符开头,以创建也执行算术运算的赋值运算符,如表 3-5 所示。当变量本身成为等式的一部分时,这允许创建更“密集”的编程语句。因此,不需要写 C = C + A,你可以简单地使用 C+=A 并获得相同的最终结果。在你的游戏逻辑设计中,你会经常用到这个赋值操作符快捷键。

表 3-5。

Java Assignment Operators, What Each Assignment Is Equal to in Code, and a Description of the Operator

操作员例子描述
=C=A+B基本赋值运算符:将右侧操作数的值赋给左侧操作数
+=C+=A 等于 C=C+A加法赋值运算符:将右操作数与左操作数相加;将结果放入左操作数
-=等于 C=C-A子赋值运算符:从左操作数中减去右操作数;将结果放入左操作数
*=C*=A 等于 C=C*AMULT 赋值运算符:将右操作数和左操作数相乘;将结果放入左操作数
/=C/=A 等于 C=C/ADIV 赋值运算符:将左操作数除以右操作数;将结果放入左操作数
%=C%=A 等于 C=C%A模赋值运算符:用左操作数除以右操作数;将余数放入左侧操作数

最后,你要看看条件操作符,它也允许你编写强大的游戏逻辑。

Java 条件运算符

Java 语言也有一个条件运算符,它可以计算一个条件,并根据该条件的解析,只使用一个紧凑的编程结构为您进行变量赋值。条件运算符的通用 Java 编程语句总是使用以下基本格式:

Variable = (evaluated expression) ? Set this value if TRUE : Set this value if FALSE ;

所以,在等号的左边,你有一个变量,它会根据等号右边的内容而改变(被设置)。这与你到目前为止所学的一致。

在等号的右边,有一个计算表达式,例如,“x 等于 3”,后面是一个问号,然后是两个用冒号分隔的数值,最后是一个分号来结束条件运算符语句。如果要在 x 等于 3 时将变量 y 的值设置为 25,而在 x 不等于 3 时将变量 y 的值设置为 10,则可以使用以下 Java 编程逻辑编写条件运算符编程语句:

y``=``(x``==``3)``?``25``:``10``;

接下来,您将看到 Java 逻辑控制结构,它利用了您刚刚学习的操作符。

Java 条件控制:决策还是循环

正如您刚才看到的,许多 Java 操作符可以有相当复杂的结构,并使用很少的 Java 编程逻辑字符提供很大的处理能力。Java 还有几个更复杂的条件控制结构,一旦你通过编写 Java 逻辑控制结构为那些决策或任务重复设置了条件,它就可以自动为你做出决策或执行重复的任务。

在本节中,您将首先探索决策控制结构,例如 Java switch-case 结构和 if-else 结构。然后,您将了解 Java 的循环控制结构,包括 for、while 和 do-while。

决策控制结构:开关盒和 If-Else

一些最强大的 Java 逻辑控制结构允许您定义在应用运行时希望程序逻辑为您做出的决策。一个这样的结构提供了一个逐案的“平面”决策矩阵;另一个有级联(如果这个,做这个;如果没有,就这样做;如果没有,就这样做;依此类推)一种结构类型,它按照您希望的检查顺序对事物进行评估。

让我们从 Java switch 语句开始,它使用 Java switch 关键字和这个决策树顶部的一个表达式,然后使用 Java case 关键字为这个表达式求值的每个结果提供 Java 语句块。如果表达式求值没有调用(使用)switch 语句结构(花括号)中的任何一种情况,您还可以提供一个 Java default 关键字和 Java 语句代码块来完成您想要做的事情。

case 语句中使用的变量可以是四种 Java 数据类型之一:char(字符)、byte、short 或 int(整数)。您通常希望在每个 case 语句代码块的末尾添加一个 Java break 关键字,至少在这样的用例中是这样,在这种用例中,需要在值之间进行切换,并且对于 switch 语句的每次调用,只有一个是可行的(或允许的)。默认语句“如果其中任何一个不匹配”是开关内的最后一个语句,不需要这个 break 关键字。

如果您没有在每个 case 逻辑块中提供 Java break 关键字,那么在通过 switch 语句的同一次传递中,可以对多个 case 语句进行求值。这将在表达式求值树从顶部(第一个 case 代码块)到底部(最后一个 case 代码块或默认关键字代码块)的过程中完成。因此,如果您有一个布尔“标志”的集合,如 hasValue、isAlive、isFixed 等,这些都可以通过使用一个根本不使用任何 break 语句的 switch-case 语句结构在一次“传递”中处理。

这样做的意义在于,您可以根据 case 语句的求值顺序,以及是否将 break 关键字放在任何给定 case 语句代码块的末尾,创建一些相当复杂的决策树。

切换情况决策树编程构造的一般格式如下所示:

switch (expression) {

case value1 :

programming statement one;

programming statement two;

break;

case value2 :

programming statement one;

programming statement two;

break;

default :

programming statement one;

programming statement two;

}

假设你想在你的游戏中决定当不可战胜的怪物被击中时(被击中,被打成肉泥,被击中,等等)调用哪个不可战胜的怪物死亡动画。死亡动画例程(方法)将被调用,基于无敌手被击中时的活动状态,例如飞行(F)、跳跃(J)、奔跑®或空闲(I)。假设这些状态保存在一个名为 ibState 的数据字段中,类型为 char,它保存一个字符。一旦命中发生,使用这些游戏块状态指示器来调用正确方法的开关情况代码结构将是:

switch (ibState) {            // Evaluate ibState char and execute case code blocks accordingly

case 'F' :

deathLogicFlying();  // Java method controlling death sequence if InvinciBagel flying

break ;

case 'J' :

deathLogicJumping(); // Java method controlling death sequence if InvinciBagel jumping

break ;

case 'R' :

deathLogicRunning(); // Java method controlling death sequence if InvinciBagel running

break ;

default :

deathLogicIdle();    // Java method controlling death sequence if InvinciBagel is idle

这个 switch-case 逻辑构造在 switch()语句的求值部分中对 ibState char 变量求值(注意,这是一个 Java 方法),然后为每个游戏角色状态(飞行、跳跃、奔跑)提供一个 case 逻辑块,并为空闲状态提供一个默认逻辑块(这是设置它的一种逻辑方式)。

因为一个游戏棋子不能同时空闲、奔跑、飞行和跳跃,所以需要使用 break 关键字来使这个决策树的每个分支都是唯一的(唯一的)。

switch-case 决策结构通常被认为比 if-else 决策结构更有效、更快,if-else 决策结构只能使用 if 关键字进行简单评估,如下所示:

if``(expression =``true

programming statement one;

programming statement two;

}

您还可以添加一个 else 关键字,使这个决策结构评估在布尔变量(true 或 false 条件)评估为 false 而不是 true 时需要执行的语句,这使这个结构更强大(也更有用)。这种通用编程结构将如下所示:

if``(expression =``true

programming statement one;

programming statement two;

}``else``{                         // Execute this code block if (expression =``false

programming statement one;

programming statement two;

}

此外,可以嵌套 if-else 结构,从而创建 if{}-{else if}-{else if}-else{}结构。如果这些结构嵌套得太深,那么您会希望切换到 switch-case 结构,相对于嵌套的 if-case 结构,if-else 嵌套得越深,这将变得越来越有效。例如,您之前为 InvinciBagel 游戏编写的 switch-case 语句,如果转换为嵌套的 if-else 决策结构,将类似于下面的 Java 编程结构:

if``(ibState = '``F

deathLogicFlying();

}``else if``(ibState = '``J

deathLogicJumping();

}``else if``(ibState = '``R

deathLogicRunning();

}``else

deathLogicIdle();

}

正如您所看到的,这个 if-else 决策树结构与您之前创建的 switch-case 非常相似,只是决策代码结构相互嵌套,而不是包含在一个平面结构中。根据经验,我将使用 if 和 if-else 进行一值和二值评估,使用 switch-case 进行三值和更高值的评估。我在关于 Android 的书中大量使用了这种开关盒结构。

接下来,让我们看看 Java 中广泛使用的其他类型的条件控制结构,即循环编程结构。这些函数允许您执行一个编程语句块预定义的次数(使用 for 循环)或直到实现一个目标(使用 while 或 do-while 循环)。

循环控制结构:While、Do-While 和 For

尽管决策树类型的控制结构被遍历了固定的次数(除非遇到 break [switch-case]或 resolved expression [if-else],否则遍历一次),但循环控制结构会随着时间的推移而不断执行,这对于 while 和 do-while 结构来说,有点危险,因为如果不小心使用编程逻辑,可能会产生无限循环!for 循环结构执行有限数量的循环(数量在 for 循环的定义中指定),您将在本节中看到。

让我们从有限循环开始,首先介绍 for 循环。Java for 循环使用以下通用格式:

for (initialization; boolean expression; update equation) {

programming statement one;

programming statement two;

}

如您所见,for 循环求值区域的三个部分在括号内,用分号分隔,因为每个部分都包含一个编程语句。第一个是变量声明和初始化,第二个是布尔表达式求值,第三个是显示如何在每次循环中递增循环的更新方程。

要在屏幕上沿 X 和 Y 方向移动 InvinciBagel 40 像素diagonally, for 循环如下:

for``(int x=0; x < 40; x = x + 1) {   // Note: an x = x + 1 statement could also be coded as

invinciBagelX++;  // Note: invinciBagelX++ could be coded invinciBagelX = invinciBagelX + 1;

invinciBagelY++;  // Note: invinciBagelY++ could be coded invinciBagelY = invinciBagelY + 1;

}

相反,while(或 do-while)类型的循环不会在有限数量的处理周期内执行,而是使用以下结构执行循环内的语句,直到满足条件:

while (boolean expression) {

programming statement one;

programming statement two;

}

使用 while 循环结构对 for 循环进行编码,将 InvinciBagel 移动 40 个像素,如下所示:

int x = 0;

while (x < 40) {

invinciBagelX++;

invinciBagelY++;

x++

}

do-while 循环和 while 循环之间的唯一区别是,对于后者,循环逻辑编程语句是在计算之前而不是之后执行的。因此,使用 do-while 循环编程结构,前面的示例将编写如下:

int x = 0;

do {

invinciBagelX++;

invinciBagelY++;

x++

}``while

正如您所看到的,Java 编程逻辑结构在花括号内,跟在 Java do 关键字后面,在右花括号后有 while 语句。注意,while 求值语句(以及整个构造)必须以分号结束。

如果要确保 while 循环结构中的编程逻辑至少执行一次,请使用 do-while,因为求值是在循环逻辑执行之后执行的。如果您想确保循环中的逻辑只在计算成功后(无论何时)才执行,这是更安全的编码方式,请使用 while 循环结构。

Java 对象:虚拟现实,使用 Java 结构

我把最好的 Java 对象留到了最后,因为它们可以用一种或另一种方式使用我在这一章中介绍的所有概念来构造,还因为它们是 OOP 语言(在这种情况下,是 Java 8)的基础。事实上,Java 8 编程语言中的一切都是基于 Java 的 Object 超类(我喜欢称之为 masterclass),它在 java.lang 包中,因此它的 import 语句将引用 java.lang.Object,Java Object 类的完整路径名。

Java 对象是用来“虚拟化”现实的,它允许你在日常生活中看到的周围的物体,或者,在你的游戏中,你根据你的想象创造的物体,被逼真地模拟。这是通过使用数据字段(变量和常量)和您在本章中学习的方法来完成的。这些 Java 编程结构将组成对象特征或属性(常量);状态(变量);和行为(方法)。Java 类构造组织每个对象定义(常量、变量和方法),并使用类的构造函数方法生成该对象的实例,该类通过各种 Java 关键字和构造来设计和定义对象。

创建 InvinciBagel 对象:属性、状态和行为

让我们以 InvinciBagel 对象为例,展示常量如何定义特征,变量如何定义状态,方法如何定义行为。我们将使用到目前为止你在本章中学到的 Java 编码结构来完成这项工作,包括你已经在某种程度上定义的常量、变量和方法。

让我们从特征开始,特征是关于一个物体的不会改变的东西,因此可以用常数来表示,这些常数是不会(不能)改变的变量。百吉饼的一个重要特征是类型(风味)。我们都有自己的最爱;我的有原味、鸡蛋、黑麦、洋葱和粗面包。另一个特点是百吉饼的大小;众所周知,有迷你百吉饼,正常大小的百吉饼,还有巨型百吉饼。

private static final String FLAVOR_OF_BAGEL = "Pumpernickel";

private static final String SIZE_OF_BAGEL = "Mini Bagel";

因此,常量用于定义对象的特征或属性。如果您正在定义一辆汽车、一艘船或一架飞机,颜色(油漆)、引擎(类型)和传输(类型)是属性(常量),因为它们通常不会改变,除非您是一名机械师或拥有一家车身修理厂!

关于将改变的对象的事情,例如它的位置、方向、它是如何行进的(飞行、驾驶、行走、奔跑)等等,被称为状态,并且使用变量来定义,这些变量可以基于现实生活中正在发生的事情实时地不断改变。这些变量将允许任何 Java 对象模仿或虚拟化它们在 Java 世界的虚拟现实中创建的真实世界的对象。当然,在游戏中尤其如此,这也是为什么本书的主题《Java 和游戏》特别相关和适用的原因。

InvinciBagel 的状态(变量)会比属性(常量)多,因为它是游戏的一部分,会特别积极地试图挽救它的洞和得分。您想要定义为变量的一些状态包括屏幕(x,y)位置、方向、行进方向、行进类型、击中次数和使用寿命。

public int invinciBagelX = 0;                    // X screen location of the InvinciBagel

public int invinciBagelY = 0;                   //  Y screen location of the InvinciBagel

public String bagelOrientation = "side";       //   Defines bagel orientation (front, side, top)

public int lifeIndex = 1000;                  //    Defines units of lifespan used

public int hitsIndex = 0;                    //     Defines units of damage (hits taken)

public String directionFacing = "E";        //      Direction that the object is facing

public String movementType = "idle"        //  Type of movement (idle, fly, run, jump)

public boolean currentlyMoving = false;   //   Flag showing if the object is in motion

随着您继续阅读本书并创建 invincibegel 游戏,您将添加属性、状态和行为,使 invincibegel 及其游戏环境和游戏玩法更加逼真、有趣和令人兴奋,就像您在现实生活中所做的一样。事实上,您正在使用 Java 对象和 Java 构造来建模一个真实的虚拟世界,在这个世界中,InvinciBagel 玩家可以战胜邪恶,并向美味的目标发射奶油芝士球。

让我们来看几个控制 InvinciBagel 行为的方法。在本书的过程中,您将创建复杂的方法来完成游戏目标,因此我将在这里向您介绍方法如何为对象提供行为,以演示如何创建反映真实世界对象功能的对象。

对于您的 InvinciBagel 游戏,主要行为将是相对于 x(宽度)和 y(高度)维度在屏幕上的 2D 移动,这将访问、使用和更新整数 invinciBagelX、invinciBagelY 和前面讨论的布尔 currentlyMoving 数据字段;InvinciBagel 角色的方向(正面、侧面、朝下等),这将访问、使用和更新 bagelOrientation 字符串字段;InvinciBagel 的预期寿命,它将访问、使用和更新 lifeIndex 变量;InvinciBagel 的运行状况,它将访问、使用和更新 hitsIndex 变量。InvinciBagel 行进的方向(东或西),这将访问、使用和更新 directionFacing 字符串变量。以及 InvinciBagel 正在使用的运动类型(飞、跳、跑、闲),这将访问、使用和更新 movementType 字符串变量。

下面是如何声明这些方法(行为)以及关于它们将要做什么的伪代码:

public void moveInvinciBagel(int x, int y) {

currentlyMoving = true;

invinciBagelX = x;

invinciBagelY = y;

}

public String getInvinciBagelOrientation() {

return bagelOrientation;

}

public void setInvinciBagelOrientation(String orientation) {

bagelOrientation = orientation;

}

public int getInvinciBagelLifeIndex() {

return lifeIndex;

}

public void setInvinciBagelLifeIndex(int lifespan) {

lifeIndex = lifespan;

}

public String getInvinciBagelDirection() {

return directionFacing;

}

public void setInvinciBagelDirection(String direction) {

directionFacing = direction;

}

public int getInvinciBagelHitsIndex() {

return hitsIndex;

}

public void setInvinciBagelHitsIndex(int damage) {

hitsIndex = damage;

}

public String getInvinciBagelMovementType() {

return movementType;

}

public void setInvinciBagelMovementType(String movement) {

movementType = movement;

}

惯例是创建。get()和。set()方法,就像这里所做的那样。这些允许您的 Java 代码轻松访问您的对象状态(变量)。现在,是时候将所有这些属性(常量)、状态(变量)和行为(方法)安装到对象的蓝图中了。如前所述,这是使用 Java 类编程结构完成的。

创建无敌蓝图:创建游戏片类

让我们将所有这些 InvinciBagel 虚拟化代码安装到一个游戏片类中,以创建一个用于游戏片对象的类和构造函数方法:

public class GamePiece

private static final String FLAVOR_OF_BAGEL = "Pumpernickel"; // Flavor (or type) of bagel

private static final String SIZE_OF_BAGEL = "Mini Bagel";    // Size (classification) of bagel

public int invinciBagelX = 0;                    // X screen location of the InvinciBagel

public int invinciBagelY = 0;                   //  Y screen location of the InvinciBagel

public String bagelOrientation = "side";       //  Define bagel orientation (front, side, top)

public int lifeIndex = 1000;                  //   Defines units of lifespan used

public int hitsIndex = 0;                    //    Defines units of damage (hits taken)

public String directionFacing = "E";        //  Direction that the bagel object is facing

public String movementType = "idle";       //   Type of movement (idle, fly, run, jump)

public boolean currentlyMoving = false; //    Flag showing if the object is in motion

public void moveInvinciBagel(int x, int y) {        // Movement Behavior

currentlyMoving = true;

invinciBagelX = x;

invinciBagelY = y;

}

public String getInvinciBagelOrientation() {        // Get Method for Orientation

return bagelOrientation;

}

public void setInvinciBagelOrientation(String orientation) {     // Set Method for Orientation

bagelOrientation = orientation;

}

public int getInvinciBagelLifeIndex() {             // Get Method for Lifespan

return lifeIndex;

}

public void setInvinciBagelLifeIndex(int lifespan) {             // Set Method for Lifespan

lifeIndex = lifespan;

}

public String getInvinciBagelDirection() {          // Get Method for Facing Direction

return directionFacing;

}

public void setInvinciBagelDirection(String direction) {         // Set Method for Direction

directionFacing = direction;

}

public int getInvinciBagelHitsIndex() {             // Get Method for Hits (damage)

return hitsIndex;

}

public void setInvinciBagelHitsIndex(int damage) {           // Set Method for Hits (damage)

hitsIndex = damage;

}

public String getInvinciBagelMovementType() {         // Get Method for Movement Type

return movementType;

}

public void setInvinciBagelMovementType(String movement) {   // Set Method for Movement Type

movementType = movement;

}

}

值得注意的是,这些常量、变量和方法用于演示类、方法和数据字段关键字如何让开发人员创建(虚拟化)他们的游戏组件。随着游戏的开发,这些可能会改变,因为游戏开发是一个改进的过程,在这个过程中,您会不断地改变和增强 Java 代码库,以添加特性和功能。

现在,你所要做的就是添加你的 GamePiece()构造函数方法,这将创建一个新的对象,该对象具有你希望默认游戏块包含的初始化变量设置。然后,您将创建第二个重载构造函数方法。第二个构造函数方法将允许参数传递到构造函数方法中,以便您可以为这些相同的变量(状态)提供自定义(非默认)设置。这样,如果调用 GamePiece(),就得到一个默认对象;如果你调用 GamePiece(这里有参数列表),你会得到一个自定义对象。

创建一个 GamePiece()构造函数:重载一个 GamePiece

最后,让我们创建构造函数方法(实际上是两个),它从 GamePiece 类获取状态(变量)并创建一个默认对象。您将使用此对象创建自定义重载构造函数方法。第一个构造函数方法将使用包私有访问控制方法,不使用 access modifier 关键字,这样 invincibagel 包中的任何代码都可以调用这个构造函数方法。然后,您将使用以下 Java 代码设置默认变量:

GamePiece() {

invinciBagelX = 0;

invinciBagelY = 0;

bagelOrientation = "side";

lifeIndex = 1000;

hitsIndex = 0;

directionFacing = "E";

movementType = "idle";

currentlyMoving = false;

}

重载的构造函数方法将在方法参数列表区域为那些逻辑上允许对象创建时发生变化的变量声明参数。唯一不允许变化的两个变量是 hitsIndex(一个新对象不会有任何伤害点,因此需要为 0)和 currentlyMoving(一个新对象出现时不会移动,即使只是一秒钟的一部分),您将初始化这两个变量,就像您对默认构造函数所做的那样。其他五个变量(状态)将使用通过参数列表传递的参数来设置,使用一个等于赋值操作符。这是使用以下代码完成的:

GamePiece(int``x``, int``y``, String``orientation``, int``lifespan``, String``direction``, String``movement``) {

invinciBagelX =``x

invinciBagelY =``y

bagelOrientation =``orientation

lifeIndex =``lifespan

hitsIndex = 0;

directionFacing =``direction

movementType =``movement

currentlyMoving = false;

}

我在参数列表中加粗了变量,以及它们在构造函数方法中的使用位置,以设置对象的状态(变量)。这些变量是在 GamePiece 类的顶部声明的,您已经用它来设计、定义和创建 GamePiece 对象。第二个构造函数方法可以说是重载了第一个构造函数方法,因为它使用了完全相同的方法调用(方法名),带有不同的参数列表(充满参数,而不是空的或没有参数)。这给了你一个默认的对象构造方法和一个自定义的对象构造方法,所以在你的游戏逻辑中,你可以创建一个默认的或者自定义的游戏角色。

摘要

在第三章中,您了解了 Java 8 编程语言中一些更重要的概念和结构。当然,我不可能在一章中涵盖 Java 的所有内容,所以在本书的过程中,我坚持使用你将用来创建游戏的概念、构造和关键字。大多数 Java 书籍都有 800 页或更多,所以如果你想真正深入了解 Java,我建议从基肖里·莎兰的《Java 8 基础》开始(Apress,2014)。

您首先从 Java 的高级角度出发,考虑它的语法,包括 Java 注释和分隔符、API 以及 Java API 包含的 Java 包。您还学习了 Java 类,包括嵌套类和内部类,因为 Java 包包含 Java 类。然后你进入 Java 的下一个层次,到方法,就像其他编程语言中的函数,以及一种特殊的 Java 方法,叫做构造函数方法。

接下来,您探索了 Java 如何表示数据,使用字段或数据字段,研究了不同的类型,如常量、固定数据字段、变量或可以改变其值的数据字段。之后,您仔细查看了 Java 修饰符关键字,包括 public、private 和 protected 访问控制关键字,以及 final、static、abstract、volatile 和 synchronized 非访问控制修饰符关键字。

在完成了基本的代码结构以及如何修改它们之后,您转到了主要的 Java 数据类型,比如 boolean、char、byte、int、float、short、long 和 double,然后探索了用于处理这些数据类型或者将这些数据类型过渡到您的编程逻辑的 Java 操作符。您学习了算术运算符,用于数值;逻辑运算符,用于布尔值;关系运算符,用于考虑数据值之间的关系;条件运算符,允许您建立任何条件变量赋值;和赋值运算符,它们允许您为变量赋值(或在变量之间赋值)。

然后,您查看了 Java 逻辑控制结构,包括决策控制结构(我喜欢称之为决策树)和循环或迭代逻辑控制结构。您了解了 Java switch-case 结构、if-else 结构、for 循环结构和 do-while 循环结构。最后,您研究了 Java 对象,发现了如何使用 Java 类、方法和构造函数方法定义对象属性、状态和行为。

在下一章中,我将概述 JavaFX 多媒体引擎及其类和功能,因为您将利用 JavaFX 向游戏添加媒体元素,如图像、视频和音频,并使用 JavaFX 对象构造(类)控制游戏,如 Stage、Scene 和 StackPane。

四、JavaFX 8 简介:探索 Java 8 多媒体引擎的功能

让我们通过学习构成 JavaFX 8 多媒体引擎的功能、组件和类,在前面章节第四章中学习 Java 编程语言的知识。这个令人惊叹的 JavaFX 8 API 是使用 JavaFX 包添加到 Java 8 中的,你在第二章和第三章中看到了这个包,它是与 Java 8 一起发布的。JavaFX 8 包对游戏编程很重要,因为它包含了你想用于游戏编程的高级形式的类,包括使用场景图组织游戏组件的类;用户界面布局和设计的类;2D 数字插图类(也称为矢量图形);以及用于数字成像(也称为光栅图形)的类;2D 动画;数字视频;数字音频;3D;网络引擎(WebKit);还有更多,所有这些我都将在本章中介绍,这样您就可以确切地知道您可以得到什么,现在这些 JavaFX 8 库已经被添加到 Java 8 编程语言中了。

深入研究这些细节的理由不仅是为了让您知道 JavaFX 8.0 可以为您的 Java 8 游戏开发做些什么,而且是为了让您对这个 JavaFX 多媒体引擎的各个组件是如何组合在一起的有一个总体的了解。您将了解 JavaFX Quantum Toolkit、Prism 渲染技术、WebKit web 引擎、Glass Windowing Toolkit、音频和视频媒体引擎以及场景图形 API。

在您真正开始在游戏中使用 JavaFX 之前,您需要这份 Java FX 工作方式的高级概述,因为它是一组相当复杂的 API(我喜欢称之为引擎)。这是因为它为在 Java 8 应用(在这里是游戏)中实现用户界面(UI)和用户体验(UX)带来了强大的力量。因此,在这些基础章节中,请耐心听我讲述如何掌握您的 IDE (NetBeans 8.0)、编程语言(Java 8)以及这种新的媒体引擎(JavaFX 8),它现在是 Java 8 编程平台的一部分,在国际上的影响力和受欢迎程度都在快速增长。

一旦您研究了 JavaFX 8.0 是如何在最高级别上组合在一起的(就像您在第三章中所做的那样),您将考虑一些您可能用来构建 Java 8 游戏的关键类,例如 Node 类以及 Stage、Scene、Group、StackPane、Animation、Layout、Shape、Geometry、Control、Media、Image、Camera、Effect、Canvas 和 Paint 类。您已经学习了 JavaFX 应用类(参见第二章和第三章),所以现在您将重点关注可用于构建复杂多媒体项目的类,如 Java 8 游戏。

最后,您将深入了解您在第二章中生成的引导 JavaFX 应用,以及 Java。main()方法和 JavaFX。start()方法使用 Stage()构造函数方法创建 primaryStage Stage 对象,并在其中使用 scene()构造函数方法创建名为 Scene 的场景对象。您将探索如何使用 Stage 类中的方法来设置场景和标题并显示舞台,以及如何创建和使用 StackPane 和 Button 类(对象),并向按钮添加 EventHandler。

JavaFX 概述:从场景图到操作系统

和上一章一样,在 Java 8 上,我从最高级别的 JavaFX 开始这个概述,使用场景图形 API 和可视化编辑工具,它们包含在一个名为 Scene Builder 的 JavaFX 应用中,我们不会使用它(Scene Builder 是用于应用 UI 设计而不是游戏设计的);我们将使用 GIMP 来代替。正如您在第一章中所观察到的那样(参见图 1-5),Scene Builder 集成到了 NetBeans 8.0 中(JavaFX 被列为专门支持在 NetBeans 中使用,主要是因为 Scene Builder 已经成为 NetBeans GUI 的一个组成部分)。

如图 4-1 所示,这些 JavaFX 应用构建工具存在于 JavaFX 8 API(Java FX 包的集合,如 javafx.scene 和 javafx.application)的“顶部”,这最终允许您构建(使用场景图)和 UI 设计(使用场景生成器)您的 Java FX 新媒体作品(在本例中,是 Java 8 游戏)。请注意,JavaFX 8.0 API 不仅连接(这里使用钢轴承来表示插头)到它上面的场景图形和场景生成器,还连接到它下面的 Java JDK 8 和 Quantum 工具包。正如您所看到的,Java JDK 8(和 API)然后将 JavaFX 新媒体引擎连接到 NetBeans、JVM 和 Java 当前支持的各种平台以及未来的平台,如 Android 4 (32 位 Android)、Android 5 (64 位 Android)和 iOS。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-1。

How JavaFX 8 is stratified, from the Scene Graph at the top down through Java 8, NetBeans 8.0, JVMs, and OSs

Quantum Toolkit 连接到 JavaFX 8.0 API,将您将要学习的所有强大的新媒体引擎联系在一起。Quantum Toolkit 还处理所有这些的线程管理,因此您的游戏代码和游戏的新媒体(音频、视频、3D 等)可以在双核、四核、六核和八核 CPU 上使用单独的处理器,这些处理器在当今的计算机和消费电子设备中非常常见。

Glass Windowing Toolkit 控制 JavaFX 8.0 的窗口管理,并负责显示屏上的所有离散区域,如舞台和弹出窗口,包括对话框。Glass 还管理事件处理队列,将事件传递给 JavaFX 进行处理,并设置计时器。

如图所示,还有一个 WebKit 引擎和一个媒体(播放器)引擎,由 Quantum Toolkit 管理。WebKit 引擎呈现您的 HTML5 和 CSS3 web 内容,媒体播放器媒体播放引擎分别播放您的数字音频和数字视频资产。

Quantum Toolkit 下面最重要的新媒体引擎是 Prism(游戏)引擎,它使用 Java 2D 渲染 2D 内容,如果您的用户使用 Windows Vista、Windows 7 或 Windows 8.1 平台,则使用 OpenGL (Mac、Linux、嵌入式操作系统)或 DirectX 渲染 3D 内容。Windows XP 支持于 2014 年 4 月停止,因为现在大多数计算机和消费电子设备都支持 64 位(XP 仅为 32 位)。

Prism 桥接了主要操作系统平台和消费电子(嵌入式)设备上的强大 3D 游戏引擎(DirectX、OpenGL ),因此 JavaFX 8.0 可以将复杂的渲染任务处理从 NVIDIA (GeForce)、AMD (ATI 镭龙)和英特尔卸载到图形处理单元(GPU)硬件。这使得 JavaFX(以及 Java 8)游戏速度更快,并允许游戏使用更少的 CPU 处理能力来将游戏资产渲染到屏幕上。这反过来允许更多的 CPU 处理能力用于游戏逻辑,如人工智能和碰撞检测。在本书的第四章中,当你掌握了 JavaFX 引擎之后,你将会学到游戏设计的这些领域。

值得注意的是,游戏开发人员不需要了解 Quantum(线程)、Glass(窗口)或 Prism(渲染)引擎的内部工作原理,就可以利用它们惊人的强大功能。在整本书中,您将关注图的顶层(场景图和场景生成器)以及 JavaFX 和 Java 8 API 层。我还将介绍 NetBeans IDE 8.0 级别,您将在第二章中了解到这一级别,但您也将在本书的剩余部分进一步探索这一级别。

至于图中的较低层,NetBeans 8.0 将生成一个 Java 字节码文件,供每个操作系统平台的定制 JVM 读取。图底部所示的 JVM 可以通过下载 Java 8 JRE 安装在任何给定的操作系统平台上,你已经在第一章中遇到过,当你把它作为 Java JDK 8 的一部分安装时。

这个 JVM 层允许你的游戏作为一个应用安装在所有流行的操作系统平台和嵌入式设备上,这些设备也支持 JavaFX 8。此外,您可以将您的 Java 8 游戏生成为一个 Java applet,它可以嵌入到一个网站中,甚至还有一个部署模型,在该模型中,应用可以从网站拖到您的桌面上,在那里它被安装为一个完整的 Java 8 应用。

此外,已经有一种方法可以在 iOS 8 以及 Android 4.4 和 5.0 上运行 JavaFX 8 应用。如果你对这方面的最新信息感兴趣,只需谷歌“Android 上的 JavaFX”或“iOS 上的 Java FX”;你可以打赌,到 2015 年,Android 5.0 和 Chrome OS 设备将“本机”运行 JavaFX 应用,这意味着有一天(很快)你将能够使用 IntelliJ 直接将 Java(和 JavaFX 引擎)应用导出到 Android 5.0,或使用 NetBeans 8.0 导出到 Chrome OS。有了这个 Java 8 和 JavaFX 8.0 动态组合,您最终将能够“一次编码,随处运行”!Oracle 最近发布了 Java 8 SE Embedded、Java 8 ME 和 Java 8 ME Embedded 版本,都支持 JavaFX。

Note

JetBrains IntelliJ IDEA 现在是用于创建 64 位 Android 5.0 应用的官方 IDE。这个 IDE 在我的 Android Apps for Absolute 初学者,第三版(Apress,2014)中进行了讨论,其中包括使用 Eclipse IDE 和 Java 6 开发 32 位 Android 4.0 应用,以及使用 IntelliJ IDEA 和 Java 7 开发 64 位 Android 5.0 应用。

让我们从图的顶部开始,看一下 JavaFX 场景图和 javafx.scene 包,它在 JavaFX API 中实现了场景图(下一章将介绍 Scene Builder)。

JavaFX 场景包:16 个核心 Java 8 类

在我们的高级概述之后,我想做的第一件事是介绍最重要的 JavaFX 包之一,javafx.scene 包。在第二章和第三章中,你会发现不止一个 JavaFX 包。正如你在第三章(见图 3-1)中看到的,InvinciBagel 游戏应用使用了四个不同的 JavaFX 包。javafx.scene 包包含 16 个强大的 Java 8 类(记住,javafx 是在 Java 8 中重新编码的),包括 Camera、ParallelCamera 和 PerspectiveCamera、Cursor 和 ImageCursor、LightBase、PointLight 和 AmbientLight 类;场景图类(节点、父、组和子场景);以及一些实用程序类(见图 4-2 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-2。

The javafx.scene package and its 16-core Scene Graph, Scene utility, Lighting, Camera, and Cursor classes

我对这 16 个 javafx.scene 包类进行了逻辑分组。Scene 类位于图的 Scene Graph 部分,因为使用 Scene 类创建的 Scene 对象包含 Scene Graph 对象,这些对象是使用这四个与 Scene Graph 相关的类(Node、Parent、Group、SubScene)及其子类创建的。我将在本章后面详细介绍场景图类(参见“JavaFX 场景图:组织场景,使用父节点”一节)

JavaFX 中的场景图架构类从最高级别开始,有一个节点超类及其父类,包括 Group 和 SubScene 类,它们是父类的子类。这些核心类用于创建 JavaFX 场景图形层次结构,以及组织和分组使用 JavaFX 包中的其他 JavaFX 类创建的对象。

有三个我称之为场景实用程序的类,它们允许你在任何时候对你的场景或它的任何场景图节点进行快照(像截图一样),如果你在一个场景中使用 3D 基本体的话,还可以打开和关闭场景初始化。javafx.scene 包中的另一半(八个)类用于场景照明、场景摄影机和场景的光标控制。我将在本章后面讨论这些类(参见“JavaFx 场景内容:灯光、摄像机、光标、动作!”),在您看了场景图类之后,这些类创建、分组、管理和操作 JavaFX 场景内容。因此,我将按照您最有可能使用 javafx.scene 包的顺序,从图的左侧到右侧,从最少到最多,介绍图中所示的 Java FX . scene 包类。

JavaFX 场景类:场景大小和颜色以及场景图形节点

javafx.scene 包中的两个主要类是 scene 类和 Node 类。我将在下一节介绍 Node 类及其父类、组类和子场景子类,因为这些类及其子类(如 InvinciBagel 类中使用的 StackPane 类)用于实现 JavaFX 中的场景图架构。此外,在某种意义上(在我的图中), Node 类及其子类可以被视为在 Scene 类之下,尽管 Node 类不是 Scene 类的子类。事实上,节点(场景图)类和子类,或者说使用这些类创建的对象,包含在场景对象本身中。

因此,您将首先考虑如何使用 Scene 类及其 Scene()构造函数方法为 JavaFX 应用创建场景对象。本节将强化你在第三章学到的关于重载构造方法的知识,因为创建一个场景对象需要几种不同的方法。

Scene 类用于创建一个 Scene 对象,使用 Scene()构造函数类,根据您选择使用六个(重载的)构造函数方法中的哪一个,该类使用一个到五个参数。这些方法包括以下构造函数方法,以及它们的六种不同的(因此也是重载的)参数列表数据字段配置:

Scene(``Parent

Scene(``Parent``root,``double``width,``double

Scene(``Parent``root,``double``width,``double``height,``boolean``depthBuffer)

Scene(``Parent``root,``double``width,``double``height,``boolean``depthBuffer,``SceneAntialiasing``aAlias)

Scene(``Parent``root,``double``width,``double``height,``Paint``fill)

Scene(``Parent``root,``Paint

当前在您的引导 Java 和 JavaFX 代码中使用的构造函数是第二个,调用如下:

Scene scene =``new

如果您想给场景添加黑色背景,您可以选择第五个重载的构造函数方法,使用一种颜色。Color 类中的 BLACK 常量(这是一个 Paint 对象,因为 Color 是 Paint 子类)作为填充数据(在本例中为填充颜色)。您可以通过使用以下 Scene()对象构造函数方法调用来实现这一点:

Scene scene =``new``Scene(root, 300, 250,``Color.BLACK

请注意,根对象是一个父子类,称为 StackPane 类,它是使用 StackPane()构造函数方法(在 Scene()构造函数方法调用上方两行)通过使用以下 Java 代码行创建的:

StackPane root =``new

正如您所看到的,任何类都可以在构造函数中使用,只要它是为该构造函数参数位置(数据)声明(必需)的对象(类)类型的子类。您可以在参数列表中使用 Color 和 StackPane 对象,因为它们分别来自 Paint 和 Parent 类。

如果您想知道,布尔 depthBuffer 参数用于 3D 场景组件。因为这些场景组件是 3D 的并且具有深度(除了 2D x 和 y 组件之外,还有一个 z 组件),所以如果要创建 3D 场景或组合 2D 和 3D 场景组件,则需要包含此参数,并将其设置为 true 值。最后,在第四个构造函数方法的参数列表中传递的 SceneAntialiasing 对象(和类)为 3D 场景组件提供实时平滑。

JavaFX 场景图:组织场景,使用父节点

场景图不是 JavaFX 独有的,在很多新媒体内容创作软件包中都可以看到,它是一种类似倒置的树的数据结构,根节点在顶部,分支节点和叶节点从根节点开始。我第一次看到场景图设计方法是在我使用 Realsoft Oy 的名为 Real 3D 的 Amiga 软件包进行 3D 建模的时候。从那时起,这种方法被许多 3D、数字视频和数字图像软件包复制,现在是 JavaFX 组织内容和场景的一部分。出于这个原因,你们中的许多人可能对这种设计范例很熟悉(也很舒服)。

JavaFX 场景图数据结构不仅允许您设计、组织和设计 JavaFX 场景及其内容,而且如果您正确设置了场景图,还可以将不透明度、状态、事件处理器、变换和特殊效果应用于场景图层次的整个逻辑分支。图 4-3 是基本的场景图树,顶部是根节点,下面是分支和叶子节点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-3。

JavaFX Scene Graph hierarchy, starting with the root node and progressing to branch and leaf nodes

根节点是最顶端的节点,这就是为什么它被称为根,即使它在顶部,而不是底部,就像植物世界中的根一样。根节点没有父节点,也就是说,在场景图形层次中,它上面没有任何东西。根节点本身是其下的分支节点和叶节点的父节点。

场景图树中第二个最强大(也是最复杂)的结构是分支节点,它使用 javafx.scene.Parent 类作为其超类,并且可以包含子类(这是合乎逻辑的,因为它扩展了一个名为 Parent 的类)。分支节点可以包含其他分支节点以及叶节点,因此它可以用于创建一些非常复杂和强大的场景图层次结构(或场景图架构)。

层次结构中的最后一级是叶节点。叶节点是分支的末端,因此不能有子节点。值得注意的是,叶节点可以直接脱离根节点,如图 4-3 所示。可以使用父类、组类或子场景类(见图 4-2 )或它们的任何子类来创建分支节点,例如 WebView、PopupControl、Region、Pane 或 StackPane 类。

叶节点的示例包括 JavaFX 类(作为对象),这些类可以使用参数(如形状、文本或 ImageView)进行配置,但它们本身是设计或内容组件,并且没有被设计为具有子级(子对象)。

因此,在 JavaFX 场景图层次结构中,叶节点将始终包含一个 JavaFX 类,该类没有从父类子类化(扩展),并且其本身也没有被专门设计为在其中或其下具有子元素(子对象)。

父类的四个子类都可以用作分支节点,包括 Group 类,用于对子(叶节点)对象进行分组,以便可以对它们应用不透明度、变换和效果;Region 类,用于将子(叶节点)对象分组以形成屏幕布局,这也可以使用 CSS 来设置样式;Control 类,可用于创建自定义用户界面元素(JavaFX 中称为控件);以及 WebView 类,用于包含 JavaFX WebEngine 类(该类将 HTML5 和 CSS3 内容呈现到 WebView 中)。

JavaFX 场景内容:灯光,摄像机,光标,动作!

接下来,我们来看看图 4-2 中列在中间一栏的八个类。它们提供了强大的多媒体工具来控制您的应用的光标,并为您的 2D 和 3D JavaFX 应用(在这种情况下,是游戏,但也可以是电子书、iTV 节目或任何其他需要 JavaFX 通过 Java 语言提供的强大新媒体功能的内容)提供定制的灯光特效和定制的相机功能。

图中更一般化的类(Cursor、LightBase、Camera)是父类,更专门化的类(ImageCursor、PointLight、ParallelCamera 等)列在每个类之后,是这些父类的子类。除了 LightBase 类,这似乎是显而易见的!

正如您可能已经猜到的(正确),JavaFX Cursor 类可用于控制在任何给定时间使用的应用光标图形(箭头、手形、闭合的手形、十字准线等)。ImageCursor 子类可用于定义和提供基于图像的自定义光标以及自定义光标图像中的 x 和 y 位置,该位置定义了光标点(也称为光标热点)的位置。

LightBase 类及其 PointLight 和 AmbientLight 子类可用于照亮场景。这些类主要用于 3D 场景,它们需要在游戏运行的任何平台上具有 3D 功能,这在当今并不是一个真正的问题,因为大多数主要的 CPU 制造商也制造(并包括)GPU。此外,值得注意的是,如果渲染游戏的平台上没有 3D 处理模拟,Prism 游戏引擎将使用 3D 处理模拟来模拟 3D 环境(GPU)。此外,如果你设置正确,你可以在你的 2D 游戏中使用光照类,或者在混合 2D 3D 游戏中使用光照。

Camera 类及其 ParallelCamera 和 PerspectiveCamera 子类可用于在 3D 和 2D(以及混合)游戏应用中拍摄或录制场景。其中两个相机类 camera 和 ParallelCamera 不要求在运行 JavaFX 应用(在本例中为游戏)的平台上具备 3D (GPU)功能。

Camera 类的子类提供了两种不同的专用类型的摄像机。ParallelCamera 类可用于渲染场景,无需任何深度透视校正,这在 3D 行业中称为正交投影。这意味着这个类非常适合用于 2D 场景(和 2D 游戏)。

PerspectiveCamera 类有一个更复杂的相机,用于 3D 场景,它将支持 3D 查看量。与 LightBase 类及其子类一样,PerspectiveCamera 类需要在运行应用(或游戏)的硬件平台上具有 3D 功能。

PerspectiveCamera 类有一个 fieldOfView 属性(state 或 variable),可以用来改变它的查看体积,就像一个真正的相机变焦镜头,当你从广角放大它的时候。fieldOfView 属性的默认设置是 30 度的锐角。如果你还记得你高中时的几何,你可以通过向下看相机的 y(垂直)轴来想象这个视野。如你所料,确实有。getFieldOfView()和。setFieldOfView(double)方法调用来控制此摄像机类属性。

接下来,让我们仔细看看场景实用程序类。之后,您将检查一些 javafx.scene 子包,例如 javafx.scene.text、javafx.scene.image、javafx.scene.shape 和 javafx.scene.layout。

JavaFX 场景工具:场景快照和抗锯齿

最后,您应该快速查看一下图 4-2 中右栏所示的三个实用程序类,因为它们可用于提高用户设备屏幕上的场景输出质量(使用抗锯齿),以及为您的用户(用于社交媒体共享)或您的游戏逻辑本身提供屏幕捕捉功能。

我们先来考察一下 SceneAntialiasing 类。抗锯齿是一个数字图像行业术语,指的是一种平滑两种颜色交汇处锯齿状边缘的算法,通常位于对角线上或图像合成的圆形区域中。图像合成是将两个独立的图像分层放置以形成一个图像。有时,这两个(或更多)图像层的图像组件之间的边缘需要平滑。平滑(抗锯齿)是必需的,以便最终的合成看起来是一个无缝的图像,这是艺术家或游戏设计师的意图。有趣的是,您已经使用 StackPane 类(窗格是层)在 InvinciBagel 应用中实现了 JavaFX“层引擎”。“层叠”图像合成方法在游戏和软件中很常见,如 Photoshop 和 GIMP。

SceneAntialiasing 类为 3D 场景提供抗锯齿处理(算法),以便可以在 2D 场景背景上合成 3D 场景,无论这是默认颜色。白色或任何其他颜色值;2D 图像(创建混合的 2D-3D 应用);或者其他任何事。scene aliasing 类允许您将静态 scene aliasing 数据字段设置为 DISABLED(关闭抗锯齿)或 BALANCED(打开抗锯齿)值。平衡选项提供了质量和性能的平衡,这意味着设备硬件的处理能力越强,处理的抗混叠质量就越高。

接下来,让我们探索 SnapshotParameters 类(object),它用于设置(包含)将由 SnapshotResult 类(object)使用的渲染属性参数。这些参数包括要使用的相机对象的类型(平行或透视);depthBuffer(用于 3D)是打开的(对于 3D 为真)还是关闭的(对于 2D 为假);一个画图对象,用于包含图像数据;一个转换对象,用于包含任何转换数据;和 Rectangle2D 对象,用于定义要渲染的视口区域(即快照尺寸)。

您将在本章中看到所有这些 javafx.scene 子包类和概念,并在本书的课程中使用它们中的许多。您将在 Java 8 游戏开发中使用的许多功能都可以在这些 JavaFX 8.0 子包中找到。

SnapshotResult 类(更重要的是,使用该类创建的对象)包含生成的快照图像数据、生成该数据的参数以及生成该数据的场景图中的源节点。因此,该类支持的三种方法应该是显而易见的。getImage()方法将获得快照图像。getSource()方法获取源节点信息,而。getSnapshotParameters()方法将获取 SnapshotParameters 对象内容。

场景子包:其他 13 个场景包

你可能在想,“咻!javafx.scene 包概述中包含了很多内容!,“而且确实核心的 javafx.scene 包里面有很多类,涵盖场景创建;场景图组织;以及场景实用工具,比如灯光、相机、光标、截图(或者我们应该称这些为 sceneshots?).在 javafx.scene 包中,在我所称的子包中,或者在 javafx.scene 包下面的包中,有更多的内容,使用另一个点和另一个包名(描述)来引用。事实上,还有 13 个 javafx.scene 包(见表 4-1 ),涵盖了绘图、绘画、图表、UI 设计、成像、特效、媒体(音频和视频)回放、输入输出、文本、形状(2D 几何)、变换和网页(用 HTML5、JavaScript 和 CSS3 创建的内容)呈现等内容。在本节中,您将探索这些场景包类。

表 4-1。

Thirteen Second-Level JavaFX Scene Subpackages, Their Primary Functions, and a Description of Classes

包名功能内容描述
javafx.scene .画布图画画布类(和画布对象);对于自定义绘图图面
javafx.scene.chart制图图表类:饼图、折线图、XYChart、条形图、面积图、气泡图
javafx .场景.控件用户界面控件UI 控件类:按钮、菜单、滑块、标签、滚动条、文本字段
javafx.scene.effect特技特殊效果类:发光,混合,开花,阴影,反射,运动模糊
javafx.scene.image成像数字图像类:图像、图像视图、可写图像视图、像素格式
javafx.scene.input输入(事件)与将用户输入获取到 JavaFX 应用相关的类
javafx.scene.layoutUI 布局UI 布局容器类:TilePane、GridPane、FlowPane、Border
javafx.scene.media媒体播放机媒体播放类:MediaPlayer、MediaView、Track、AudioTrack、AudioClip
javafx.scene.paint绘画绘画类:绘画、颜色、线性渐变、径向渐变、停止、材质等等
javafx.scene.shape几何学2D 和 3D 几何类:网格、形状、Shape3D、圆弧、圆、直线、路径等
javafx.scene.text文本和字体文本呈现和字体呈现类:字体、文本、文本流等等
javafx.scene.transform转换变换类:变换,缩放,旋转,剪切,平移,仿射
javafx.scene.webWebKitWeb 支持类:WebView、WebEvent、WebEngine、HTMLEditor

让我们从类最少的包开始。该表按字母顺序列出了子包,但是第一个子包 javafx.scene.canvas 恰好只包含一个类,canvas 类,顾名思义,它用于创建一个 Canvas 对象,该对象用作画布,您可以用它来创建东西!列出的下一个子包是 Java FX . scene . chart;这本书有图表类,如饼图、折线图、XYChart、条形图、面积图和 BubbleChart,供业务应用使用,这是完全不同的一本书,所以我将不讨论图表。

下一个子包 javafx.scene.control 提供了所有的 UI 控件(Android 中的 widget)类,比如 Button、Menu、CheckBox、RadioButton、DatePicker、ColorPicker、ProgressBar、Slider、Label、Scrollbar、TextField 和其他 80 多个类。因为 javafx.scene.control 中大约有一百个类,所以我甚至不打算在这里介绍它;关于这个子包,可能可以写一整本书!如果您想复习这些类,只需在 Google 或 Oracle Java 网站上参考“javafx.scene.control ”,您就可以连续几天仔细阅读这些类能做什么。对于这个子包,“reference”是关键词,因为当您需要实现一个给定的 UI 元素时,您会希望单独引用这个包及其类。

下一个子包 javafx.scene.effect 提供了所有的特效类,差不多有 24 个。这些对于 Java 8 游戏开发非常有用,因此这是我将在本节中详细介绍的少数几个子包之一。

javafx.scene.image 子包用于在 javafx 中实现数字影像,它包含 image、ImageView、WritableImage、PixelFormat 和 WritablePixelFormat 类。ImageView 类是您通常用来保存数字图像资产的类,如果您想要进行更高级的(算法)基于像素的数字图像创建,则更高级的 PixelFormat 类允许您逐个像素地创建数字图像。

javafx.scene.input 子包包括用于从 javafx 应用的用户获取输入的类。这个输入使用事件处理能力进行处理,你将在本书的课程中详细研究,并且你已经在你的 JavaFX 应用中体验过了,在第三章(见图 3-2,ll。第 22 至 24 页)。

javafx.scene.layout 子包包含用于创建 UI 设计布局以及用于屏幕布局设计的类。这些布局类包括控制和管理背景的类;添加边框并设置其样式;并提供 UI 窗格管理,如 StackPane、TilePane、GridPane、FlowPane 和 AnchorPane。这些 UI 类为 JavaFX 中的 UI 控件提供了自动屏幕布局算法。Background 类(及其子类)提供了屏幕背景实用程序,Border 类(及其子类)提供了屏幕边框实用程序,可用于为 UI 屏幕增加图形设计的趣味。

javafx.scene.media 子包包含用于播放音频或视频媒体的类,包括 media、MediaPlayer 和 MediaView 类。媒体类(实际上是对象)引用并包含媒体(音频或视频)资产,MediaPlayer 播放该资产,MediaView(对于视频)显示该资产。这个子包还有一个 Track 超类和 AudioTrack、VideoTrack、SubtitleTrack 子类,以及 AudioClip、AudioEqualizer 和 EquilizerBand 类,它们提供高级音频(均衡器)控件和短格式音频剪辑,或非常适合在游戏中使用的音频片段。你将在本书的后面使用 AudioClip 类(见第一章 5)。

javafx.scene.paint 子包包含 Stop 类和 paint 超类及其 Color、ImagePattern、LinearGradient 和 RadialGradient 子类,以及 Material 超类及其 PhongMaterial 子类。熟悉 3D 内容制作的人会认识这种 Phong 着色器算法,它允许模拟不同的表面外观(塑料、橡胶等)。Material 和 PhongMaterial 类需要 3D 功能才能在播放硬件上成功运行,就像 SceneAntialiasing、PerspectiveCamera 和 LightBase 类(及其子类)一样。Paint 类创建您的 Paint 对象,Color 类为该对象着色(用一种颜色填充它),LinearGradient 和 RadialGradient 类用颜色渐变填充 Paint 对象,Stop 类允许您定义渐变颜色在渐变中的开始和停止位置。最后,还有一个 ImagePattern 类,它可以用可平铺的图像模式填充 Paint 对象(这对游戏非常有用)。

javafx.scene.shape 子包为 2D 几何图形(通常称为图形)和 3D 几何图形(通常称为网格)提供了类。Mesh 超类及其 TriangleMesh 子类处理 3D 几何,Shape3D 超类及其 Box、Sphere、Cylinder 和 MeshView 子类也是如此。形状超类有更多的子类(11);这些是 2D 几何元素,包括圆弧、圆、三次曲线、椭圆、直线、路径、多边形、折线、四次曲线、矩形和 SVGPath 类。PathElement 超类及其 ArcTo、ClosePath、CubicCurveTo、HLineTo、LineTo、MoveTo、QuadCurveTo 和 VLineTo 子类也提供了路径支持,即定义为开放形状的路径(我喜欢称之为样条曲线,因为我是 3D 建模师),它允许您绘制样条曲线来创建自己的自定义形状!

javafx.scene.text 子包包含将文本形状和字体渲染到场景中的类。这包括 Font 类和 Text 类,前者用于使用您可能想要使用的任何非 JavaFX 系统字体的字体,后者用于创建一个将使用该字体显示文本值的文本节点。还有一个专门的布局容器类,称为 TextFlow,用于流动文本,就像您在文字处理器上看到的那样。

javafx.scene.transform 子包提供了用于渲染 2D 和 3D 空间变换的类,例如 transform 超类的 Scale、Rotate、Shear、Translate 和 Affine (3D rotation)子类。这些可以应用于场景图中的任何节点对象。这允许您的场景图中的任何内容(文本、UI 控件、形状、网格、图像、媒体等等)以您喜欢的任何方式进行转换,这为 JavaFX 游戏开发人员提供了大量的创造力。如果你想知道,平移是整个物体的线性运动;剪切是 2D 平面上两个不同方向的线性运动,或者是 2D 平面的另一部分固定时的一个方向的运动。想象移动一个平面的顶部,而底部保持固定,这样正方形就变成了平行四边形,或者向不同方向移动同一平面(正方形)的顶部和底部。

javafx.scene.web 子包提供了用于将 web 资源渲染到场景中的类,使用了一组类,包括 WebView、WebEvent、WebEngine、WebHistory 和 HTMLEditor。正如您可能想象的那样,WebEngine(请参阅,其他人也称之为引擎)类在 JavaFX 中执行显示 HTML5 + CSS3 + JS 的处理,WebView 类创建用于在场景图中显示 WebEngine 输出的节点。WebHistory 类(最终是对象)保存所访问网页的会话历史(从 WebEngine 实例化到从内存中删除), WebEvent 将 JavaScript web 事件处理与 JavaFX 事件处理联系起来。

既然您已经查看了 javafx.scene 包及其相关子包中大量重要且有用的类(对象),那么让我们来看看 15 个顶级 javafx 包,以便更好地了解 JavaFX 为应用开发提供的关键功能(当然,重点是那些可用于游戏开发的功能)。

其他 JavaFX 包:15 个顶级包

有 15 个顶级包(javafx.packagename 是我认为的顶级包),其中一些包也有子包级别,就像您看到的 javafx.scene 包和子包一样。表 4-2 概述了这些包装并描述了其内容。

表 4-2。

JavaFX Top-Level Packages, Their Primary Functions, and a Description of Their Functional Classes

包名功能内容描述
javafx.animation动画时间轴,转场,动画计时器,插值器,关键帧,键值
javafx .应用应用应用(初始化、启动、停止方法)、预加载程序、参数、平台
javafx.beansJavaFX beans定义最一般形式的可观察性的 Java 接口
javafx.collections收集定义最一般形式的可观察性的 Java 集合
javafx.concurrent穿线线程类:任务、服务、计划服务、工作状态事件
javafx.css半铸钢ˌ钢性铸铁(Cast Semi-Steel)与在 JavaFX 中实现 CSS 相关的类
javafx.embed使…嵌入嵌入废弃的 Java Swing 和 Java AWT GUI 范例
javafx.event事件处理器事件处理类:Event、ActionEvent、EventType、WeakEventHandler
javafx.fxml断续器断续器
javafx.geometry3D 几何图形3D 几何类
javafx.print印刷打印类别
javafx.scene场景控制与场景创建、组织、控制和实现相关的课程
javafx.stage舞台创作舞台创作课
javafx.utilJavaFX 实用程序JavaFX 实用程序类
netscape.javascriptJava Script 语言允许 Java 代码调用 JavaScript 方法并检查 JavaScript 属性

我已经讨论过其中的一些,比如 javafx.application 包(参见第二章和第三章)和 javafx.scene 包(参见“JavaFX Scene 包:十六个强大的 Java 8 类”一节)。这里有几个其他的 JavaFX 包您应该仔细看看,因为它们(和 javafx.scene 包一起)包含了您想要在 Java 8 游戏开发中使用的类(还有其他的,比如 javafx.print、javafx.fxml、javafx.beans 和 javafx.embed 包不太可能在您的 Java 游戏设计和开发工作过程中使用);它们是 javafx.animation、javafx.stage、javafx.geometry、javafx.concurrent 和 javafx.event,接下来让我们深入看看这些包为您的游戏开发目标提供了什么。

游戏的 JavaFX 动画:使用 javafx.animation 类

javafx.animation 包包含 animation 超类,该超类包含 Timeline 和 Transition 子类以及 AnimationTimer、Interpolator、KeyFrame 和 KeyValue 类。动画是 Java 8 游戏中一个重要的设计元素,多亏了 JavaFX,这些动画类已经为我们编码好了,所以你所要做的就是正确地使用它们来为你的游戏添加动画!

JavaFX Animation 类:动画对象的基础

Animation 类(实际上是对象)提供了 JavaFX 中动画的核心功能。Animation 类包含两个(重载的)Animation()构造函数方法;它们是 Animation()和 Animation(double target frame rate),它们将在内存中创建动画对象,该对象将控制动画及其播放特征和生命周期。

动画类包含。play()方法。playFrom(cuePoint)或。playFrom(持续时间)方法和. playFromStart()方法。这些方法用于开始播放动画对象。也有。pause()方法可以暂停动画播放,而. stop()方法可以停止动画播放。那个。jumpTo(持续时间)和。jumpTo(cuePoint)方法用于跳转到动画中预定义的位置。

您可以使用 rate 属性设置动画播放速度(也称为帧速率或每秒帧数[FPS])。cycleCount 属性(变量)允许您指定动画循环的次数,delay 属性允许您指定动画开始前的延迟时间。如果动画正在循环,此延迟属性将指定循环之间的延迟时间,这可以帮助您创建一些逼真的效果。

您可以通过将 cycleCount 属性或特性(变量)设置为不定,然后使用 autoReverse 属性(设置为 false)来指定无缝动画循环,也可以通过为 autoReverse 属性指定 true 值来使用 pong(来回)动画循环。如果不希望动画无限循环,也可以将 cycleCount 设置为一个数值(如果希望动画只播放一次,请使用 1)。

那个。setRate()方法设置动画播放速率属性。setDelay()方法设置 Delay 属性,而。setCycleCount()和。setCycleDuration()方法控制循环特性。也有类似的。get()方法来“获取”这些动画对象变量(特性、属性、参数或特征;但是您更喜欢查看这些数据字段是可以的)。

使用 ActionEvent 对象加载的 onFinished 属性,可以指定动画播放完成时要执行的动作。当动画到达每个循环的结尾时,动作将被执行,正如你可以想象的那样,一些非常强大的东西可以在具有这种特定功能的游戏中被触发。

还有只读变量(属性),您可以随时“轮询”这些变量,以找到每个动画对象的状态、当前时间、当前速率、循环更新和总持续时间。例如,可以使用 currentTime 属性查看动画播放周期中任何时间点的播放头(帧指针)位置。

JavaFX TimeLine 类:用于属性时间轴管理的动画子类

JavaFX Timeline 类是 JavaFX Animation 超类的子类,因此它的继承层次结构从 Java 8 master class Java . lang . object 开始,向下发展到 Timeline 类,如下所示:

> java.lang.Object

> javafx.animation.Animation

> javafx.animation. Timeline

Timeline 对象可用于定义一种特殊的动画对象,该对象由对象类型 WritableValue 的 JavaFX 值(属性)组成。因为所有的 JavaFX 属性都是这种类型,所以这个类可以用来制作 JavaFX 中任何东西的动画,这意味着它的使用只受您的想象力的限制。

如前所述,时间轴动画是使用通过 KeyFrame 类创建的 KeyFrame 对象定义的,key frame 类既创建又管理这些对象。根据时间变量(通过 KeyFrame.time 访问)和要设置动画的属性(使用 KeyFrame 对象的 values 变量(通过 KeyFrame.values 访问)定义),由时间轴对象处理 KeyFrame 对象。

请务必注意,您需要在开始运行时间轴对象之前设置关键帧对象,因为您不能在正在运行的时间轴对象中更改关键帧对象。这是因为一旦启动,它就会被放入系统内存中。如果您想以任何方式更改正在运行的时间轴对象中的关键帧对象,首先,停止时间轴对象;然后,对关键帧进行更改;最后,再次启动时间轴对象。这将使用新值将时间轴对象及其修订的关键帧对象重新加载到内存中。

Interpolator 类根据时间轴方向在时间轴对象中插入这些 KeyFrame.values。插值是根据开始值和结束值创建中间(或补间)帧的过程。如果您想知道方向是如何推断出来的,它保存在 Animation 超类的 rate 和只读 currentRate 属性中(它是 extended Timeline 子类的一部分)。

反转 rate 属性的值(即,使其为负)将反转(切换)回放方向;在读取 currentRate 属性时,同样的原则也适用(负值表示相反的方向)。最后,KeyValue 类(object)用于保存 KeyFrame 对象中的值。

JavaFX 过渡类:过渡效果应用的动画子类

JavaFX Transition 类是 JavaFX Animation 超类的子类,因此它的继承层次结构从 Java 8 master class Java . lang . object 开始,向下发展到 Transition 类,如下所示:

> java.lang.Object

> javafx.animation.Animation

> javafx.animation. Transition

transition 类是一个公共抽象类,因此,它只能用于(子类化或扩展)创建 Transition 子类。事实上,已经为您创建了十个这样的子类,用于创建您自己的过渡特效;这些是 SequentialTransition、FadeTransition、FillTransition、PathTransition、PauseTransition、RotateTransition、ScaleTransition、TranslateTransition、ParallelTransition 和 StrokeTransition 类。作为动画的子类,过渡类包含了动画的所有功能。

您可能最终会直接使用这十个自定义过渡类,因为它们提供了您可能想要使用的不同类型的过渡(渐变、填充、基于路径、基于笔画、旋转、缩放、移动等)。接下来我将继续讨论 AnimationTimer 类,因为在本书中我们将使用这个类作为游戏引擎。

JavaFX AnimationTimer 类:帧处理、纳秒和脉冲

JavaFX AnimationTimer 类不是 JavaFX Animation 超类的子类,因此它的继承层次结构从 Java 8 master class Java . lang . object 开始,如下所示:

> java.lang.Object

> javafx.animation. AnimationTimer

这意味着 AnimationTimer 类是专门为 JavaFX 提供 AnimationTimer 功能的临时代码,它与 Animation(或时间轴或过渡)类或子类没有任何关系。因此,如果您将该类与占用 javafx.animation 包的 Animation、Interpolator、KeyFrame 和 KeyValue 类组合在一起,那么该类的名称可能会有些误导,因为它与这些类没有任何关系!

像 Transition 类一样,AnimationTimer 类也被声明为公共抽象类。因为是抽象类,所以只能用来(子类化或者扩展)创建 AnimationTimer 子类。与 Transition 类不同,它没有为您创建的子类;你必须从头开始创建你自己的 AnimationTimer 子类,我们将在本书的后面创建我们的 GamePlayLoop.java 类。

AnimationTimer 类看似简单,因为它只有一个您必须重写或替换的方法,包含在公共抽象类中。handle()方法。此方法提供了您希望在 JavaFX 引擎的舞台和场景处理周期的每一帧上执行的编程逻辑,它被优化为以 60FPS 播放(这对游戏来说是完美的)。JavaFX 使用脉冲系统,该系统基于新的 Java 8 纳秒时间单位(以前版本的 Java 使用毫秒)。

JavaFX 脉冲同步:场景图形元素的异步处理

JavaFX 脉冲是一种同步(计时)事件,它同步为 JavaFX 应用(游戏)创建的任何给定场景图结构中包含的元素的状态。JavaFX 中的脉冲系统由 Glass Windowing Toolkit 管理。脉冲使用高分辨率(纳秒)定时器,从 Java 8 API 开始,使用 System.nanoTime()方法的 Java 程序员也可以使用这种定时器。

JavaFX 中的脉冲管理系统被限制为 60FPS。这是为了让所有 JavaFX 线程都有“处理空间”来做它们需要做的事情。根据您在应用逻辑中所做的事情,JavaFX 应用将自动生成多达三个线程。一个基本的业务应用可能只使用主要的 JavaFX 线程,但是一个 3D 游戏也会产生 Prism 渲染线程,如果该游戏使用音频或视频,或者两者都使用,它通常会产生一个媒体播放线程。

在您的游戏开发过程中,您将使用音频、2D、3D,可能还有视频,因此您的 JavaFX 游戏应用肯定会是多线程的!正如您将看到的,JavaFX 被设计为能够利用多线程和纳秒计时功能以及 3D 渲染硬件(Prism)支持来创建游戏。

每当场景图中发生变化时,比如 UI 控件定位、CSS 样式定义或动画播放,都会调度一个 脉冲事件,并最终触发它来同步场景图中元素的状态。JavaFX 游戏设计中的诀窍是优化脉冲事件,以便它们专注于游戏运行逻辑(动画、碰撞检测等);因此,您将最小化 脉冲引擎查看的其他更改(UI 控件位置、CSS 样式更改等)。您将通过使用场景图作为固定的设计系统来实现这一点,这意味着您将使用场景图来设计您的游戏结构,但不会使用动态编程逻辑实时操纵场景图上的节点,因为脉冲系统将执行更新。

JavaFX 脉冲系统允许开发人员异步处理事件,就像在纳秒级调度任务的批处理系统,而不是像旧大型机时代的批处理调度程序那样每天一次。接下来,让我们研究如何使用. handle()方法在脉冲中调度代码。

利用 JavaFX 脉冲引擎:扩展 AnimationTimer 类以生成脉冲事件

扩展 AnimationTimer 类是让 JavaFX 脉冲系统为它处理的每个脉冲处理代码的一个好方法。您的实时游戏编程逻辑将放在。handle(long now)方法,可以通过使用另外两个 AnimationTimer 方法随意启动和停止。开始()和。停止()。

那个。开始()和。stop()方法是从 AnimationTimer 超类调用的,尽管这两个方法也可以被覆盖;只是要确保最终在重写代码方法中调用 super.start()和 super.stop()。如果作为内部类添加到当前 JavaFX public void 中。start()方法结构,代码结构可能看起来如下(参见第三章,图 3-2):

public void start(Stage primaryStage) {

Button btn = new Button;

new AnimationTimer() {

@Override

public void``handle(long now)

// Program logic that gets processed on every 脉冲 that JavaFX processes

}

} .start();

}

上面的编程逻辑展示了 AnimationTimer 内部类是如何构造的,以及 Java 点链接是如何工作的。那个。对 AnimationTimer 超类的 start()方法调用被附加到新的 AnimationTimer(){。。。}代码构造,以便将整个 AnimationTimer 创建(使用 new)、声明(使用花括号)和执行(使用. start()方法调用)链接到 AnimationTimer 对象构造。

如果您想为游戏逻辑的核心部分创建一个更复杂的 AnimationTimer 子类,比如碰撞检测,那么让这个游戏逻辑成为它自己的自定义 AnimationTimer 子类将是一个更好的主意(Java 代码设计方法)。

如果您要创建多个 AnimationTimer 子类来进行脉冲事件控制的高速处理,这一点尤其正确。没错,您可以同时运行多个 AnimationTimer 子类(只是不要忘乎所以,使用太多的 animation timer)。您可以使用 extends 关键字实现这一点,使用以下类定义创建您自己的 AnimationTimer 类,称为 GamePlayLoop:

public class GamePlayLoop``extends

@Override

public void``handle(long now)

// Program logic that gets processed on every 脉冲 that JavaFX processes

}

@Override

public void``start()

super.start();

}

@Override

public void``stop()

super.stop();

}

}

接下来,让我们研究一下 JavaFX Stage 类(object),它被传递到您的 InvinciBagel 中。start()方法!

JavaFX 屏幕和窗口控件:使用 javafx.stage 类

javafx.stage 包中包含的类可以被视为 javafx 应用(在本例中是一个游戏)显示的顶级类。这个显示在最终游戏的顶部,因为它向应用的最终用户显示了游戏的场景。Stage 对象内部是场景对象,这些对象内部是场景图形节点对象,它们包含组成应用的元素。

相比之下,从操作系统的角度来看,这个包中的类可以被认为是相当低级的;它们是 Stage、Screen、Window、WindowEvent、PopupWindow、Popup、DirectoryChooser 和 FileChooser 类以及 FileChooser。ExtensionFilter 嵌套类。这些类可用于连接设备的显示硬件、操作系统软件的窗口管理、文件管理和目录(文件夹)管理功能。

要获得运行 JavaFX 应用的设备所使用的显示硬件的描述,您需要使用 Screen 类。该类支持多屏幕(通常称为第二屏幕)方案,使用。getScreens()方法,该方法可以访问 ObservableList 对象,该对象将包含一个包含所有当前可用屏幕的列表(数组)。使用访问主屏幕。getPrimary()方法调用。您可以通过使用. getDpi()方法调用来获取主屏幕硬件的物理分辨率。也有。getBounds()和。getVisualBounds()方法调用可用的分辨率。

JavaFX 最终用户可以使用 Window 超类及其 Stage 和 PopupWindow 子类与您的应用进行交互。正如你在第三章中看到的(见图 3-2),这是使用名为 primaryStage 的 Stage 对象完成的,它被传递到你的。start()方法,或者使用 PopupWindow(对话框、工具提示、上下文菜单、通知等)子类,如 Popup 或 PopupControl 对象。

您可以使用 Stage 类在 JavaFX 应用编程逻辑中创建辅助阶段。主 Stage 对象总是由 JavaFX 平台使用公共 void start(Stage primaryStage)方法调用来构造,正如您已经在 NetBeans 创建的 bootstrap JavaFX 应用的第二章和第三章中看到的那样。

所有 JavaFX Stage 对象都必须使用构造,并在主 JavaFX 应用线程中修改,这一点我在上一节中已经讨论过了。因为阶段等同于它所运行的操作系统平台上的窗口,所以某些属性或特性是只读的,因为它们需要在操作系统级别被控制;这些是布尔属性(变量):alwaysOnTop、全屏、图标化和最大化。

所有 Stage 对象都有一个 StageStyle 属性和一个 Modality 属性,可以使用常量进行设置。stageStyle 常量是 StageStyle。装饰,舞台风格。无装饰,舞台风格。TRANSPARENT 和 StageStyle.UTILITY。通道常量是通道。无,模态。应用模态和模态。窗口 _ 模态。在下一节中,我将向您展示如何使用 StageStyle 属性和透明常量来做一些真正令人印象深刻的事情,这将使您的 JavaFX 应用在市场中脱颖而出。

Popup 类可用于从头开始创建自定义弹出通知,甚至自定义游戏组件。或者,您可以使用 PopupControl 类及其 ContextMenu 和 Tooltip 子类来提供这些预定义的(编码的)JavaFX UI 控件。

DirectoryChooser 和 FileChooser 类支持将标准 OS 文件选择和目录导航对话框传递到 JavaFX 应用中。文件选择器。ExtensionFilter 嵌套类提供了一个实用程序,用于根据文件类型(文件扩展名)过滤将出现在 FileChooser 对话框中的文件。

接下来,让我们将您当前的 InvinciBagel Stage 对象提升到下一个级别,并使其成为一个无窗口(浮动)应用。这是 JavaFX 令人印象深刻的特性之一,是 Flash 或其他游戏引擎无法比拟的。

使用 JavaFX 主 Stage 对象:创建浮动的无窗口应用

让我们将 InvinciBagel 应用的主阶段设置为透明的,这样按钮 UI 控件就可以悬浮在操作系统桌面上。这是 JavaFX 可以做到的,但你并不经常看到,它允许你创建浮动在操作系统桌面之上的 3D 应用(对于 3D 虚拟对象,这被称为无窗口 ActiveX 控件)。

这是通过使用 StageStyle 实现的。透明常数,与。initStyle()方法,来自 Stage 类。如图 4-4 所示,我还使用了我在第三章中告诉过你的技术(这种技术不遵循正确的 Java 编码惯例,为你计划使用的类声明一个导入语句)。在代码的第 35 行,我通过在 primary stage . init style(stage style style)方法调用中使用完全限定的类名(package . subpackage . class . constant)、Java FX . stage . stage style . transparent 来引用常量。这是通过下面一行 Java 代码完成的:

primaryStage.initStyle(javafx.stage.StageStyle.``TRANSPARENT

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-4。

Call an .initStyle() method with the StageStyle.TRANSPARENT constant, off the primaryStage Stage object

正如您所看到的,我在 NetBeans IDE 8.0 的代码编辑区域中单击了 primaryStage Stage 对象,它会显示(跟踪)该对象在代码中的用法。Stage 对象是使用。setTitle(),。initStyle(),。setScene()和。show()方法调用。

我要离开了。在代码中调用 setTitle()方法,但是要记住,一旦你让这种无窗口的应用处理工作起来,标题栏就是窗口的“chrome”或 UI 元素的一部分,当这些元素(包括标题栏)消失时,标题的这种设置就没有意义了。

如果您一直在担心内存优化,那么在应用开发工作过程的这一点上,您应该删除。setTitle()方法调用,因为标题不会使用 StageStyle 显示。StageStyle 属性的透明常数。

接下来,使用运行图标(或运行菜单),运行应用。如图 4-5 所示,你试图实现的并没有成功:窗口的铬元素不见了,透明度值也不明显。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-5。

Run the project to see if the Stage object is transparent; clearly, something is set to White

在处理管道中一定有其他东西还没有使用透明度值定义它的背景。透明度使用十六进制值#00000000 来定义,这表示所有 aarggbb(alpha 通道,红色,绿色,蓝色)颜色和不透明度值都已关闭。您需要开始将应用的 JavaFX 组件视为层(目前,它们是 stage-scene-stackPane-button)。随着这本书的进展,你将学习数字成像概念,如色深、alpha 通道、图层、混合,以及所有与处理 2D 平面中的像素相关的技术信息。

您应该尝试设置的下一个透明值是 JavaFX 场景图层次结构中从舞台向下的下一级,它包含场景图本身。如前所述,下一个最顶层的组件是场景对象,它也有一个背景颜色值参数或属性。

像 Stage 类(object)一样,Scene 类(object)也没有透明的样式常量,因此您必须使用不同的方法和常量,以不同的方式将 Scene 对象的背景设置为透明值。您应该知道的一件事是,JavaFX 中所有将自身写入屏幕的东西都会以某种方式支持透明性,以允许 JavaFX 应用中的多层合成。

如果您阅读场景类文档,您会注意到有一个方法。setFill(颜色值),它接受一个颜色(类或对象)值,所以让我们接下来试试。如图 4-6 所示,我调用了。setFill()关闭名为 Scene 的场景对象,使用一个scene.setFill(Color.TRANSPARENT);语句,这是 NetBeans 帮我构造的!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-6。

Call the .setFill() method with the Color.TRANSPARENT constant, off the Scene object named scene

再次运行应用,查看透明度是否显示出来。如图 4-7 所示,并不是!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-7。

Run the project to look at the transparent Stage object; something is still set to White

因为您使用 StackPane 对象来实现 InvinciBagel 应用中的层,所以这是您需要尝试设置透明度值的下一个级别。显然,JavaFX 使用了一种颜色。其所有对象的白色默认背景色值。如果我是 JavaFX 设计团队的一员,我会主张将它改为彩色。透明常数,但是,当然,这可能会混淆新用户,因为阿尔法通道和合成层是先进的概念。

javafx.scene.layout.StackPane 类是 javafx.scene.layout.Region 类的子类,该类具有用于设置背景(类或对象)值的. setBackground()方法。同样,透明值常量必须可用,因为您总是需要将背景值设置为透明的,尤其是对于 Java 8 游戏设计。

有趣的是,在 Java 编程中,事情并不总是像您希望的那样简单和一致,因为,为了获得完全相同的最终结果(为设计元素安装透明的背景色/图像板),到目前为止,您已经使用了三个不同的方法调用,传递了三个自定义对象类型:。initStyle(StageStyle 对象)。setFill(颜色对象),以及。setBackground(背景对象)。

这一次,您将调用。setBackground(背景值)方法,还有另一个背景类(对象)常量,为空。如图 4-8 所示,一旦使用以下 Java 语句调用名为 root 的 StackPane 对象的方法,NetBeans 将帮助您找到该常量:root.setBackground(Background。空);。NetBeans 提供了一个方法选择器下拉框,一旦您选择了一个方法,就会出现一个信息对话框,显示该方法的来源(超类)以及它的作用和深入的描述。在这种情况下,空(无)、零颜色填充或零图像集等同于透明。现在,您已经准备好通过使用 run project 工作流程来测试您的无窗口(透明)应用版本了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-8。

Call a .setBackground() method with a Background.EMPTY constant, off the StackPane object named root

正如你在图 4-9 中看到的,你现在已经实现了你的目标,在桌面上只有按钮对象是可见的。我将 NetBeans IDE 8.0 的顶部向下拉了一点,这样您就可以看到它的效果有多好,并且仍然可以看到您为实现这一最终结果而添加的三行 Java 代码。使用 2D、3D 和 alpha 通道,可以通过这种 StageStyle 创建一些非常酷的应用。透明功能,所以我想我应该在本书的早期向您展示它,并在 JavaFX 概述章节中获得一些 JavaFX 应用 Java 编码经验。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-9。

Windowless JavaFX application seen at the top; completed Java and JavaFX code that achieves it seen in the IDE

既然您已经研究了 javafx.stage 包,接下来让我们研究 javafx.geometry 包!

JavaFX 边界和尺寸:使用 javafx.geometry 类

尽管术语“几何体”在技术上适用于 2D 和 3D 资源,但是它们包含在 javafx.scene.shape 包中,我在前面已经介绍过了(参见“场景子包:13 个其他场景包”一节)。javafx.geometry 包更像是一个实用程序包,包含从头开始构建 2D 和 3D 构造的基础类。因此,该包提供了 Bounds 超类及其 BoundingBox 子类等类,以及 Insets、Point2D、Point3D、Dimension2D 和 Rectangle2D 几何内容创建实用程序类。

javafx.geometry 包中的所有类,除了 BoundingBox 类,都是直接从 java.lang.Object master 类扩展而来的,这意味着它们都是从头开始开发(编码)的,用于提供点(也称为顶点)、矩形、尺寸、边界和 insets(内部边界)作为 javafx 应用开发的几何实用程序。

Point2D 和 Point3D 类(最终是对象)保存 2D 平面上 2D 点的 x,y 坐标或 3D 空间中 3D 点的 x,y,z 坐标。这些点对象将用于构建由点集合组成的更复杂的 2D 或 3D 结构,如 2D 路径或 3D 网格。Point2D 和 Point3D 构造函数方法调用没有重载,它们分别使用以下标准格式:

Point2D(double``X,``double)

Point3D(double X, double Y, double Z

Rectangle2D 类(object)可用于定义一个矩形 2D 区域,通常称为平面,正如您所想象的,它在图形编程中有许多用途。Rectangle2D 对象在指定矩形的左上角有一个起点,使用一个x和一个y坐标位置以及一个尺寸(宽乘高)。Rectangle2D 对象的构造函数方法具有以下标准格式,并且未被重载:

Rectangle2D(double``minX``, double``minY``, double``width``, double``height``)

此外,Dimension2D 类(object)仅指定宽度和高度尺寸,并不使用x, y位置在屏幕上放置尺寸(这会使其成为矩形)。该类的构造函数方法如下:

Dimension2D(double``width``, double``height

Insets 类(object)类似于 Dimension2D 类,因为它不提供插入的位置值,但根据顶部、底部、左侧和右侧的偏移距离提供矩形插入区域的偏移。Insets 方法实际上是重载的,因此可以使用以下代码指定等距插入或自定义插入:

Insets(double``topRightBottomLeft

Insets(double``top``, double``right``, double``bottom``, double``left``)

Bounds 类是一个公共抽象类,永远不会是一个对象,而是一个创建节点边界类的蓝图,比如它的 BoundingBox 子类。Bounds 超类也允许一个负值,用来表示一个边界区域是空的(可以认为它是空的,或者未使用的)。BoundingBox 类使用以下(重载)构造函数方法创建 2D(第一个构造函数)或 3D(第二个构造函数)BoundingBox 对象:

BoundingBox(double``minX``, double``minY``, double``width``, double``height``)

BoundingBox(double``minX``, double``minY``, double``minZ``, double``width``, double``height``, double``depth``)

接下来,让我们看看 JavaFX 中的事件和动作事件处理,因为这将为您的游戏添加交互性。

游戏的 JavaFX 输入控件:使用 javafx.event 类

因为游戏本质上是交互式的,所以接下来让我们看看 javafx.event 包;它为我们提供了 Eventsuperclass 及其 ActionEvent 子类,用于处理动作事件,例如 UI 元素的使用和动画关键帧的处理。因为您将在 JavaFX 游戏(应用)中使用 ActionEvent,所以我在这里描述它的类继承层次,因为这也将向您展示 Event 类的起源:

Java.lang.Object

> java.util.EventObject

> javafx.event.Event

> javafx.event. ActionEvent

您的 InvinciBagel 游戏应用已经在使用这个 ActionEvent 类(object ),带有 EventHandler 接口和它的。handle()方法,由您自己编写代码来告诉您的应用在事件发生(触发)后如何“处理”事件(ActionEvent)。那个。handle()方法捕获这个触发的事件,然后根据。handle()方法。

Java 接口是一个提供空方法的类,这些方法被声明供使用,但还不包含任何 Java 编程结构。未实现的方法在使用时必须由 Java 程序员来实现。这个 Java 接口只定义了要实现的方法(在本例中,是处理 ActionEvent 的方法,以便以某种方式处理事件)。需要注意的是,Java 接口定义了需要编码的方法,但并没有为您编写方法代码,因此它是一个路线图,说明了您必须做些什么来完成现有的编程结构(在本例中,是用于处理 ActionEvent 对象的 Java 编程结构,即触发的操作事件)。

现在,让我们看看 JavaFX 中的多线程,这是高级游戏的另一个重要概念,以此来结束对 JavaFX API 和包层次结构中与 2D 和 3D(游戏)相关的一切的探索。

游戏的 JavaFX 线程控制:javafx.concurrent 包

游戏需要后台或异步处理。这可以使用除 JavaFX 应用线程、Prism 渲染线程和媒体播放线程之外的其他线程来完成,这些线程都是根据您在场景图形中使用的类(对象)自动创建的。您的应用编程逻辑可以生成自己的工作线程进行处理,这样您就不会使主 JavaFX 应用线程过载。接下来让我们看一下 javafx.concurrent 包,因为它为我们提供了 Service 超类及其 ScheduledService 子类,用于创建 Worker 对象,还提供了 Task 类,用于一次性任务处理。

因为您将在 JavaFX 游戏(应用)中使用 Service 和 ScheduledService,所以我在这里演示 ScheduledService 类继承层次结构,因为这也将向您展示服务类的 java.lang.Object 起源:

Java.lang.Object

> javafx.concurrent.Service

> javafx.concurrent. ScheduledService

而任务(类)对象只使用一次,为了完成一个给定的任务,一个service正在进行,一个服务对象和一个调度服务(类)对象可以被重用,也就是说,它们随时准备执行它们的service。这更适合于玩游戏的处理,因为玩游戏会持续很长一段时间,这里的假设是,在玩游戏期间,随着时间的推移,也需要计算所涉及的游戏逻辑处理的类型,而不是像任务类(对象)那样,只计算一次。

Worker Java 构造实际上是一个接口,Task、Service 和 ScheduledService 类都是基于这个 Worker 接口为您创建的(这比EventHandler接口更好,您必须自己实现它!).

Worker 对象使用后台线程执行处理,可以是可重用的(如在 Service 类中),也可以是不可重用的(如在 Task 类中)。工作线程状态由工作线程控制。状态类(对象)并包含工作线程的生命周期阶段。这些应用于 javafx.concurrent 包中的三个主要类,因为它们实现了 Worker 接口及其相关的嵌套类。如前一章所述,嵌套类是通过点符号访问的,因此 State 类嵌套在Worker interface (class中。因为在你使用一个工作线程之前,理解它的状态是非常重要的,所以我将以表格的形式详细描述它们,这样你就一目了然了(见表 4-3 )。

表 4-3。

Worker Thread Life Cycle States, as Defined by the Worker.State Nested Class for Use with a Worker Interface

工人。状态常数意义
准备好的工作对象(线程)已经初始化(或重新初始化)并准备好使用。
预定的工作对象(线程)已计划执行,但当前没有运行。
运转工作对象(线程)当前正在运行,并且正在执行 Java 编程逻辑。
成功工作对象(线程)已成功执行,有效结果在 value 属性中。
不成功的由于某些意外情况,工作对象(线程)未能成功执行。
取消已通过调用 Worker.cancel()方法取消了工作对象(线程)。

正如本 JavaFX 8 多媒体引擎概述章节中的其他内容一样,在应用这些 JavaFX 编程结构和概念时,您将在本书的过程中深入了解如何使用这些包、类、嵌套类、接口、方法、常量和变量的细节!

摘要

在第四章中,您仔细查看了 JavaFX 8 API 中一些更重要的包、概念、组件、类、构造函数、常量和变量(属性), Java FX 8 API 是一个令人印象深刻的 36 个 Java FX . package name . sub pagename 包的集合,我在表格中列出了这些包,并根据多媒体 2D 和 3D(以及混合 2D-3D)游戏开发的需要逐一进行了介绍。我说的“概述”就是概述!

当然,我不能在一章中讨论 JavaFX 中的每个功能类,所以我首先概述了 JavaFX 引擎,以及它如何与上面的 JavaFX Scene Builder 工具和 JavaFX Scene Graph API集成,以及如何与下面的 Java 8 API、NetBeans 8.0 和目标操作系统集成,这为 JavaFX 提供了跨众多流行平台和设备以及主流 web 浏览器的扩展操作系统支持。

我展示了 JavaFX 的高级技术视图,详细介绍了它的结构,包括 JavaFX 场景图、API、Quantum、Prism、Glass、WebKit 和媒体引擎。您了解了这些多线程、渲染、窗口、媒体和 web 引擎如何与 Java 8 API 和 Java JDK 8 以及 NetBeans 8.0 及其生成的 JVM 字节码进行交互,这些字节码由当前运行在十几种不同消费电子设备类型上的各种操作系统平台读取。

您还了解了 JavaFX 的核心概念,如JavaFX Scene Graph和 JavaFX 脉冲 events 系统,您将在阅读本书时利用它们来创建 Java 8 游戏,从下一章开始,我将解释如何在 NetBeans 中使用 JavaFX Scene Builder 可视化编辑工具。

然后,深入研究游戏设计的一些关键 JavaFX 包和子包,比如Application, Scene, Shape, Effect, Layout, Control, Media, Image, Stage, Animation, Geometry, Event, and Concurrent,以及它们的包类和子类,甚至在某些情况下,它们的接口、嵌套类和常量。

您甚至花了一点时间向 InvinciBagel 应用添加了一些代码,将它变成了一个无窗口应用,并学习了如何使用 alpha 通道和十六进制#00000000 或颜色使stage, scene, and stackPane背景板透明。透明,背景。空,和场景样式。透明常数。我不得不在本章中加入一些关于 NetBeans IDE 8.0、Java 8 编程语言和 JavaFX API 的内容!

在下一章中,您将探索 JavaFX Scene Builder,它使得您在本章中学习的场景图结构的构建变得容易。你也将开始构建你的游戏启动画面,因为我知道你渴望开始一个游戏基础设施,即使它只是一个启动画面!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值