C 游戏编程入门外文翻译资料

 2022-05-19 10:05

Beginning C Game Programming

John Horton

Chapter 5 Collisions, Sound, and End Conditions – Making the Game Playable

This is the final phase of the first project. By the end of this chapter you will have your first completed game. Once you have Timber!!! up-and-running, be sure to read the last section of this chapter as it will suggest ways to make the game better. We will be looking at the following topics:

Adding the rest of the sprites

Handling the player input

Animating the flying log Handling death

Adding sound effects

Adding features and improving Timber!!!

Preparing the player (and other sprites)

Let#39;s add the code for the player#39;s sprite, as well as a few more sprites and textures at the same time. This next, quite large, block of code also adds a gravestone sprite for when the player gets squished, an ax sprite to chop with, and a log sprite that can whiz away each time the player chops.

Notice that after the spritePlayer object we also declare a side variable, playerSide, to keep track of where the player is currently standing. Furthermore, we add some extra variables for the spriteLog object, including, logSpeedX, logSpeedY, and logActive to store how fast the log will move, and whether it is currently moving. The spriteAxe also has two related float constant variables to remember where the ideal pixel position is on both the left and the right.

Add this next block of code just before the while(window.isOpen()) code as we have done so often before. Note that all the code in this next listing is new, not just the highlighted code. I haven#39;t provided any extra context for the next block of code as while(window.isOpen()) should be easy to identify. The highlighted code is the code we have just specifically discussed.

Add the entirety of this code, just before the while(window.isOpen()) line, and make a mental note of the highlighted lines we have briefly discussed. It will make the rest of the chapter#39;s code easier to understand:

// Prepare the player Texture texturePlayer; texturePlayer.loadFromFile('graphics/player.png'); Sprite spritePlayer; spritePlayer.setTexture(texturePlayer); spritePlayer.setPosition(580, 720);

// The player starts on the left side playerSide = side::LEFT;

// Prepare the gravestone Texture textureRIP; textureRIP.loadFromFile('graphics/rip.png'); Sprite spriteRIP; spriteRIP.setTexture(textureRIP); spriteRIP.setPosition(600, 860);

// Prepare the axe Texture textureAxe; textureAxe.loadFromFile('graphics/axe.png'); Sprite spriteAxe; spriteAxe.setTexture(textureAxe); spriteAxe.setPosition(700, 830);

// Line the axe up with the tree const float AXE_POSITION_LEFT = 700; const float AXE_POSITION_RIGHT = 1075;

// Prepare the flying log

Texture textureLog; textureLog.loadFromFile('graphics/log.png'); Sprite spriteLog; spriteLog.setTexture(textureLog); spriteLog.setPosition(810, 720);

// Some other useful log related variables bool logActive = false; float logSpeedX = 1000; float logSpeedY = -1500;

Now we can draw all our new sprites.

Drawing the player and other sprites

Before we add the code to move the player and use all our new sprites, let#39;s draw them. This is so that, as we add code to update/change/move the sprites, we will be able to see what is happening.

Add the highlighted code to draw the four new sprites:

// Draw the tree window.draw(spriteTree);

// Draw the player window.draw(spritePlayer);

// Draw the axe window.draw(spriteAxe);

// Draraw the flying log window.draw(spriteLog);

// Draw the gravestone window.draw(spriteRIP);

// Draw the bee window.draw(spriteBee);

Run the game and you will see our new sprites in the scene.

We are really close to a working game now.

Handling the player#39;s input

Lots of different things depend on the movement of the player, such as when to show the ax, when to begin animating the log, and when to move all the branches down a place. It therefore makes sense to set up the keyboard handling for the player chopping. Once this is done, we can put all the features we just mentioned into the same part of the code.

Let#39;s think for a moment about how we detect keyboard presses. In each frame we test whether a particular keyboard key is currently being held down. If it is, we take action. If the Esc key is being held down, we quit the game, or if the Enter key is being held down we restart the game. So far, this has been sufficient for our needs.

There is, however, a problem with this approach when we try and handle the chopping of the tree. The problem has always been there, it just didn#39;t matter until now. Depending on how powerful your PC is, the game loop could be executing thousands of times per second. Each and every pass through the game loop during which a key is held down, it is detected and the related code will execute.

So actually, every time you press Enter to restart the game, you are most likely restarting it well in excess of a hundred times. This is because even the briefest of presses will last a significant fraction of a second. You can verify this by running the game and holding down the Enter key. Note that the time bar doesn#39;t move. This is because the game is being restarted over and over again, hundreds, or even thousands, of times a second.

If we don#39;t use a different approach for the player chopping, then just one attempted chop will bring the entire tree down in a mere fraction of a second. We need to be a bit more sophisticated. What we will do is allow the player to chop then, when he does so, disable the code that detects a key press. We will then detect when the player removes his finger from a key and then re-enable the detection of key presses.

