- SFML Game Development
- Artur Moreira Henrik Vogelius Hansson Jan Haller
- 780字
- 2021-08-13 17:11:11
A typical use case
Now we have seen what kinds of different resources there are, but we do not know yet how to apply this knowledge to our game. While the approach you have seen in Chapter 1, Making a Game Tick, may work for simple examples, it does not scale well to a bigger project. As our game grows, we have to reflect about how the resources are going to be used. This is explained in the next sections.
Graphics
In our game, a crucial part will be the visual representation of the world and different objects in it. We need to think about how we get from an image on the hard disk to its visualization on the screen.
- Game entities such as the player's airplane, enemies, or the landscape are represented with sprites and possibly texts. They do not own the heavy textures and fonts; instead they use the front-end classes to refer to them.
- As a consequence, the resources (textures and fonts) need to be accessible by the entities. We must make sure that the resource objects stay alive as long as any front-end object refers to them, so we have to find an appropriate scope to declare the resources.
- A sprite in the airplane must somehow get a reference to the texture stored outside. Therefore, we have to transport this information via constructor parameter to the airplane class.
Audio
Another important resource is audio, which can be divided into sound effects and background music. We have to consider how to make both of them audible in the final application, when all we start with is a bunch of audio files in a directory:
- Sound effects are not tied to a specific game entity such as an airplane; they persist independently of the object that causes them. Imagine an airplane that explodes and creates an explosion sound. When we destroy the plane object, we still want the explosion to be audible for some time. As a result, we do not store
sf::Sound
instances in the game entities, but in an object which remains alive throughout a mission. The same applies to the underlyingsf::SoundBuffer
objects which are used bysf::Sound
. - For music themes, the semantics are similar. It may even occur that the same theme is played across multiple missions. Ideally, the
sf::Music
objects exist in a scope that outlives a single mission. - Although the game entities do not own sound effects, they are supposed to play them. As a consequence, we shall provide an interface that allows playing new sound effects.
Acquiring, releasing, and accessing resources
Once we have decided which resources are required by the application, the next step is to investigate how long and by whom they are used. This allows us to decide how the resources are stored in the application, as well as who is responsible of loading and releasing them.
- We want to load the resource in advance, for example, at the time the game starts or the player begins a new mission. In contrast to loading on demand (as soon as a resource is needed), this approach has the advantage that possible loading times occur in the beginning and not during a game. Therefore, the game itself remains fluent and is not interrupted because of resources.
- When resources are likely to not be needed anymore, we can release them and free the memory. This is usually the case at the end of a mission or when the application is quit. We do not want to release resources too early if we risk reloading them shortly after. For example, we do not release the explosion sound buffer as soon as the sound effect is over, because the next explosion may follow a few seconds later.
- There must be a possibility to get a reference to a certain resource after it has been loaded—using a resource identifier. This identifier (ID) could be the file path as a
std::string
. This has some disadvantages: all classes that use a resource must hardcode the path, so if it changes, a lot of code needs to be refactored. Strings are also quite error-prone regarding typographic or case errors. An alternative to strings are enums, where each enumerator denotes an ID. Since an enum has a predefined set of possible states, we get some compile-time safety, and we can handle the paths in a central place.
In conclusion, we have the heavy resource classes which shall be loaded when appropriate, but before the game. Throughout their lifetime, front-end classes such as sprites or sounds may reference them, so we must keep the resources alive. When they are not needed anymore, we can release them.
- Facebook Application Development with Graph API Cookbook
- Vue.js設計與實現
- TypeScript Blueprints
- Building a Game with Unity and Blender
- Power Up Your PowToon Studio Project
- Java Web及其框架技術
- 基于免疫進化的算法及應用研究
- 飛槳PaddlePaddle深度學習實戰
- Getting Started with Greenplum for Big Data Analytics
- Unity 2D Game Development Cookbook
- Clean Code in C#
- Hack與HHVM權威指南
- Software Development on the SAP HANA Platform
- 大規模語言模型開發基礎與實踐
- Python量子計算實踐:基于Qiskit和IBM Quantum Experience平臺