diff options
-rw-r--r-- | src/crepe/api/Asset.h | 4 | ||||
-rw-r--r-- | src/crepe/api/Config.h | 38 | ||||
-rw-r--r-- | src/crepe/facade/SDLContext.cpp | 6 | ||||
-rw-r--r-- | src/crepe/manager/SaveManager.cpp | 48 | ||||
-rw-r--r-- | src/crepe/manager/SaveManager.h | 6 | ||||
-rw-r--r-- | src/doc/feature/bgm.dox | 22 | ||||
-rw-r--r-- | src/doc/feature/config.dox | 61 | ||||
-rw-r--r-- | src/doc/feature/gameobject.dox | 4 | ||||
-rw-r--r-- | src/doc/feature/proxy.dox | 43 | ||||
-rw-r--r-- | src/doc/feature/savemgr.dox | 80 | ||||
-rw-r--r-- | src/doc/feature/script.dox | 42 | ||||
-rw-r--r-- | src/doc/feature/script_ecs.dox | 57 | ||||
-rw-r--r-- | src/doc/feature/sfx.dox | 24 | ||||
-rw-r--r-- | src/doc/features.dox | 55 | ||||
-rw-r--r-- | src/doc/style.css | 27 | ||||
-rw-r--r-- | src/test/main.cpp | 3 |
16 files changed, 436 insertions, 84 deletions
diff --git a/src/crepe/api/Asset.h b/src/crepe/api/Asset.h index bfd0ac7..d802e83 100644 --- a/src/crepe/api/Asset.h +++ b/src/crepe/api/Asset.h @@ -43,13 +43,13 @@ private: /** * \brief Locate asset path, or throw exception if it cannot be found * - * This function resolves asset locations relative to crepe::Config::root_pattern if it is + * This function resolves asset locations relative to Config::asset::root_pattern if it is * set and \p src is a relative path. If \p src is an absolute path, it is canonicalized. * This function only returns if the file can be found. * * \param src Arbitrary path to resource file * - * \returns \p src if crepe::Config::root_pattern is empty + * \returns \p src if Config::asset::root_pattern is empty * \returns Canonical path to \p src * * \throws std::runtime_error if root_pattern cannot be found diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 6472270..fae31f4 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -3,24 +3,21 @@ #include <string> #include "../util/Log.h" - -#include "types.h" +#include "../types.h" namespace crepe { /** * \brief Global configuration interface * - * This class stores engine default settings. Properties on this class are only supposed to be - * modified *before* execution is handed over from the game programmer to the engine (i.e. the - * main loop is started). + * This struct stores both engine default settings and global configuration parameters. */ struct Config final { //! Retrieve handle to global Config instance static Config & get_instance(); //! Logging-related settings - struct { + struct log { // NOLINT /** * \brief Log level * @@ -28,7 +25,7 @@ struct Config final { */ Log::Level level = Log::Level::INFO; /** - * \brief Colored log output + * \brief Enable colored log output * * Enables log coloring using ANSI escape codes. */ @@ -36,7 +33,7 @@ struct Config final { } log; //! Save manager - struct { + struct savemgr { // NOLINT /** * \brief Save file location * @@ -46,25 +43,22 @@ struct Config final { std::string location = "save.crepe.db"; } savemgr; - //! physics-related settings - struct { - /** - * \brief gravity value of physics system - * - * Gravity value of game. - */ + //! Physics-related settings + struct physics { // NOLINT + //! Gravity value of physics system double gravity = 1; } physics; - //! default window settings - struct { - //! default screen size in pixels - ivec2 default_size = {1280, 720}; - std::string window_title = "Jetpack joyride clone"; - } window_settings; + //! Default window settings + struct window { // NOLINT + //! Default window size (in pixels) + ivec2 size = {1280, 720}; + //! Default window title + std::string title = "Jetpack joyride clone"; + } window; //! Asset loading options - struct { + struct asset { // NOLINT /** * \brief Pattern to match for Asset base directory * diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 6becf60..52929e1 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -39,10 +39,10 @@ SDLContext::SDLContext() { throw runtime_error(format("SDLContext: SDL_Init error: {}", SDL_GetError())); } - auto & cfg = Config::get_instance().window_settings; + auto & cfg = Config::get_instance().window; SDL_Window * tmp_window - = SDL_CreateWindow(cfg.window_title.c_str(), SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, cfg.default_size.x, cfg.default_size.y, 0); + = SDL_CreateWindow(cfg.title.c_str(), SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, cfg.size.x, cfg.size.y, 0); if (!tmp_window) { throw runtime_error(format("SDLContext: SDL_Window error: {}", SDL_GetError())); } diff --git a/src/crepe/manager/SaveManager.cpp b/src/crepe/manager/SaveManager.cpp index d4ed1c1..034a283 100644 --- a/src/crepe/manager/SaveManager.cpp +++ b/src/crepe/manager/SaveManager.cpp @@ -133,9 +133,32 @@ template void SaveManager::set(const string &, const float &); template void SaveManager::set(const string &, const double &); template <typename T> +T SaveManager::get(const string & key) { + return this->deserialize<T>(this->get_db().get(key)); +} +template uint8_t SaveManager::get(const string &); +template int8_t SaveManager::get(const string &); +template uint16_t SaveManager::get(const string &); +template int16_t SaveManager::get(const string &); +template uint32_t SaveManager::get(const string &); +template int32_t SaveManager::get(const string &); +template uint64_t SaveManager::get(const string &); +template int64_t SaveManager::get(const string &); +template float SaveManager::get(const string &); +template double SaveManager::get(const string &); +template string SaveManager::get(const string &); + +template <typename T> ValueBroker<T> SaveManager::get(const string & key, const T & default_value) { if (!this->has(key)) this->set<T>(key, default_value); - return this->get<T>(key); + T value; + return { + [this, key](const T & target) { this->set<T>(key, target); }, + [this, key, value]() mutable -> const T & { + value = this->get<T>(key); + return value; + }, + }; } template ValueBroker<uint8_t> SaveManager::get(const string &, const uint8_t &); template ValueBroker<int8_t> SaveManager::get(const string &, const int8_t &); @@ -148,26 +171,3 @@ template ValueBroker<int64_t> SaveManager::get(const string &, const int64_t &); template ValueBroker<float> SaveManager::get(const string &, const float &); template ValueBroker<double> SaveManager::get(const string &, const double &); template ValueBroker<string> SaveManager::get(const string &, const string &); - -template <typename T> -ValueBroker<T> SaveManager::get(const string & key) { - T value; - return { - [this, key](const T & target) { this->set<T>(key, target); }, - [this, key, value]() mutable -> const T & { - value = this->deserialize<T>(this->get_db().get(key)); - return value; - }, - }; -} -template ValueBroker<uint8_t> SaveManager::get(const string &); -template ValueBroker<int8_t> SaveManager::get(const string &); -template ValueBroker<uint16_t> SaveManager::get(const string &); -template ValueBroker<int16_t> SaveManager::get(const string &); -template ValueBroker<uint32_t> SaveManager::get(const string &); -template ValueBroker<int32_t> SaveManager::get(const string &); -template ValueBroker<uint64_t> SaveManager::get(const string &); -template ValueBroker<int64_t> SaveManager::get(const string &); -template ValueBroker<float> SaveManager::get(const string &); -template ValueBroker<double> SaveManager::get(const string &); -template ValueBroker<string> SaveManager::get(const string &); diff --git a/src/crepe/manager/SaveManager.h b/src/crepe/manager/SaveManager.h index 3d8c852..e2ef005 100644 --- a/src/crepe/manager/SaveManager.h +++ b/src/crepe/manager/SaveManager.h @@ -33,17 +33,17 @@ public: ValueBroker<T> get(const std::string & key, const T & default_value); /** - * \brief Get a read/write reference to a value + * \brief Get a value directly * * \param key The value key * - * \return Read/write reference to the value + * \return The value * * \note Attempting to read this value before it is initialized (i.e. set) will result in an * exception */ template <typename T> - ValueBroker<T> get(const std::string & key); + T get(const std::string & key); /** * \brief Set a value directly diff --git a/src/doc/feature/bgm.dox b/src/doc/feature/bgm.dox new file mode 100644 index 0000000..968abb8 --- /dev/null +++ b/src/doc/feature/bgm.dox @@ -0,0 +1,22 @@ +// vim:ft=doxygen +namespace crepe { +/** + +\defgroup feature_bgm Playing background music +\ingroup feature +\brief Add background music to a scene using the AudioSource component + +This page shows how to implement background music using the AudioSource +effects. + +\see AudioSource + +\par Example + +\note This example assumes you already have a GameObject. If not, read +\"\ref feature_gameobject\" first. + +\todo Merge #60 + +*/ +} diff --git a/src/doc/feature/config.dox b/src/doc/feature/config.dox new file mode 100644 index 0000000..85d6803 --- /dev/null +++ b/src/doc/feature/config.dox @@ -0,0 +1,61 @@ +// vim:ft=doxygen +namespace crepe { +/** + +\defgroup feature_config Engine configuration +\ingroup feature +\brief Configure default values and global options + +Default values and options that apply to the engine globally are read from a +singleton struct named Config. + +\see Config + +\par Example + +Configuration options may be set individually or by assigning a [designated +initializer list][desginit]. All of Config's members have default values and can +safely be omitted from initializer lists. + +[desginit]: https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers + +```cpp +#include <crepe/api/Config.h> + +int main() { + auto & config = crepe::Config::get_instance(); + + // Designated initializer list + config = { + // specify options here + }; + + // Reset default options + config = {}; + + // Set specific option + config.log.color = false; +} +``` + +\par Options + +\noop Display config properties in monospace font +\htmlonly +<style> +tr td:first-child { font-family: monospace; } +</style> +\endhtmlonly + +|Option|Description| +|-|-| +|\ref Config::asset::root_pattern ".asset.root_pattern"|\copybrief Config::asset::root_pattern| +|\ref Config::log::color ".log.color"|\copybrief Config::log::color| +|\ref Config::log::level ".log.level"|\copybrief Config::log::level| +|\ref Config::physics::gravity ".physics.gravity"|\copybrief Config::physics::gravity| +|\ref Config::savemgr::location ".savemgr.location"|\copybrief Config::savemgr::location| +|\ref Config::window::size ".window.size"|\copybrief Config::window::size| +|\ref Config::window::title ".window.title"|\copybrief Config::window::title| + +*/ +} diff --git a/src/doc/feature/gameobject.dox b/src/doc/feature/gameobject.dox index c561874..ac3927c 100644 --- a/src/doc/feature/gameobject.dox +++ b/src/doc/feature/gameobject.dox @@ -2,9 +2,9 @@ namespace crepe { /** -\defgroup feature_gameobject GameObjects +\defgroup feature_gameobject Entity basics \ingroup feature -\brief GameObject to create a Scene +\brief Building game entities using a GameObject GameObjects are the fundamental building blocks of a Scene. They represent entities in the game world and can have various components attached to them to define their diff --git a/src/doc/feature/proxy.dox b/src/doc/feature/proxy.dox new file mode 100644 index 0000000..66bbd2f --- /dev/null +++ b/src/doc/feature/proxy.dox @@ -0,0 +1,43 @@ +// vim:ft=doxygen +namespace crepe { +/** + +\defgroup feature_proxy Proxy utility +\ingroup feature +\brief Use ValueBroker as if it were a regular variable + +Proxy provides operators that allow you to use a ValueBroker instance as if it +were a regular variable. Proxy implements a constructor that allows it to be +used as a substitute return type for any function that returns ValueBroker. + +\see ValueBroker +\see Proxy + +\par Example + +```cpp +#include <crepe/util/Proxy.h> +#include <crepe/ValueBroker.h> + +int calculation(int value) { + return 3 * value; +} + +void anywhere() { + crepe::ValueBroker<int> foo_handle; + crepe::Proxy foo = foo_handle; + + // implicitly calls .set() + foo += 10; + + // implicitly calls .get() + int out = calculation(foo); + + // explicitly cast (also calls .get()) + int casted = int(foo); +} + +``` + +*/ +} diff --git a/src/doc/feature/savemgr.dox b/src/doc/feature/savemgr.dox new file mode 100644 index 0000000..6aeab03 --- /dev/null +++ b/src/doc/feature/savemgr.dox @@ -0,0 +1,80 @@ +// vim:ft=doxygen +namespace crepe { +/** + +\defgroup feature_savemgr Save data +\ingroup feature +\brief Functions to persistently store and retrieve arbitrary values + +The SaveManager may be used to persistently store game state such as player +progress, statistics, achievements, etc. It works like a key-value store, where +the key is a string and the value is an arbitrary type. + +SaveManager implements the following: + +- Storage and retrieval of primitive types and strings. +- Automatic initialization of the database using default values. +- The underlying database format is journaled, which reduces the likelihood of + players losing save data when an unexpected crash occurs while the SaveManager + is writing to disk. + +\see SaveManager + +\par Example + +The SaveManager instance reference may be retrieved by calling \c +get_save_manager(). This function is available--- + +- Within (derivatives of) Script + +- \todo Within (derivatives of) Scene + +- \todo As a public member function of LoopManager + +```cpp +// Retrieve save manager +crepe::SaveManager & save_manager = get_save_manager(); +``` + +SaveManager may be used *explicitly*, using the \ref SaveManager::set "set()", +\ref SaveManager::get "get()" and \ref SaveManager::has "has()" methods: +```cpp +// Check if the key "foo" exists, and initialize it to 3 if it doesn't +if (!save_manager.has("foo")) + save_manager.set<int>("foo", 3); +// Get value of key "foo" +int foo = save_manager.get<int>("foo"); + +// ~~~ arbitrary game code ~~~ +foo += 10; +// ~~~ arbitrary game code ~~~ + +// Save "foo" back to database +save_manager.set<int>("foo", foo); +``` + +Alternatively, SaveManager::get may be called with a default value as second +parameter. This changes its return type to ValueBroker, which acts as a +read/write handle to the specific key requested, and remembers the key and its +value type for you: +```cpp +// Get a read/write handle to the value stored in key "foo", and initialize it +// to 3 if it doesn't exist yet +ValueBroker foo_handle = save_manager.get<int>("foo", 3); +int foo = foo_handle.get(); + +// ~~~ arbitrary game code ~~~ +foo += 10; +// ~~~ arbitrary game code ~~~ + +// Save back to database +foo_handle.set(foo); +``` + +To further simplify game code, the return value of SaveManager::get may be +implicitly cast to Proxy instead of ValueBroker. This allows the database value +to be used as if it were a regular variable. This usage is detailed separately +in \"\ref feature_proxy\". + +*/ +} diff --git a/src/doc/feature/script.dox b/src/doc/feature/script.dox index d25a63b..e3b5508 100644 --- a/src/doc/feature/script.dox +++ b/src/doc/feature/script.dox @@ -2,19 +2,14 @@ namespace crepe { /** -\defgroup feature_script Scripting +\defgroup feature_script Scripting basics \ingroup feature -\brief User-defined scripts for game objects +\brief Create a concrete Script and attach it to a GameObject Scripts can be used to implement game behavior, and allow arbitrary code to run as part of the game loop. Scripts are implemented as derivative classes of -Script, which are added to game objects using the BehaviorScript \ref Component -"component". - -\todo This section is incomplete: -- Utility functions to get components/events/etc inside script -- How to listen for events -- Extensions of script (keylistener) +Script, which are added to \ref GameObject "game objects" using the \ref +BehaviorScript \ref Component "component". \see Script \see BehaviorScript @@ -22,11 +17,14 @@ Script, which are added to game objects using the BehaviorScript \ref Component \par Example -First, define a class that inherits from Script. This class acts as an -interface, and has two functions (\ref Script::init "\c init()" and \ref -Script::update "\c update()"), which may be implemented (they are empty by -default). From now on, this derivative class will be referred to as a *concrete -script*. +\note This example assumes you already have a GameObject. If not, read +\"\ref feature_gameobject\" first. + +First, define a class (anywhere) that inherits from Script. The Script class +acts as an interface, and has two functions (\ref Script::init "\c init()" and +\ref Script::update "\c update()"), which *may* be implemented (they are empty +by default). From now on, this derivative class will be referred to as a +*concrete script*. ```cpp #include <crepe/api/Script.h> @@ -42,19 +40,23 @@ class MyScript : public crepe::Script { }; ``` -Concrete scripts can be instantiated and attached to \ref GameObject -"game objects" using the BehaviorScript \ref Component "component". +After defining a concrete script, it can be instantiated and attached to \ref +feature_gameobject "game objects" during \ref feature_scene +"scene initialization" using a BehaviorScript component: ```cpp using namespace crepe; -GameObject obj = component_manager.new_object("name"); +GameObject obj; -// create BehaviorScript instance +// Create a BehaviorScript component to hold MyScript BehaviorScript & behavior_script = obj.add_component<BehaviorScript>(); -// attach (and instantiate) MyScript to behavior_script + +// Instantiate (and attach) MyScript to behavior_script behavior_script.set_script<MyScript>(); +``` -// the above can also be done in a single call for convenience: +The above can also be done in a single call for convenience: +```cpp obj.add_component<BehaviorScript>().set_script<MyScript>(); ``` diff --git a/src/doc/feature/script_ecs.dox b/src/doc/feature/script_ecs.dox new file mode 100644 index 0000000..bbe1abc --- /dev/null +++ b/src/doc/feature/script_ecs.dox @@ -0,0 +1,57 @@ +// vim:ft=doxygen +namespace crepe { +/** + +\defgroup feature_script_ecs Using ECS inside Script +\ingroup feature +\brief Query the component manager inside a concrete Script + +Script provides several methods to request references to components during +runtime. These methods may be used in cases where it is either not practical or +impossible to manually pass the references required to implement a certain +behavior. + +\see Script +\see ComponentManager + +\par Example + +\note This example assumes you already have a concrete Script. If not, read +\"\ref feature_script\" first. + +The component manager can be queried for components inside Script using the +following methods: + +- For requesting components on the same GameObject as this Script instance: + - Script::get_component(): \copybrief Script::get_component + - Script::get_components(): \copybrief Script::get_components +- For requesting components in the current Scene: + - Script::get_components_by_id(): \copybrief Script::get_components_by_id + - Script::get_components_by_name(): \copybrief Script::get_components_by_name + - Script::get_components_by_tag(): \copybrief Script::get_components_by_tag + +```cpp +#include <crepe/util/Log.h> +#include <crepe/api/Script.h> +#include <crepe/api/Metadata.h> + +using namespace crepe; + +class MyScript : public Script { + void show_self() { + Metadata & own_metadata = get_component<Metadata>(); + Log::logf("My name is {}", own_metadata.name); + } + + void list_enemies() { + RefVector<Metadata> enemies = get_components_by_tag<Metadata>("enemy"); + Log::logf("There are {} enemies:", enemies.size()); + for (const Metadata & enemy : enemies) { + Log::logf("- {}", enemy.name); + } + } +}; +``` + +*/ +} diff --git a/src/doc/feature/sfx.dox b/src/doc/feature/sfx.dox new file mode 100644 index 0000000..2a5c9cc --- /dev/null +++ b/src/doc/feature/sfx.dox @@ -0,0 +1,24 @@ +// vim:ft=doxygen +namespace crepe { +/** + +\defgroup feature_sfx Playing sound effects +\ingroup feature +\brief Fire a sound effect using the AudioSource component + +This page shows how to implement one-shot sound effects using the AudioSource +component's 'fire and forget'-style API. + +\see AudioSource + +\par Example + +\note This example assumes you already have a GameObject to attach the +AudioSource component to, and uses a Script to control the AudioSource instance. +Separate pages describing these features in more detail can be found at \"\ref +feature_gameobject\" and \"\ref feature_script\" respectively. + +\todo Merge #60 + +*/ +} diff --git a/src/doc/features.dox b/src/doc/features.dox index 21a040a..56d17c7 100644 --- a/src/doc/features.dox +++ b/src/doc/features.dox @@ -3,8 +3,12 @@ \htmlonly <style> -table.memberdecls { display: none; } -ul { margin: 1ex 0pt; } +table.memberdecls, +.groupheader +{ display: none; } +ul, +li +{ margin: 1ex 0pt; } </style> \endhtmlonly @@ -14,15 +18,52 @@ ul { margin: 1ex 0pt; } This page lists engine features and contains usage instructions for each feature. -\par Features +- Basics + - \todo Hello world / engine initialization -- Scripting - - \ref feature_script \n\copybrief feature_script + - \ref feature_config \n\copybrief feature_config -- Game flow management +- Scenes - \ref feature_scene \n\copybrief feature_scene + - \todo Navigating between scenes + +- Input + - \todo Key/Mouse events (w/ Script) -- Entity +- Actors / game objects - \ref feature_gameobject \n\copybrief feature_gameobject +- \todo HUD + +- Animation + - \todo Animation using spritesheet + + - \todo Particle effects + +- Save data + - \ref feature_savemgr \n\copybrief feature_savemgr + +- Audio + - \ref feature_sfx \n\copybrief feature_sfx + - \ref feature_bgm \n\copybrief feature_bgm + +- \todo AI + +- \todo Physics + +- Scripting + - \ref feature_script \n\copybrief feature_script + - \ref feature_script_ecs \n\copybrief feature_script_ecs + + - \todo Subscribing to *any* event inside Script + + - \todo Creating and dispatching custom events + +- \todo Replay + +- Utilities + - \todo Logging + + - \ref feature_proxy \n\copybrief feature_proxy + */ diff --git a/src/doc/style.css b/src/doc/style.css index c12240c..efc669b 100644 --- a/src/doc/style.css +++ b/src/doc/style.css @@ -4,3 +4,30 @@ a[href="namespaces.html"] { display: none; } h2.groupheader { margin-top: revert; } + +dl { + padding: 4px 12px !important; + border-radius: 8px !important; + border: 0 !important; +} +dt { + margin-bottom: 0.5ex; +} + +a:hover { + text-decoration: revert !important; + background: unset !important; +} + +dl.section.see, +dl.section.user { + padding: 0 !important; + border-radius: 0 !important; + margin-top: 0; +} +dl.section.see dt, +dl.section.user dt { + font-size: 130%; + margin-bottom: 0.5ex; + margin-top: 1.5ex; +} diff --git a/src/test/main.cpp b/src/test/main.cpp index ed2aed5..0e1bc75 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -1,6 +1,7 @@ -#include <crepe/api/Config.h> #include <gtest/gtest.h> +#include <crepe/api/Config.h> + using namespace crepe; using namespace testing; |