Skip to content

Latest commit

 

History

History
923 lines (565 loc) · 60.3 KB

File metadata and controls

923 lines (565 loc) · 60.3 KB

一、C++,SFML,VisualStudio,并开始第一个游戏

欢迎来到《开放 C++ 游戏编程》第 1 卷。我不会浪费任何时间让你开始写你的旅程,用 C++ 和 OpenGL 供电的 SFML 来为 PC 编写精彩的游戏。

这是一个相当沉重的第一章,但我们绝对会学习我们所需要的一切,这样我们就有了第一场比赛的第一部分。以下是我们在本章中要做的事情:

  • 了解我们将创建的游戏
  • 满足 C++
  • 了解微软 Visual C++
  • SFML 及其与 C++ 的关系探讨
  • 建立发展环境
  • 计划和准备第一个游戏项目,木材!!!
  • 写下这本书的第一个 C++ 代码,制作一个可以绘制背景的可运行游戏。

我们将打造的游戏

这段旅程将是顺利的,因为我们将一步一步地学习超高速 C++ 语言的基本原理,然后把新的知识用于添加我们将要构建的五个游戏的酷功能。

以下是本书的五个项目。

木材!!!

第一个游戏是一个令人上瘾的,快节奏的,巨大成功的木材人的复制品,可以在找到 http://store.steampowered.com/app/398710/ 。我们的游戏,木材!!!,在我们构建一个真正的可玩游戏时,我们将介绍 C++ 的所有基本知识。以下是我们完成游戏后的版本,我们在最后一刻添加了一些增强功能:

Pong 是最早制作的视频游戏之一,你可以在这里了解它的历史:https://en.wikipedia.org/wiki/Pong 。这是一个很好的例子,说明了游戏对象动画和动态碰撞检测的基础知识是如何工作的。我们将构建这个简单的复古游戏来探索类和面向对象编程的概念。球员将使用屏幕底部的球棒,将球击回屏幕顶部:

僵尸竞技场

下一步,我们将打造一款疯狂的僵尸生存射击游戏,与蒸汽打击9000 多名僵尸没什么两样!,您可以在了解更多信息 http://store.steampowered.com/app/273500/ 。玩家将拥有一把机关枪,必须击退不断增长的僵尸浪潮。所有这些都将发生在一个随机生成的滚动世界中。为了实现这一点,我们将学习面向对象编程如何使我们拥有易于编写和维护的大型代码库(大量代码)。期待激动人心的功能,如数百个敌人、快速射击武器、皮卡车和一个可以在每次浪潮后“升级”的角色:

托马斯迟到了

第四款游戏将是一款时尚且富有挑战性的单人和合作拼图平台。它基于非常流行的游戏托马斯是孤独的http://store.steampowered.com/app/220780/ )。希望了解一些很酷的主题,如粒子效果、OpenGL 着色器和分屏协作多人游戏:

提示

如果您现在想玩任何游戏,您可以从Runnable Games文件夹中的下载包中进行。只需双击相应的.exe文件。请注意,在此文件夹中,您可以从任何章节运行已完成的游戏或处于部分完成状态的任何游戏。

太空入侵者++

最后的游戏将是太空入侵者的克隆。在某些方面,游戏本身并不重要。该项目将用于学习游戏编程模式。随着本书的深入,我们的代码将变得越来越长,越来越复杂。每个项目都会引入一种或多种技术来解决这个问题,但尽管有这些技术,我们的代码的复杂性和长度还是会不断地挑战我们。

太空入侵者项目(称为太空入侵者++)将向我们展示如何从根本上重新组织我们的游戏代码,我们也可以一劳永逸地控制和正确管理我们的代码。这将为您提供规划和构建深度、复杂和创新游戏所需的所有知识,而不会陷入代码混乱。

游戏还将引入屏幕、输入处理程序和实体组件系统等概念。它还将允许我们学习如何让玩家使用 GAMEPAD 而不是键盘,并介绍 C++ 指针的智能指针、转换、断言、断点调试,并教我们从整本书中最重要的一课:如何构建自己独特的游戏:

让我们开始介绍 C++,Visual Studio 和 SFML!

满足 C++

现在我们知道我们将要构建什么游戏,让我们从 C++、VisualStudio 和 SFML 开始。你可能有一个问题,为什么要使用 C++ 语言?第二步:C++ 很快-非常快。我们编写的代码被直接翻译成机器可执行指令,这一事实使这一点成为现实。这些说明是游戏的关键。可执行游戏包含在一个.exe文件中,玩家只需双击即可运行该文件。

在将代码更改为可执行文件的过程中,有几个步骤。首先,预处理器查看是否有其他代码需要包含在我们自己的代码中并添加它。接下来,所有代码由编译器程序编译目标文件。最后,第三个程序称为链接器,将所有目标文件连接到游戏的可执行文件中。

此外,C++ 是非常好建立的,同时也是最新的。C++ 是一种面向对象编程的编程语言 To1(Apple T2SooOutT3)语言,这意味着我们可以编写和组织我们的代码,使用测试良好的约定,使我们的游戏高效和可管理。当我们阅读本书时,它的好处和必要性将会显现出来。

正如您可能猜到的,我提到的大多数其他代码是 SFML,我们将在一分钟内了解更多关于 SFML 的信息。我刚才提到的预处理器、编译器和链接器程序都是 Visual Studio集成开发环境IDE的一部分。

微软 Visual Studio

VisualStudio 隐藏了预处理、编译和链接的复杂性。只需按下一个按钮,它就能把一切都包起来。除此之外,它还为我们提供了一个灵活的用户界面,可以将代码输入并管理大量的代码文件和其他项目资产。

虽然 Visual Studio 的高级版本花费数百美元,但我们将能够在免费的“Express 2019 for Community版本中构建所有五款游戏。这是 Visual Studio 的最新免费版本。

\12304;T0]SFML

SFML简单快速媒体库。它不是唯一的 C++ 游戏和多媒体库。使用其他库是可能的,但 SFML 似乎每次都能为我所接受。首先,使用面向对象 C++ 编写。面向对象 C++ 的好处是很多的,而且随着你在这本书中的进步,你会体验到它们。

SFML 也很容易入门,因此如果您是初学者,它是一个不错的选择,但同时,如果您是专业人士,它有潜力构建最高质量的 2D 游戏。因此,初学者可以开始使用 SFML,而不必担心随着经验的增长必须重新开始使用新的语言/库。

也许最大的好处是大多数现代 C++ 编程都使用面向对象编程。每个 C++ 初学者的指导我都读过使用和教 OOP。事实上,OOP 是几乎所有语言编码的未来(和现在)。那么,如果你从一开始就学习 C++,你会想用其他方法来做吗?

SFML 有一个模块(代码),用于在 2D 游戏中执行任何操作。SFML 使用 OpenGL 工作,OpenGL 也可以制作 3D 游戏。当您希望在多个平台上运行游戏时,OpenGL 实际上可以免费使用图形库。当您使用 SFML 时,您将自动使用 OpenGL。