全文共24705字,剩余内容已隐藏,支付完成后下载完整资料


C 游戏编程入门

约翰·霍顿

第5章 碰撞,声音和结束条件 - 使游戏可玩

这是第一个项目的最后阶段。在本章的最后,你将会完成你的第一个游戏。请务必阅读到本章的最后一节,因为它会提示如何让游戏变得更好。 我们将着重围绕以下主题展开:

添加其余的精灵;

处理玩家输入;

制作处理死亡的飞行日志;

添加声音效果;

添加功能并改进木材。

准备玩家(以及其他精灵)

让我们添加玩家的精灵和纹理的代码。接下来,继续添加一段代码,描述在玩家被压扁时,添加一块墓碑精灵,一个斧头精灵和一个每当玩家劈到它时都会消失的日志精灵。

请注意,在spritePlayer对象之后,我们还会声明一个副变量playerSide,以跟踪玩家当前的位置。此外,我们为spriteLog对象添加了一些额外的变量,包括logSpeedX,logSpeedY和logActive来存储日志移动的速度以及当前是否正在移动。spriteAxe还有两个相关的浮点型常量来记住理想像素位置在左右两侧的位置。

在while(window.isOpen())代码之前添加下面的代码块,和我们之前做的一样。请注意,下一个列表中的所有代码都是新的,而不仅仅是突出显示的代码。我没有为下一块代码提供任何额外的上下文,因为while(window.isOpen())应该很容易识别。突出显示的代码是我们刚才特别讨论的代码。

在while(window.isOpen())行之前添加此代码的全部内容,并对我们简要讨论的突出显示的行进行记录。这将使本章的其余部分代码更易于理解:

// Prepare the player Texture texturePlayer;

texturePlayer.loadFromFile('graphics/player.png');

Sprite spritePlayer;

spritePlayer.setTexture(texturePlayer);

spritePlayer.setPosition(580, 720);

// The player starts on the left side playerSide = side::LEFT;

// Prepare the gravestone Texture textureRIP;

textureRIP.loadFromFile('graphics/rip.png');

Sprite spriteRIP;

spriteRIP.setTexture(textureRIP);

spriteRIP.setPosition(600, 860);

// Prepare the axe Texture textureAxe;

textureAxe.loadFromFile('graphics/axe.png');

Sprite spriteAxe;

spriteAxe.setTexture(textureAxe);

spriteAxe.setPosition(700, 830);

// Line the axe up with the tree const float AXE_POSITION_LEFT = 700;

const float AXE_POSITION_RIGHT = 1075;

// Prepare the flying log

Texture textureLog;

textureLog.loadFromFile('graphics/log.png');

Sprite spriteLog; spriteLog.setTexture(textureLog);

spriteLog.setPosition(810, 720);

// Some other useful log related variables

bool logActive = false; float logSpeedX = 1000; float logSpeedY = -1500;

现在我们可以画出所有的精灵了。

绘制玩家和其他精灵

在我们添加代码来移动玩家并使用所有新的精灵之前,让我们先来绘制它们。因为当我们添加代码来更新、更改、移动精灵时,我们将能够看到发生了什么。

添加突出显示的代码以绘制四个新的精灵:

// Draw the tree window.draw(spriteTree);

// Draw the player window.draw(spritePlayer);

// Draw the axe window.draw(spriteAxe);

// Draraw the flying log window.draw(spriteLog);

// Draw the gravestone window.draw(spriteRIP);

// Draw the bee window.draw(spriteBee);

运行游戏,你现在能够看见场景中的精灵了。

至此,我们离一个可运行的游戏已经非常接近了。

处理玩家的输入

许多不同的事情取决于玩家的移动,例如何时展示斧头,何时开始动画日志,以及何时将所有分支移动到一个地方。因此,为玩家斩杀设置键盘处理是有意义的。一旦完成,我们可以将我们刚刚提到的所有功能放入代码的同一部分。

让我们思考一下如何检测键盘按压。在每个框架中,我们测试一个特定的键盘是否正在被压下来,如果是,我们就采取相应的行动。如果是Esc键被按住,我们就推出游戏,或者如果是Enter键被按压,我们重新启动游戏。到目前为止,这以经足够满足我们的需求。

然而,当我们尝试处理树的截断时,这种方法仍旧存在一个问题,而且这个问题是自始至终都存在的,不是现在才出现的。这取决于你的电脑有多强大,游戏循环每秒可以执行数千次,每次通过游戏循环,在其中一个键被按住时,它被检测到,相关的代码将被执行。

所以事实上,每当你按Enter键重启游戏时,你很有可能会重新启动它超过一百次,这是因为即使是最简单的按压也会持续一秒。你可以通过运行游戏并按住Enter键来验证这一点,注意时间栏不会移动,这是因为游戏一遍又一遍被重新启动,每秒数百次,甚至数千次。