SFML 允许您创建以下内容:

  • 2D 图形和动画,包括滚动游戏世界。
  • 音效和音乐播放,包括高品质的定向声音。
  • 使用键盘、鼠标和游戏板进行输入处理。
  • 在线多人游戏功能。
  • 同样的代码可以在所有主要的桌面操作系统和手机上编译和链接!。

广泛的研究并没有发现任何更合适的方式来为 PC 甚至为专家开发 2D 游戏,尤其是如果你是初学者,并且想在有趣的游戏环境中学习 C++。

在接下来的部分中,我们将设置开发环境,首先讨论在使用 Mac 或 Linux 操作系统时应该做什么。

建立发展环境

现在,您对我们将如何制作游戏有了更多的了解,现在是时候建立一个开发环境,以便我们可以进行编码了。

Mac 和 Linux 呢?

我们将制作的游戏可以在 Windows、Mac 和 Linux 上运行!对于每个平台,我们使用的代码都是相同的。但是,每个版本都需要在其预期的平台上编译和链接,VisualStudio 将无法帮助我们使用 Mac 和 Linux。

说这本书完全适合 Mac 和 Linux 用户是不公平的,特别是对初学者来说。虽然,我想,如果你是一个热情的 Mac 或 Linux 用户,并且对自己的操作系统感到满意,那么你很可能会成功。您将遇到的大多数额外挑战将出现在开发环境 SFML 的初始设置和第一个项目中。

为此,我可以强烈推荐以下教程,它们将有望取代接下来的 10 页(大约),直到*计划书!!!*节,本书何时与所有操作系统相关。

对于 Linux,请阅读本文以替换下面的几个部分:https://www.sfml-dev.org/tutorials/2.5/start-linux.php

在 Mac 上,阅读本教程开始:https://www.sfml-dev.org/tutorials/2.5/start-osx.php

安装 Visual Studio 2019 社区版

要开始创建游戏,我们需要安装 VisualStudio2019。安装 VisualStudio 几乎可以像下载文件并单击几个按钮一样简单。我将一步一步地指导您完成安装过程。

重要提示

请注意,多年来,Microsoft 可能会更改用于获取 Visual Studio 的名称、外观和下载页面。他们可能会更改用户界面的布局,并使随后的说明过时。然而,我们为每个项目配置的设置是 C++ 和 SFML 的基础,因此即使在微软对 VisualStudio 进行一些激进的操作时,对本章后面的说明也可能进行仔细的解释。无论如何,在撰写本文时,VisualStudio2019 已经发布了两周,所以希望这一章在一段时间内是最新的。如果确实发生了一些重要的事情,那么我将在上添加一个最新的教程 http://gamecodeschool.com 我一发现这件事。

让我们开始安装 Visual Studio:

  1. 您首先需要的是 Microsoft 帐户和登录详细信息。如果你有 Hotmail 或 MSN 电子邮件地址,那么你已经有了。如果没有,您可以在这里注册一个免费的:https://login.live.com/

  2. The next step is to visit https://visualstudio.microsoft.com/vs/ and find the download link for Community 2019. This is what it looks like at the time of writing:

  3. 将文件保存到您的计算机。

  4. 下载完成后,双击以运行下载。在撰写本文时,我的文件名为vs_community__33910147.1551368984.exe。根据当前版本的 Visual Studio,您的将有所不同。

  5. After giving permission for Visual Studio to make changes to your computer, you will be greeted with the following window. Click Continue:

  6. Wait for the installer program to download some files and set up the next stage of the installation. Shortly, you will be presented with the following window:

  7. 如果要选择新位置来安装 Visual Studio,请找到更改选项并配置安装位置。最简单的方法是将文件保留在 VisualStudio 选择的默认位置。当您准备好时,用 C++ OutT3AY 选项定位 OLE T2 桌面开发并选择它。

  8. 接下来,点击安装按钮。抓取一些点心,因为这一步可能需要一些时间。

  9. 当这个过程完成时,您可以关闭所有打开的窗口,包括任何提示您启动新项目的窗口,因为在安装 SFML 之前,我们还没有准备好开始编码。

现在,我们准备将注意力转向 SFML。

设置 SFML

本简短教程将指导您下载 SFML 文件,这些文件允许我们在项目中包含库中包含的功能。此外,我们将了解如何使用 SFMLDLL文件,使我们编译的目标代码能够与 SFML 一起运行。要设置 SFML,请执行以下步骤:

  1. Visit this link on the SFML website: http://www.sfml-dev.org/download.php. Click on the button that says Latest stable version, as shown here:

  2. By the time you read this book, the latest version will almost certainly have changed. This won’t matter as long as you do the next step just right. We want to download the 32-bit version of Visual C++ 2017. This might sound counter-intuitive because we have just installed Visual Studio 2019 and you probably (most commonly) have a 64-bit PC. The reason we chose to download the 32-bit version is that Visual C++ 2017 is part of Visual Studio 2019 (Visual Studio does more than C++) and we will be building games in 32-bit so that they can run on both 32- and 64-bit machines. Click the Download button that’s shown in the following screenshot:

  3. 下载完成后,在安装 Visual Studio 的同一驱动器的根目录下创建一个文件夹,并将其命名为SFML。另外,在安装 Visual Studio 的驱动器的根目录下创建另一个文件夹,并将其命名为VS Projects

  4. 最后,解压缩 SFML 下载。在桌面上执行此操作。解压缩完成后,您可以删除.zip 文件夹。您的桌面上将只剩下一个文件夹。其名称将反映您下载的 SFML 版本。我的名字叫SFML-2.5.1-windows-vc15-32-bit。您的文件名可能会反映较新的版本。双击此文件夹查看其内容,然后再次双击进入下一个文件夹(我的文件夹名为SFML-2.5.1。下面的屏幕截图显示了我的SFML-2.5.1 文件夹的内容。你的应该看起来一样:

  5. 复制此文件夹的全部内容,并将所有文件和文件夹粘贴到您在步骤 3中创建的SFML文件夹中。在本书的其余部分,我将把这个文件夹简单地称为“您的SFML文件夹”。

现在,我们已经准备好在 VisualStudio 中使用 C++ 和 SFML。

创建新项目

由于建立项目是一个复杂的过程,我们将一步一步地进行,以便我们能够开始习惯它:

  1. Start Visual Studio in the same way you start any app: by clicking on its icon. The default installation options will have placed a Visual Studio 2019 icon in the Windows start menu. You will see the following window:

  2. Click on the Create a new project button, as highlighted in the preceding screenshot. You will see the Create a new project window, as shown in the following screenshot:

  3. In the Create a new project window, we need to choose the type of project we will be creating. We will be creating a console app, so select Console App, as highlighted in the preceding screenshot, and click the Next button. You will then see the Configure your new project window. This following screenshot shows the Configure your new project window after the next three steps have been completed:

  4. 配置新项目窗口中,在项目****名称字段中键入Timber。请注意,这会导致 Visual Studio 自动将解决方案名称字段配置为相同的名称。

  5. 位置字段中,浏览到我们在上一教程中创建的VS Projects文件夹。这将是我们所有项目文件的保存位置。

  6. 选中选项将解决方案和项目放在同一目录中。

  7. Note that the preceding screenshot shows what the window looks like when the previous three steps have been completed. When you have completed these steps, click Create. The project will be generated, including some C++ code. This following screenshot shows where we will be working throughout this book:

  8. 现在,我们将配置该项目以使用我们放在SFML文件夹中的 SFML 文件。从主菜单中选择项目****木材属性…。您将看到以下窗口:

提示

在前面的屏幕截图中,确定取消应用按钮未完全形成。这可能是 Visual Studio 没有正确处理我的屏幕分辨率的问题。你的身体有望完全成形。无论你的按钮是否像我的一样,继续学习教程都是一样的。

接下来,我们将开始配置项目属性。由于这些步骤相当复杂,我将在新的步骤列表中介绍它们。

配置项目属性

在此阶段,您应该打开木材属性页窗口,如前一节末尾的屏幕截图所示。现在,我们将开始配置一些属性,同时使用以下带注释的屏幕截图作为指导:

我们将在本节中添加一些相当复杂和重要的项目设置。这是一个艰苦的部分,但我们只需要做一次,每个项目。我们需要做的是告诉 VisualStudio 在哪里可以从 SFML 找到特殊类型的代码文件。我所指的特殊类型的文件是一个头文件。头文件是定义 SFML 代码格式的文件,因此当我们使用 SFML 代码时,编译器知道如何处理它。请注意,头文件与主要源代码文件不同,它们包含在具有.hpp文件扩展名的文件中。当我们最终开始在第二个项目中添加我们自己的头文件时,所有这些都会变得更加清晰。此外,我们需要告诉 VisualStudio 在哪里可以找到 SFML 库文件。在木材属性页窗口中,执行以下三个步骤,在前面的屏幕截图中编号:

  1. 首先(1,从配置:下拉列表中选择所有配置

  2. 第二步(2,从左侧菜单中选择C/C++,然后选择General

  3. 第三个(3,找到附加包含目录编辑框,键入 SFML 文件夹所在的驱动器号,然后键入\SFML\include。如果您在 D 驱动器上找到了SFML文件夹,则键入的完整路径如前一屏幕截图所示;也就是说,D:\SFML\include。如果在不同的驱动器上安装了 SFML,请更改路径。

  4. 点击应用保存您目前的配置。

  5. 现在,仍然在同一窗口中,执行以下步骤,这些步骤涉及以下带注释的屏幕截图。首先(1,选择连接器,然后选择普通

  6. Now, find the Additional Library Directories edit box (2) and type the drive letter where your SFML folder is, followed by \SFML\lib. So, the full path to type if you located your SFML folder on your D drive is, as shown in the following screenshot, D:\SFML\lib. Vary your path if you installed SFML to a different drive:

  7. 点击应用保存您目前的配置。

  8. 最后,对于这个阶段,仍然在同一个窗口中,执行以下步骤,这些步骤参考以下带注释的屏幕截图。切换配置:下拉菜单(1到调试,因为我们将在调试模式下运行和测试我们的游戏。

  9. 选择连接器,然后输入2

  10. 找到附加依赖项编辑框(3),点击最左侧。现在,复制并粘贴/键入以下内容:sfml-graphics-d.lib;sfml-window-d.lib;sfml-system-d.lib;sfml-network-d.lib;sfml-audio-d.lib;在指定位置。要格外小心,将光标准确地放置在正确的位置,不要覆盖已经存在的任何文本。

  11. Click OK:

![](img/B14278_01_16a.jpg)
  1. 点击应用,然后点击确定

呸;就这样!我们已经成功配置了 Visual Studio,可以继续规划木材!!!项目

规划木材!!!

每当你做游戏时,最好先用铅笔和纸开始。如果你不知道你的游戏在屏幕上是如何工作的,你怎么可能让它在代码中工作呢?

提示

在这一点上,如果你还没有,我建议你去看一段 Timberman 在行动的视频,这样你就可以看到我们的目标。如果你觉得你的预算可以应付,那就拿一份拷贝来试一试。它通常在 Steam 上以低于 1 美元的价格出售:http://store.steampowered.com/app/398710/

定义游戏性的游戏特征和对象称为机制。游戏的基本机制如下:

  • 时间总是不多了。
  • 你可以通过砍树得到更多的时间。
  • 砍树会导致树枝掉落。
  • 球员必须避免树枝掉落。
  • 重复此操作,直到时间用完或球员被压扁。

希望你在这个阶段规划 C++ 代码显然有点傻。这当然是 C++ 初学者入门的第一章。但是,我们可以看看我们使用的所有资产,以及我们需要做什么来做我们的 C++ 代码。

看看这个游戏的注释截图:

您可以看到,我们有以下功能:

  • **玩家得分:**玩家每次砍一根圆木,得一分。他们可以用向左或向右箭头(光标)键来砍木头。
  • **玩家角色:**玩家每次砍树时,他们将移动到/停留在树的同一侧,相对于他们使用的光标键。因此,球员必须小心选择在哪一边砍。
  • 当玩家切碎时,玩家角色手中会出现一个简单的斧头图形。
  • **收缩时间条:**每次玩家切碎时,会在不断收缩的时间条上增加少量时间。
  • **致命的树枝:**玩家砍得越快,他们得到的时间就越多,但树枝向下移动的速度也越快,因此他们被压扁的可能性就越大。树枝在树顶随机繁殖,每砍一次就向下移动。
  • 当玩家被压扁时——他们会经常被压扁——墓碑图形就会出现。
  • **切碎的原木:**当玩家切碎时,一个切碎的原木图形会呼啸而过,远离玩家。
  • **只是为了装饰:**这里有三朵浮云,它们会以随机的高度和速度漂移,还有一只蜜蜂,它什么也不做,只是四处飞。
  • **背景:**所有这些都发生在一个美丽的背景上。

因此,简而言之,玩家必须疯狂地砍杀以获得分数,避免时间耗尽。有点反常,但有趣的结果是,他们砍得越快,就越有可能在泥泞中死去。

我们现在知道了游戏是什么样子,如何玩,以及游戏机制背后的动机。现在,我们可以开始建造了。遵循以下步骤:

  1. Now, we need to copy the SFML .dll files into the main project directory. My main project directory is D:\VS Projects\Timber. It was created by Visual Studio in the previous tutorial. If you put your VS Projects folder somewhere else, then perform this step there instead. The files we need to copy into the project folder are located in your SFML\bin folder. Open a window for each of the two locations and highlight all the files in the SFML\bin folder, as shown in the following screenshot:

  2. 现在,将突出显示的文件复制粘贴到项目文件夹中,即D:\VS Projects\Timber

该项目现已建立并准备就绪。您将能够看到以下屏幕。我对这个屏幕截图进行了注释,这样您就可以开始熟悉 VisualStudio 了。我们将很快重新审视所有这些领域和其他领域:

您的布局可能与前面的屏幕截图略有不同,因为与大多数应用一样,VisualStudio 的窗口是可自定义的。花点时间找到右侧的解决方案资源管理器窗口,并对其进行调整,使其内容清晰明了,就像上一个屏幕截图一样。

我们将很快回到这里开始编码。但首先,我们将探索我们将使用的项目资产。

项目资产

资产是你制作游戏所需要的任何东西。在我们的案例中,这些资产包括以下内容:

  • 在屏幕上书写的字体
  • 不同动作的音效,如斩、死和时间不足
  • 角色、背景、分支和其他游戏对象的图形

本游戏所需的所有图形和声音都包含在本书的下载包中。它们可以在Chapter 1/graphicsChapter 1/sound文件夹中找到。

尚未提供所需的字体。这是因为我想避免关于许可证的任何可能的歧义。不过,这不会引起任何问题,因为我将向您展示为您自己选择和下载字体的确切位置和方式。

虽然我将提供资产本身或从何处获取资产的信息,但您可能希望自己创建或获取这些资产。

资产外包

有许多网站允许你与艺术家、音响工程师甚至程序员签约。其中最大的一个是 Upwork(www.Upwork.com)。你可以免费加入这个网站并发布你的工作。你需要对你的要求写一个清晰的解释,并说明你准备支付多少。然后,你可能会得到一个很好的选择承包商投标做这项工作。然而,请注意,有许多不合格的承包商的工作可能令人失望,但如果你仔细选择,你可能会找到一位称职、热情、有价值的人或公司来做这项工作。

制作自己的声音特效

音效可以从 Freesound(www.Freesound.org等网站免费下载,但如果您正在销售游戏,许可证通常不允许您使用音效。另一种选择是使用来自www.BFXR.net的名为 BFXR 的开源软件,它可以帮助您生成许多不同的音效,您可以根据自己的喜好保留和处理这些音效。

将资产添加到项目中

一旦决定了要使用哪些资产,就应该将它们添加到项目中。以下说明假设您正在使用本书下载包中提供的所有资产。当您使用自己的文件时,只需使用完全相同的文件名将相应的声音或图形文件替换为您自己的文件:

  1. 浏览到项目文件夹,即D:\VS Projects\Timber
  2. 在此文件夹中创建三个新文件夹,并将其命名为graphicssoundfonts
  3. 从下载包中,将Chapter 1/graphics 的全部内容复制到D:\VS Projects\Timber\graphics文件夹中。
  4. 从下载包中,将Chapter 1/sound的全部内容复制到D:\VS Projects\Timber\sound文件夹中。
  5. 现在,请访问http://www.1001freefonts.com/komika_poster.font 在您的网络浏览器中点击并下载Komika 海报字体。
  6. 提取压缩下载的内容并将KOMIKAP_.ttf文件添加到D:\VS Projects\Timber\fonts文件夹中。

让我们来看看这些资产,特别是图形,以便我们可以看到当我们在 C++ 代码中使用的时候发生了什么。

探索资产

图形资源构成了场景的一部分,即我们的木材!!!游戏如果你看一看图形资产,就应该清楚在我们的游戏中将在哪里使用它们:

声音文件都是.wav格式。这些文件包含我们将在游戏中的某些事件中播放的声音效果。它们都是使用 BFXR 生成的,如下所示:

  • chop.wav:有点像斧头(复古斧头)砍树的声音
  • death.wav:有点像复古“失落”的声音
  • out_of_time.wav:当玩家因时间不足而输球时发出的声音,而不是被压扁的声音

我们已经看到了所有的资产,包括图形,所以现在我们将有一个关于屏幕分辨率的简短讨论,以及我们如何在屏幕上定位图形。

了解屏幕和内部坐标

在我们转到实际 C++ 代码之前,让我们来谈谈坐标。我们在显示器上看到的所有图像都是由像素构成的。像素是微小的光点,它们结合在一起形成我们看到的图像。

有许多不同的监视器分辨率,但作为一个例子,考虑到一个相当典型的游戏监视器可能有 1920 个像素水平和 1080 个像素垂直。

像素从屏幕左上角开始编号。如下图所示,我们的 1920 x 1080 示例在水平(x)轴上编号为 0 到 1919,在垂直(y)轴上编号为 0 到 1079:

因此,可以通过 x 和 y 坐标确定特定和准确的屏幕位置。我们通过将游戏对象(如背景、角色、项目符号和文本)绘制到屏幕上的特定位置来创建游戏。这些位置由像素的坐标标识。看看下面这个假设的例子,我们可以在屏幕的大致中心坐标处进行绘制。在 1920 x 1080 屏幕的情况下,这将位于 960540 位置:

除了屏幕坐标外,我们的游戏对象也将拥有各自相似的坐标系。与屏幕坐标系一样,它们的内部本地坐标从左上角的 0,0 开始。

在前面的图像中,我们可以看到在屏幕的 960540 处绘制了字符的 0,0。

一个可视的 2D 游戏对象,比如一个角色或者一个僵尸,被称为精灵。精灵通常由图像文件制作。所有精灵都有所谓的起源

如果我们将精灵绘制到屏幕上的特定位置,则原点将位于该特定位置。精灵的 0,0 坐标是其原点。下图演示了这一点:

因此,在显示绘制到屏幕上的字符的图像中,尽管我们在中心位置(960540)绘制了图像,但它看起来有点向右和向下。

了解这一点很重要,因为它将帮助我们理解绘制所有图形时使用的坐标。

重要提示

请注意,在现实世界中,游戏玩家有各种各样的屏幕分辨率,我们的游戏需要使用尽可能多的分辨率。在第三个项目中,我们将看到如何使我们的游戏动态地适应几乎任何分辨率。在第一个项目中,我们需要假设屏幕分辨率为 1920 x 1080。如果您的屏幕分辨率更高,这将是好的。不要担心,如果你的屏幕低于这一点,因为我已经提供了一套单独的代码为每一章的木材!!!游戏除了在开头添加和交换几行代码之外,代码文件几乎完全相同。如果您的屏幕分辨率较低,那么只需按照本书中的代码进行操作,假设您的分辨率为 1920 x 1080。在试用游戏时,您可以根据需要复制并粘贴前五章low res文件夹中的代码文件。事实上,一旦从第一章中添加了额外的行,所有其余的代码都将是相同的,无论您的屏幕分辨率如何。为了方便起见,我为每一章提供了低分辨率代码。第三个项目将讨论这几行代码如何发挥其魔力(缩放屏幕)。可供选择的代码将在低至 960 x 540 的分辨率下工作,因此在几乎任何 PC 或笔记本电脑上都可以。

现在,我们可以编写第一段 C++ 代码,并在动作中看到它。

开始编写游戏代码

如果 Visual Studio 尚未打开,请打开它。打开木材!!!通过在 Visual Studio 主窗口上的最近列表中左键单击项目。

找到右侧的解决方案资源管理器窗口。在源文件文件夹下找到Timber.cpp文件。

重要提示

.CPP 用于 C Plus。

删除“代码”窗口的全部内容并添加以下代码,以便您自己拥有相同的代码。你可以用与任何文本编辑器或文字处理器相同的方式来实现这一点;如果您愿意,您甚至可以复制并粘贴它。在您进行编辑后,我们可以讨论:

// This is where our game starts from
int main()
{
    return 0;
}

这个简单的 C++ 程序是个好地方。让我们一行一行地看一遍。

通过注释使代码更清晰

第一行代码如下:

// This is where our game starts from

任何以两个正斜杠(//开头的代码行都是注释,编译器会忽略它。因此,这行代码不起任何作用。它用于在以后返回代码时留下任何有用的信息。注释在行尾结束,因此下一行的任何内容都不是注释的一部分。还有另一种类型的注释称为多行c 风格注释,可用于留下占用多行的注释。我们将在本章后面看到其中一些。在本书中,我将留下数百条注释,以帮助添加上下文并进一步解释代码。

主要功能

我们在代码中看到的下一行如下:

int main()

int是一种被称为的物质。C++ 有多种类型,它们代表不同类型的数据。int整数或整数。等一下,我们马上就回来。

main()部分是后面代码段的名称。代码部分在开始的花括号({和下一个结束的花括号(}之间标出。

因此,这些花括号{...}之间的所有内容都是main的一部分。我们将这样的代码段称为函数

每一个 C++ 程序都有一个函数,它是整个程序开始执行的一个地方。随着我们阅读本书,最终,我们的游戏将有许多代码文件。然而,只有一个main函数,无论我们编写什么代码,我们的游戏都将从main函数开头的花括号内的第一行代码开始执行。

现在,不要担心函数名()后面的奇怪括号。我们将在第 4 章【循环、数组、开关、枚举和函数——实现游戏机制中进一步讨论它们,届时我们将以全新的、更有趣的角度看待函数。

让我们仔细看看main函数中的一行代码。

呈现和语法

再看看我们的main功能的整体:

int main()
{
    return 0;
}

我们可以看到,在Main中,只有一行代码return 0;。在我们继续了解这行代码的作用之前,让我们先看看它是如何呈现的。这很有用,因为它可以帮助我们准备编写易于阅读且与代码的其他部分不同的代码。

首先,请注意, return 0;向右缩进一个制表符。这清楚地表明它是main函数的内部。随着代码长度的增长,我们将看到缩进代码并留下空白对于保持可读性至关重要。

接下来,注意这行末尾的标点符号。分号(;)告诉编译器它是指令的结尾,后面的任何内容都是新指令。我们将以分号结尾的指令称为 astatement

请注意,编译器并不关心是否在分号和下一个语句之间留下新行或空格。但是,如果没有为每个语句开始一行,则会导致代码极难读取,并且完全缺少分号将导致语法错误,游戏将无法编译或运行。

一段代码加在一起,通常由其与该段其余部分的缩进表示,称为

现在您已经熟悉了main函数的概念,缩进代码以保持整洁,并在每个语句的末尾加上分号,我们可以继续了解return 0;语句的实际功能。

从函数返回值

实际上,return 0;在我们的游戏环境中几乎什么都不做。然而,这一概念很重要。当我们使用return关键字时,无论是单独使用还是后跟一个值,它都是一条指令,用于程序执行跳转/移回最初启动函数的代码。

通常,启动函数的代码将是代码中其他地方的另一个函数。然而,在这种情况下,是操作系统启动了main功能。因此,当执行return 0;时,main函数退出,整个程序结束。

由于在return关键字后面有一个0,该值也会发送到操作系统。我们可以将 0 的值更改为其他值,该值将被发送回。

我们说启动函数的代码调用函数,函数返回值。

您还不需要完全掌握所有这些函数信息。在这里介绍它很有用。在我们继续之前,我将介绍函数的最后一件事。还记得int main()中的int吗?这告诉编译器从main返回的值的类型必须是int(整数/整数)。我们可以返回任何符合int条件的值;可能是 0、1999、6358 等等。如果我们尝试返回的不是int,或者 12.76,那么代码将无法编译,游戏也无法运行。

函数可以返回大量不同类型的选择,包括我们为自己发明的类型!但是,必须以我们刚才看到的方式让编译器知道该类型。

这一点关于函数的背景信息将使事情在我们前进的过程中变得更加顺利。

运行游戏

你甚至可以在这一点上运行游戏。通过单击 Visual Studio 快速启动栏中的本地 Windows 调试器按钮来执行此操作。或者,您可以使用F5快捷键:

你只会得到一个黑屏。如果黑屏不能自动关闭,您可以点击任意键将其关闭。这个窗口是 C++ 控制台,我们可以用它调试我们的游戏。我们现在不需要这样做。我们的程序正在启动,从main的第一行即return 0;开始执行,然后立即退出回到操作系统。

我们现在有了可能编码和运行的最简单的程序。我们现在将添加一些代码来打开一个窗口,游戏最终将出现在其中。

使用 SFML 打开窗口

现在,让我们再添加一些代码。下面的代码将使用 SFML 打开一个窗口!!!最终会发生冲突。窗口宽 1920 像素,高 1080 像素,全屏显示(无边框或标题)。

将此处突出显示的新代码输入到现有代码中,然后我们将对其进行检查。键入(或复制粘贴)时,请尝试了解发生了什么:

// Include important libraries here
#include <SFML/Graphics.hpp>
// Make code easier to type with “using namespace”
using namespace sf;
// This is where our game starts from
int main()
{
 // Create a video mode object
 VideoMode vm(1920, 1080);
 // Create and open a window for the game
 RenderWindow window(vm, “Timber!!!”, Style::Fullscreen);
return 0;
}

#包括 SFML 功能

我们将在新代码中注意到的第一件事是#include指令。

#include指令告诉 Visual Studio 在编译之前包括或添加另一个文件的内容。这样做的结果是,当我们运行程序时,一些我们自己没有编写的其他代码将成为程序的一部分。将其他文件中的代码添加到我们的代码中的过程称为预处理,并且可能毫不奇怪地由一个称为预处理器的程序执行。.hpp文件扩展名表示它是文件。

因此,#include <SFML/Graphics.hpp>告诉预处理器包含名为SFML.的文件夹中包含的Graphics.hpp文件的内容。它与我们在设置项目时创建的文件夹相同。

这一行添加了上述文件中的代码,这使我们能够访问 SFML 的一些特性。当我们开始编写自己的独立代码文件并使用#include使用它们时,它是如何实现这一点的将变得更加清晰。

我们将在本书中包括的主要文件是 SFML 头文件,它使我们能够访问所有酷的游戏编码特性。我们还将使用 AutoT0TAL 访问 OLE T1E.C++ 标准库 ALE T2A.头文件。这些头文件使我们能够访问 C++ 语言本身的核心特性。

现在重要的是,如果我们添加这一行代码,就可以使用 SFML 提供的一整套新功能。

下一条新线是using namespace sf;。我们将很快回到这条线的功能。

面向对象、类和对象

在阅读本书的过程中,我们将全面讨论 OOP、类和对象。下面是一个简短的介绍,以便我们了解正在发生的事情。

我们已经知道 OOP 代表面向对象编程。OOP 是一种编程范式,即一种编码方式。OOP 在编程界几乎每种语言中都被公认为是编写代码的最好、甚至是唯一的专业方法。

OOP 引入了很多编码概念,但它们的基础都是对象。在编写代码时,只要可能,我们都希望编写可重用、可维护和安全的代码。我们这样做的方式是将代码结构化为一个类。我们将在第 6 章【面向对象编程——开始乒乓球游戏中学习如何做到这一点。

我们现在需要知道的关于类的一切是,一旦我们编码了类,我们就不只是在游戏中执行代码;相反,我们从类的创建可用对象*。*

例如,如果我们想要 100 个僵尸NPCs(非玩家角色,我们可以仔细设计并编写一个名为Zombie的类,然后从这个类中创建我们喜欢的任意多个僵尸对象。每个僵尸对象都具有相同的功能和内部数据类型,但每个僵尸对象都是一个独立的实体。

为了进一步说明假设的僵尸示例,但不显示Zombie类的任何代码,我们可以基于Zombie类创建一个新对象,如下所示:

Zombie z1;

z1对象现在是一个完全编码并运行的Zombie对象。我们可以这样做:

Zombie z2;
Zombie z3;
Zombie z4;
Zombie z5;

我们现在有五个独立的Zombie实例,但它们都基于一个精心编码的类。在我们回到刚才编写的代码之前,让我们再进一步。我们的僵尸可以包含行为(由函数定义)和数据,这些数据可能表示僵尸的健康状况、速度、位置或旅行方向。例如,我们可以编写我们的Zombie类,使我们能够使用Zombie对象,可能如下所示:

z1.attack(player);
z2.growl();
z3.headExplode();

重要提示

请再次注意,目前所有这些僵尸代码都是假设的。不要在 Visual Studio 中键入此代码–它只会产生一系列错误。

我们将设计我们的类,以便我们能够以最合适的方式使用数据和行为,以符合我们游戏的目标。例如,我们可以设计类,以便在创建每个僵尸对象时为其分配数据值。

假设我们需要在创建每个僵尸时指定一个唯一的名称和速度(以米/秒为单位)。仔细编写Zombie类可以让我们编写如下代码:

// Dave was a 100 metre Olympic champion before infection 
// He moves at 10 metres per second
Zombie z1(“Dave”, 10);
// Gill had both of her legs eaten before she was infected
// She drags along at .01 metres per second
Zombie z2(“Gill”, .01);

关键是类几乎是无限灵活的,一旦我们对类进行了编码,我们就可以通过创建它们的对象/实例来使用它们。正是通过类和从中创建的对象,我们才能利用 SFML 的强大功能。是的,我们还将编写自己的类,包括一个Zombie类。

让我们回到刚才编写的真实代码。

使用名称空间 sf

在我们继续深入研究VideoModeRenderWindow之前,我们将了解using namespace sf; 行代码的作用,您可能已经猜到它们是由 SFML 提供的类。

当我们创建一个类时,我们在一个名称空间中这样做。我们这样做是为了将我们的类与其他人编写的类区分开来。考虑一下这个类。在 Windows 这样的环境中,完全有可能已经有人编写了一个名为VideoMode的类。通过使用名称空间,我们和 SFML 程序员可以确保类的名称永远不会冲突。

VideoMode类的完整使用方式如下:

sf::VideoMode...

using namespace sf; 允许我们在代码中的任何地方省略sf::前缀。如果没有它,仅在这个简单的游戏中就有 100 多个sf::实例。它还使我们的代码更可读,也更短。

SFML 视频模式和渲染窗口

main函数中,我们现在有两条新注释和两行新的实际代码。实际代码的第一行是:

VideoMode vm(1920, 1080);

此代码从名为VideoMode的类中创建一个名为vm的对象,并设置两个内部值19201080。这些值表示玩家屏幕的分辨率。

下一行新代码如下所示:

RenderWindow window(vm, “Timber!!!”, Style::Fullscreen);

在前一行代码中,我们正在从 SFML 提供的名为RenderWindow的类创建一个名为window的新对象。此外,我们正在窗口对象内设置一些值。

首先,使用vm对象初始化window的一部分。起初,这似乎令人困惑。但是,请记住,类可以根据其创建者的意愿而变化和灵活。是的,一些类可以包含其他类的其他实例。

提示

只要您理解这个概念,就没有必要在此时完全理解它是如何工作的。我们编写一个类,然后从该类中生成可用的对象——有点像架构师绘制蓝图。你当然不能把你所有的家具、孩子和狗都搬到蓝图中去,但你可以从蓝图中建造一座房子(或许多房子)。在这个类比中,类就像蓝图,对象就像房子。

接下来,我们使用“Timber!!!”值为窗口命名。然后,我们使用预定义的Style::FullScreen值使window对象全屏显示。

提示

Style::FullScreen是在 SFML 中定义的值。它很有用,因为我们不需要记住内部代码用来表示全屏的整数。此类值的编码术语为constant。常数和它们的密切 C++ 亲属,Po.T2 变量。

让我们看一看正在运行的窗口对象。

运行游戏

此时您可以再次运行游戏。你会看到一个更大的黑屏闪烁,然后消失。这是我们刚刚编码的 1920 x 1080 全屏窗口。不幸的是,我们的程序仍然在启动,从main的第一行开始执行,创建一个很酷的新游戏窗口,然后进入return 0;并立即退出回到操作系统。

接下来,我们将添加一些代码,这些代码将构成本书中每个游戏的基本结构。这就是所谓的游戏循环。

主游戏循环

我们需要一种方法,在玩家想要退出之前一直留在程序中。同时,我们应该清楚地标出代码的不同部分将在我们使用木材的过程中走向何处!!!。此外,如果我们要阻止我们的游戏退出,我们最好在玩家准备好时为他们提供退出的方式;否则,游戏将永远继续下去!

将以下突出显示的代码添加到现有代码中,然后我们将浏览并讨论所有代码:

int main()
{
// Create a video mode object
VideoMode vm(1920, 1080);
// Create and open a window for the game
RenderWindow window(vm,	“Timber!!!”, Style::Fullscreen);
 while (window.isOpen())
 {
 /*
 ****************************************
 Handle the players input
 ****************************************
 */
 if (Keyboard::isKeyPressed(Keyboard::Escape))
 {
 window.close();
 }
 /*
 ****************************************
 Update the scene
 ****************************************
 */
 /*
 ****************************************
 Draw the scene
 ****************************************
 */
 // Clear everything from the last frame
 window.clear();
 // Draw our game scene here
 // Show everything we just drew
 window.display();
 }
    return 0;
}

While 循环

我们在新代码中看到的第一件事如下:

while (window.isOpen())
{

我们在新代码中看到的最后一件事是结束}。我们已经创建了一个while循环。在while循环的开始({和结束(}括号)之间的一切都将继续执行,一次又一次,可能永远。

仔细观察while循环的括号(...)之间,如下所示:

while (window.isOpen())

这段代码的完整解释必须等到我们在第 4 章中讨论循环和条件,循环、数组、开关、枚举和函数——实现游戏机制。现在重要的是,当window对象被设置为 closed 时,代码的执行将跳出while循环并转到下一条语句。窗户是如何关上的,很快就有人知道了。

当然,下一句话是return 0;,它结束了我们的游戏。

我们现在知道我们的while循环会一圈又一圈地旋转,重复执行其中的代码,直到我们的 window 对象被设置为 closed。

C 型代码注释

就在while循环内部,我们可以看到乍一看可能有点像 ASCII 艺术:

/*
****************************************
Handle the player’s input
****************************************
*/

重要提示

ASCII 艺术是一种利用计算机文本创建图像的利基但有趣的方式。您可以在此处阅读更多信息:https://en.wikipedia.org/wiki/ASCII_art

前面的代码只是另一种注释类型。这种类型的注释称为 C 风格的注释。注释以(/*开头,以(*/结尾)。介于两者之间的任何内容都只是为了提供信息,而不是编译。我已经使用了这个稍微复杂的文本来明确我们将在代码文件的每个部分中做什么。当然,您现在可以计算出,下面的任何代码都与处理玩家的输入有关。

跳过几行代码,您将看到我们有另一个 C 风格的注释,宣布在代码的这一部分,我们将更新场景。

如果你跳到下一个 C 风格的评论,我们将在哪里绘制所有的图形就很清楚了。

输入、更新、绘制、重复

尽管第一个项目使用了最简单的游戏循环版本,但每个游戏都需要代码中的这些阶段。让我们看一下步骤:

  1. 获取玩家的输入(如果有)。
  2. 根据人工智能、物理或玩家输入等内容更新场景。
  3. 绘制当前场景。
  4. 以足够快的速度重复这些步骤,以创建一个平滑、动画的游戏世界。

现在,让我们看看在游戏循环中实际执行某些操作的代码。

检测按键

首先,在注释可识别的部分中,我们有以下代码:

if (Keyboard::isKeyPressed(Keyboard::Escape))
{
 window.close();
}

此代码检查当前是否按下了Esc键。如果是,突出显示的代码使用window对象关闭自身。现在,下次while循环开始时,它将看到window对象已关闭,并在while循环的关闭花括号后立即跳转到代码,游戏将退出。我们将在第 2 章中更全面地讨论 if语句、变量、运算符和决策–设置精灵动画

清理并绘制场景

目前,Update the scene部分中没有代码,所以让我们转到Draw the scene部分。

我们要做的第一件事是使用以下代码擦去动画的前一帧:

window.clear();

我们现在要做的是从游戏中抽出每一个物体。但是,我们没有任何游戏对象。

下一行代码如下:

window.display();

当我们绘制所有游戏对象时,我们正在将它们绘制到一个隐藏的曲面,以便显示。window.display()代码从先前显示的表面翻转到新更新(先前隐藏)的表面。这样,玩家将永远看不到绘制过程,因为曲面上添加了所有精灵。它还保证场景在翻转之前是完整的。这可以防止被称为撕裂的图形故障。这个过程称为双缓冲

还要注意,所有这些绘图和清除功能都是使用我们的window对象执行的,该对象是从 SFMLRenderWindow类创建的。

运行游戏

运行游戏,您将获得一个空白的全屏窗口,该窗口将一直打开,直到您按下Esc键。

这是一个良好的进展。在这个阶段,我们有一个正在执行的程序,它打开一个窗口并循环,等待玩家按Esc键退出。现在,我们可以继续绘制游戏的背景图像。

绘制游戏背景

现在,我们将在游戏中看到一些图形。我们需要做的是创建一个精灵。我们将创建的第一个将是游戏背景。然后我们可以在清除窗口和显示/翻转窗口之间绘制它。

使用纹理准备雪碧

SFMLRenderWindow类允许我们创建window对象,该对象基本上负责游戏窗口所需的所有功能。

现在我们来看另外两个 SFML 类,它们将负责将精灵绘制到屏幕上。也许毫不奇怪,其中一个类被称为Sprite。另一个类称为Texture。纹理是存储在存储器中的图形,在图形处理单元GPU上)。

Sprite类生成的对象需要由Texture类生成的对象才能将自身显示为图像。添加以下突出显示的代码。试着弄清楚到底发生了什么。然后,我们将一行一行地通过它:

int main()
{
    // Create a video mode object
    VideoMode vm(1920, 1080);
    // Create and open a window for the game
    RenderWindow window(vm,	“Timber!!!”, Style::Fullscreen);
    // Create a texture to hold a graphic on the GPU
    Texture textureBackground;
    // Load a graphic into the texture
    textureBackground.loadFromFile(“graphics/background.png”);
    // Create a sprite
    Sprite spriteBackground;
    // Attach the texture to the sprite
    spriteBackground.setTexture(textureBackground);
    // Set the spriteBackground to cover the screen
    spriteBackground.setPosition(0,0);
    while (window.isOpen())
    {

首先,我们从 SFMLTexture类创建一个名为textureBackground的对象:

Texture textureBackground;

完成后,我们可以使用textureBackground对象将图形从graphics文件夹加载到textureBackground,如下所示:

textureBackground.loadFromFile(“graphics/background.png”);

提示

我们只需要指定graphics/background,因为路径是相对于我们创建文件夹并添加图像的 Visual Studio工作目录的。

接下来,我们使用以下代码从 SFMLSprite类创建一个名为spriteBackground的对象:

Sprite spriteBackground;

然后,我们可以将Texture对象backgroundTextureSprite对象backgroundSprite关联起来,如下所示:

spriteBackground.setTexture(textureBackground);

最后,我们可以将spriteBackground对象定位在window对象的0,0坐标处:

spriteBackground.setPosition(0,0);

由于图形文件夹中的background.png图形宽 1920 像素,高 1080 像素,因此它将整齐地填充整个屏幕。请注意,前一行代码实际上并没有显示精灵。它只是设置它的位置,为显示它做好准备。

backgroundSprite对象现在可用于显示背景图形。当然,你几乎肯定想知道为什么我们要以如此复杂的方式做事。原因在于图形卡和 OpenGL 的工作方式。

纹理占用图形内存,而这个内存是一个有限的资源。此外,将图形加载到 GPU 内存中的过程非常缓慢——速度不会太慢,以至于你可以看到它发生,或者在它发生时你会看到你的电脑明显变慢,但速度足够慢,以至于你无法在游戏循环的每一帧都这样做。因此,将实际纹理(textureBackground与我们将在游戏循环期间操纵的任何代码分离是非常有用的。

正如您将看到的,当我们开始移动图形时,我们将使用 sprite 进行移动。任何由Texture类生成的对象都会愉快地坐在 GPU 上,只需等待相关的Sprite对象告诉它在哪里显示自己。在以后的项目中,我们还将使用多个不同的Sprite对象重用相同的Texture对象,这将有效利用 GPU 内存。

总之,我们可以陈述如下:

  • 纹理加载到 GPU 的速度非常慢。
  • 纹理一旦在 GPU 上就可以快速访问。
  • 我们将Sprite对象与纹理相关联。
  • 我们操纵Sprite对象的位置和方向(通常在Update the scene 部分)。

我们绘制Sprite对象,它依次显示与其关联的Texture对象(通常在Draw the scene 部分)。所以,我们现在需要做的就是使用我们的双缓冲系统,这是由我们的window对象提供的,来绘制我们的新Sprite对象(spriteBackground,我们应该可以看到我们的游戏在运行。

双缓冲背景精灵

最后,我们需要在游戏循环中的适当位置绘制该精灵及其相关纹理。

提示

请注意,当我呈现来自同一块的代码时,我不会添加缩进,因为它减少了书籍文本中换行的实例。缩进是隐含的。查看下载包中的代码文件,了解缩进的充分使用。

添加以下突出显示的代码:

/*
****************************************
Draw the scene
****************************************
*/
// Clear everything from the last run frame
window.clear();
// Draw our game scene here
window.draw(spriteBackground);
// Show everything we just drew
window.display();

新的代码行简单地使用window对象来绘制spriteBackground对象,介于清除显示和显示新绘制的场景之间。

我们现在知道了精灵是什么,我们可以将纹理与之关联,然后将其放置在屏幕上,最后绘制它。游戏已经准备好再次运行,这样我们就可以看到这段代码的结果了。

运行游戏

如果我们现在运行该程序,我们将看到第一个迹象,表明我们正在进行一场真正的游戏:

在目前的状态下,它不会在 Steam 上获得年度独立游戏,但至少我们已经在路上了!

让我们看看本章中可能出现的一些错误,以及在我们继续阅读本书时。

处理错误

你做的每一个项目都会有问题和错误。这是保证!问题越棘手,解决问题时就越令人满意。经过数小时的努力,当一个新的游戏功能终于出现时,它可能会引起真正的高潮。如果没有这场斗争,它将不知何故变得不值得。

在这本书的某个时候,可能会有一些挣扎。保持冷静,相信你会克服它,然后开始工作。

记住,不管你有什么问题,你很可能不是世界上第一个有同样问题的人。想一个简洁的句子来描述你的问题或错误,然后把它输入谷歌。你会惊讶地发现,别人已经很快、准确、经常地为你解决了问题。

话虽如此,这里有一些指针(双关语;参见第 10 章、指针、标准模板库和纹理管理)可以帮助您开始,以防您在努力使第一章起作用。

配置错误

本章中出现问题的最可能原因是配置错误。正如您在设置 VisualStudio、SFML 和项目本身的过程中可能注意到的那样,有很多文件名、文件夹和设置需要恰到好处。仅仅一个错误的设置就可能导致一系列错误中的一个,这些错误的文本并不能确切地说明什么是错误的。

如果您无法在黑屏工作的情况下获得空项目,那么重新开始可能会更容易。确保所有文件名和文件夹都适合您的特定设置,然后运行代码的最简单部分。这是屏幕闪烁黑色然后关闭的部分。如果您能够达到这个阶段,那么配置可能不是问题。

编译错误

编译错误可能是我们今后遇到的最常见的错误。检查您的代码是否与我的代码相同,尤其是行末尾的分号以及类和对象名称的大小写的细微变化。如果所有其他操作都失败,请打开下载包中的代码文件,然后复制并粘贴它。虽然本书中总是有可能出现代码输入错误,但代码文件是从实际工作项目中生成的——它们确实有效!

链路错误

链接错误很可能是由于缺少 SFML.dll文件造成的。你把它们都复制到项目文件夹了吗?

虫子

bug 是代码工作时发生的事情,但并不像您期望的那样。调试其实很有趣。你挤压的虫子越多,你的游戏就越好,你一天的工作也就越令人满意。解决 bug 的诀窍是尽早发现它们!要做到这一点,我建议您在每次实现新功能时运行和玩游戏。你越早发现这个 bug,你就越有可能对其原因记忆犹新。在本书中,我们将运行代码以查看每个可能阶段的结果。

总结

这是一个相当具有挑战性的章节,也许作为第一章有点刻薄。确实,配置一个 IDE 来使用 C++ 库可能有点尴尬和长。此外,众所周知,类和对象的概念对于不熟悉编码的人来说有点尴尬。

现在,我们在这个阶段,但是,我们可以完全集中在 C++,SFML 和游戏。随着我们这本书的进步,我们将学习越来越多的 C++,以及实现越来越有趣的游戏功能。在这样做的同时,我们将进一步了解函数、类和对象等内容,以帮助它们更加神秘化。

我们在本章中已经取得了大量的成果,包括概述了一个具有基本功能的 C++ 程序,构造了一个简单的游戏循环,它可以监听玩家的输入,并将精灵(连同其相关的纹理)绘制到屏幕上。

在下一章中,我们将学习所有 C++,我们需要画更多的精灵并激活它们。

常见问题

以下是您可能想到的一些问题:

Q) 到目前为止,我一直在为所呈现的内容而挣扎。我适合编程吗?

A) 在本书中,设置一个开发环境并将 OOP 作为一个概念来考虑可能是最难的事情。只要游戏正常运行(绘制背景),就可以继续下一章。

Q) 所有这些关于 OOP、类和对象的讨论太多了,有点破坏了整个学习体验。

A) 别担心。我们将不断回到 OOP、类和对象。在第 6 章面向对象编程——开始乒乓球游戏中,我们将真正开始掌握整个 OOP。您现在需要了解的是,SFML 已经编写了大量有用的类,我们可以通过从这些类创建可用对象来使用这些代码。

Q) 我真的不懂这个函数。

A) 没关系;我们将不断地再次回到它,并将更彻底地了解函数。你只需要知道,当函数被调用时,它的代码被执行,当它完成(到达return语句)时,程序跳回调用它的代码。