如果我们使用相同的方法来进行玩家的砍切,那么只需要一个尝试,就能把整棵树的速度降低一秒,我们需要更复杂一点。我们要做的是允许玩家在这样做的时候,禁用检测按键的代码,然后我们会发现玩家何时从键盘上离开,接下来重新启用对按键的检测,以下是列出的步骤:

  1. 等待玩家使用左右键来劈砍木柴;
  2. 当玩家劈砍木柴时,禁用按键检测;
  3. 等待玩家手指离开键盘;
  4. 重新启用按键检测;
  5. 重复步骤1。

这听起来可能有点复杂,但是在SFML的帮助下,它将变得非常简单。我们现在来一步一步实现这个。

添加高亮显示的代码行,该代码声明了一名为acceptInput的bool变量,该变量将用于确定何时检测劈砍,何时忽略它们:

float logSpeedX = 1000;

float logSpeedY = -1500;

// Control the player input

bool acceptInput = false;

while (window.isOpen()) { }

现在我们有了布尔变量设置可以继续下一步。

处理设置一个新游戏

现在我们已经准备好处理劈砍,将高亮显示的代码添加到新启动游戏的if块中:

/* **************************************** Handle the players input **************************************** */

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

// Start the game if (Keyboard::isKeyPressed(Keyboard::Return)) { paused = false;

// Reset the time and the score score = 0; timeRemaining = 6;

// Make all the branches disappear for (int i = 1; i lt; NUM_BRANCHES; i ) { branchPositions[i] = side::NONE; }

// Make sure the gravestone is hidden spriteRIP.setPosition(675, 2000);

// Move the player into position spritePlayer.setPosition(580, 720);

acceptInput = true; }

/* **************************************** Update the scene **************************************** */

在前面的代码中,我们使用for循环来设置没有分支的树,这对玩家来说是公平的,因为如果游戏开始时在玩家头顶上方有一根树枝,那将被认为是玩家静止的,然后我们只需要将画布移除屏幕,玩家就会进入他左边的起始位置。这个代码所做的最后一件事是将acceptInput的值设置为true。

简单的声音播放

我们将会添加三个声音,每个声音将在一个特定的游戏事件里播放,当玩家劈砍树木时播放一个简单的重击声,当玩家耗尽时间时播放一个令人沮丧的失去的声音,以及当玩家将要死亡时播放一种令人崩溃的声音。

SFML声音是如何运作的?

SFML使用两个不同的类来播放声音效果。第一个类是SoundBuffer类。这是一个从声音文件中保存实际音频数据的类。它是一个声音缓冲区,负责将.wav文件加载到PC的RAM中,这种格式可以在没有任何进一步的解码工作的情况下播放。

在一分钟内,当我们为声音效果编写代码时,我们会看到,一旦我们有一个声音缓冲对象,我们的声音存储在它里面,我们就会创建另一个类型声音的对象。然后我们可以将这个声音对象与一个SoundBuffer对象关联起来。然后,在代码的合适位置,我们可以调用适当的声音对象的播放函数。

什么时候播放声音

我们很快就会看到,c 代码加载和播放声音非常简单,然而,我们需要考虑的是何时调用播放函数。在我们的代码中,我们把函数调用放在哪里?以下是我们想要达到的一些功能:

从左右光标键的按键上可以调用玩家劈砍声音。

如果检测到玩家死亡,就可以从if块中播放死亡声音。

当检测到timeRemaining小于零的if块时,可以播放玩家耗尽时间的声音。

现在我们可以写出声音代码了。

添加声音代码

首先,我们添加另一个#include指令,以使SFML的相关类可用。添加以下突出显示的代码:

#include 'stdafx.h'

#include lt;sstreamgt;

#include lt;SFML/Graphics.hppgt;

#include lt;SFML/Audio.hppgt;

使用命名空间sf;现在我们声明三个不同的SoundBuffer对象,将三个不同的声音文件加载到它们当中,并将三个不同类型的声音对象与SoundBuffer的相应对象关联起来。添加以下突出显示的代码:

// Control the player input bool acceptInput = false;

// Prepare the sound SoundBuffer chopBuffer; chopBuffer.loadFromFile('sound/chop.wav');

Sound chop;

chop.setBuffer(chopBuffer);

SoundBuffer deathBuffer;

deathBuffer.loadFromFile('sound/death.wav');

Sound death;

death.setBuffer(deathBuffer);

// Out of time SoundBuffer ootBuffer; ootBuffer.loadFromFile('sound/out_of_time.wav');

全文共11531字,剩余内容已隐藏,支付完成后下载完整资料


资料编号:[12111],资料为PDF文档或Word文档,PDF文档可免费转换为Word

原文和译文剩余内容已隐藏,您需要先支付 30元 才能查看原文和译文全部内容!立即支付

以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。