aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/crepe/Collider.h3
-rw-r--r--src/crepe/api/Asset.h4
-rw-r--r--src/crepe/api/Color.cpp2
-rw-r--r--src/crepe/api/Color.h2
-rw-r--r--src/crepe/api/Components.h16
-rw-r--r--src/crepe/api/Config.h30
-rw-r--r--src/crepe/api/Engine.cpp1
-rw-r--r--src/crepe/api/Sprite.cpp13
-rw-r--r--src/crepe/api/Sprite.h10
-rw-r--r--src/crepe/api/Text.cpp13
-rw-r--r--src/crepe/api/Text.h6
-rw-r--r--src/crepe/api/Vector2.h46
-rw-r--r--src/crepe/api/Vector2.hpp15
-rw-r--r--src/crepe/system/AudioSystem.cpp2
-rw-r--r--src/doc/feature/bgm.dox22
-rw-r--r--src/doc/feature/config.dox61
-rw-r--r--src/doc/feature/gameobject.dox4
-rw-r--r--src/doc/feature/scene.dox15
-rw-r--r--src/doc/feature/script.dox48
-rw-r--r--src/doc/feature/script_ecs.dox57
-rw-r--r--src/doc/feature/sfx.dox24
-rw-r--r--src/doc/features.dox55
-rw-r--r--src/doc/index.dox9
-rw-r--r--src/doc/layout.xml6
-rw-r--r--src/doc/style.css27
-rw-r--r--src/test/AudioTest.cpp9
-rw-r--r--src/test/InputTest.cpp30
-rw-r--r--src/test/Vector2Test.cpp10
28 files changed, 452 insertions, 88 deletions
diff --git a/src/crepe/Collider.h b/src/crepe/Collider.h
index 42ccfd4..4344f15 100644
--- a/src/crepe/Collider.h
+++ b/src/crepe/Collider.h
@@ -5,6 +5,9 @@
namespace crepe {
+/**
+ * \brief Base collider class
+ */
class Collider : public Component {
public:
Collider(game_object_id_t id, const vec2 & offset);
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/Color.cpp b/src/crepe/api/Color.cpp
index 6858aa8..d0e3b35 100644
--- a/src/crepe/api/Color.cpp
+++ b/src/crepe/api/Color.cpp
@@ -10,3 +10,5 @@ const Color Color::BLACK {0x00, 0x00, 0x00};
const Color Color::CYAN {0x00, 0xff, 0xff};
const Color Color::YELLOW {0xff, 0xff, 0x00};
const Color Color::MAGENTA {0xff, 0x00, 0xff};
+const Color Color::GREY {0x80, 0x80, 0x80};
+const Color Color::GOLD {249, 205, 91};
diff --git a/src/crepe/api/Color.h b/src/crepe/api/Color.h
index 84edb5c..dbfd0ed 100644
--- a/src/crepe/api/Color.h
+++ b/src/crepe/api/Color.h
@@ -18,6 +18,8 @@ struct Color {
static const Color MAGENTA;
static const Color YELLOW;
static const Color BLACK;
+ static const Color GREY;
+ static const Color GOLD;
};
} // namespace crepe
diff --git a/src/crepe/api/Components.h b/src/crepe/api/Components.h
new file mode 100644
index 0000000..fa0663d
--- /dev/null
+++ b/src/crepe/api/Components.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "AI.h"
+#include "Animator.h"
+#include "AudioSource.h"
+#include "BehaviorScript.h"
+#include "BoxCollider.h"
+#include "Button.h"
+#include "Camera.h"
+#include "CircleCollider.h"
+#include "Metadata.h"
+#include "ParticleEmitter.h"
+#include "Rigidbody.h"
+#include "Sprite.h"
+#include "Text.h"
+#include "Transform.h"
diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h
index 6b9e3ca..ab8bb59 100644
--- a/src/crepe/api/Config.h
+++ b/src/crepe/api/Config.h
@@ -2,25 +2,22 @@
#include <string>
+#include "../types.h"
#include "../util/Log.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,8 +43,8 @@ struct Config final {
std::string location = "save.crepe.db";
} savemgr;
- //! physics-related settings
- struct {
+ //! Physics-related settings
+ struct physics { // NOLINT
/**
* \brief gravity value of physics system
*
@@ -56,15 +53,16 @@ struct Config final {
float gravity = 10;
} physics;
- //! default window settings
- struct {
- //! default screen size in pixels
+ //! Default window settings
+ struct window_settings { // NOLINT
+ //! Default window size (in pixels)
ivec2 default_size = {1280, 720};
- std::string window_title = "Jetpack joyride clone";
+ //! Default window title
+ std::string window_title = "crepe window";
} window_settings;
//! Asset loading options
- struct {
+ struct asset { // NOLINT
/**
* \brief Pattern to match for Asset base directory
*
@@ -85,7 +83,7 @@ struct Config final {
* This config option is the font size at which all fonts will be loaded initially.
*
*/
- unsigned int size = 16;
+ unsigned int size = 100;
} font;
//! Configuration for click tolerance.
struct {
diff --git a/src/crepe/api/Engine.cpp b/src/crepe/api/Engine.cpp
index cd9786b..0bbe51f 100644
--- a/src/crepe/api/Engine.cpp
+++ b/src/crepe/api/Engine.cpp
@@ -56,6 +56,7 @@ void Engine::loop() {
try {
systems.frame_update();
+ this->scene_manager.load_next_scene();
} catch (const exception & e) {
Log::logf(
Log::Level::WARNING, "Uncaught exception in frame update function: {}\n",
diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp
index 0107c7b..3c77e2e 100644
--- a/src/crepe/api/Sprite.cpp
+++ b/src/crepe/api/Sprite.cpp
@@ -19,3 +19,16 @@ Sprite::Sprite(game_object_id_t id, const Asset & texture, const Sprite::Data &
}
Sprite::~Sprite() { dbg_trace(); }
+
+unique_ptr<Component> Sprite::save() const { return unique_ptr<Component>(new Sprite(*this)); }
+
+void Sprite::restore(const Component & snapshot) {
+ *this = static_cast<const Sprite &>(snapshot);
+}
+
+Sprite & Sprite::operator=(const Sprite & snapshot) {
+ this->active = snapshot.active;
+ this->data = snapshot.data;
+ this->mask = snapshot.mask;
+ return *this;
+}
diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h
index a3fc319..3565bed 100644
--- a/src/crepe/api/Sprite.h
+++ b/src/crepe/api/Sprite.h
@@ -42,10 +42,10 @@ public:
FlipSettings flip;
//! Layer sorting level of the sprite
- const int sorting_in_layer = 0;
+ int sorting_in_layer = 0;
//! Order within the sorting layer
- const int order_in_layer = 0;
+ int order_in_layer = 0;
/**
* \brief width and height of the sprite in game units
@@ -119,6 +119,12 @@ private:
//! Render area of the sprite this will also be adjusted by the AnimatorSystem if an Animator
// object is present in GameObject. this is in sprite pixels
Rect mask;
+
+protected:
+ virtual std::unique_ptr<Component> save() const;
+ Sprite(const Sprite &) = default;
+ virtual void restore(const Component & snapshot);
+ virtual Sprite & operator=(const Sprite &);
};
} // namespace crepe
diff --git a/src/crepe/api/Text.cpp b/src/crepe/api/Text.cpp
index e5b623d..e5cc39d 100644
--- a/src/crepe/api/Text.cpp
+++ b/src/crepe/api/Text.cpp
@@ -3,6 +3,7 @@
#include "Text.h"
using namespace crepe;
+using namespace std;
Text::Text(
game_object_id_t id, const vec2 & dimensions, const std::string & font_family,
@@ -12,3 +13,15 @@ Text::Text(
text(text),
data(data),
font_family(font_family) {}
+
+unique_ptr<Component> Text::save() const { return unique_ptr<Component>(new Text(*this)); }
+
+void Text::restore(const Component & snapshot) { *this = static_cast<const Text &>(snapshot); }
+
+Text & Text::operator=(const Text & snapshot) {
+ this->active = snapshot.active;
+ this->data = snapshot.data;
+ this->text = snapshot.text;
+ this->font_family = snapshot.font_family;
+ return *this;
+}
diff --git a/src/crepe/api/Text.h b/src/crepe/api/Text.h
index 8b3d53e..859490e 100644
--- a/src/crepe/api/Text.h
+++ b/src/crepe/api/Text.h
@@ -49,6 +49,12 @@ public:
std::optional<Asset> font;
//! Data instance
Data data;
+
+protected:
+ virtual std::unique_ptr<Component> save() const;
+ Text(const Text &) = default;
+ virtual void restore(const Component & snapshot);
+ virtual Text & operator=(const Text &);
};
} // namespace crepe
diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h
index 52e1bb6..6613641 100644
--- a/src/crepe/api/Vector2.h
+++ b/src/crepe/api/Vector2.h
@@ -1,5 +1,7 @@
#pragma once
+#include <format>
+
namespace crepe {
//! 2D vector
@@ -11,55 +13,55 @@ struct Vector2 {
T y = 0;
//! Subtracts another vector from this vector and returns the result.
- Vector2 operator-(const Vector2<T> & other) const;
+ Vector2<T> operator-(const Vector2<T> & other) const;
//! Subtracts a scalar value from both components of this vector and returns the result.
- Vector2 operator-(T scalar) const;
+ Vector2<T> operator-(T scalar) const;
//! Adds another vector to this vector and returns the result.
- Vector2 operator+(const Vector2<T> & other) const;
+ Vector2<T> operator+(const Vector2<T> & other) const;
//! Adds a scalar value to both components of this vector and returns the result.
- Vector2 operator+(T scalar) const;
+ Vector2<T> operator+(T scalar) const;
//! Multiplies this vector by another vector element-wise and returns the result.
- Vector2 operator*(const Vector2<T> & other) const;
+ Vector2<T> operator*(const Vector2<T> & other) const;
//! Multiplies this vector by a scalar and returns the result.
- Vector2 operator*(T scalar) const;
+ Vector2<T> operator*(T scalar) const;
//! Divides this vector by another vector element-wise and returns the result.
- Vector2 operator/(const Vector2<T> & other) const;
+ Vector2<T> operator/(const Vector2<T> & other) const;
//! Divides this vector by a scalar and returns the result.
- Vector2 operator/(T scalar) const;
+ Vector2<T> operator/(T scalar) const;
//! Adds another vector to this vector and updates this vector.
- Vector2 & operator+=(const Vector2<T> & other);
+ Vector2<T> & operator+=(const Vector2<T> & other);
//! Adds a scalar value to both components of this vector and updates this vector.
- Vector2 & operator+=(T other);
+ Vector2<T> & operator+=(T other);
//! Subtracts another vector from this vector and updates this vector.
- Vector2 & operator-=(const Vector2<T> & other);
+ Vector2<T> & operator-=(const Vector2<T> & other);
//! Subtracts a scalar value from both components of this vector and updates this vector.
- Vector2 & operator-=(T other);
+ Vector2<T> & operator-=(T other);
//! Multiplies this vector by another vector element-wise and updates this vector.
- Vector2 & operator*=(const Vector2<T> & other);
+ Vector2<T> & operator*=(const Vector2<T> & other);
//! Multiplies this vector by a scalar and updates this vector.
- Vector2 & operator*=(T other);
+ Vector2<T> & operator*=(T other);
//! Divides this vector by another vector element-wise and updates this vector.
- Vector2 & operator/=(const Vector2<T> & other);
+ Vector2<T> & operator/=(const Vector2<T> & other);
//! Divides this vector by a scalar and updates this vector.
- Vector2 & operator/=(T other);
+ Vector2<T> & operator/=(T other);
//! Returns the negation of this vector.
- Vector2 operator-() const;
+ Vector2<T> operator-() const;
//! Checks if this vector is equal to another vector.
bool operator==(const Vector2<T> & other) const;
@@ -89,12 +91,20 @@ struct Vector2 {
T distance_squared(const Vector2<T> & other) const;
//! Returns the perpendicular vector to this vector.
- Vector2 perpendicular() const;
+ Vector2<T> perpendicular() const;
//! Checks if both components of the vector are NaN.
bool is_nan() const;
+
+ //! Rotate this vector clockwise by \c deg degrees
+ Vector2<T> rotate(float deg) const;
};
} // namespace crepe
+template <typename T>
+struct std::formatter<crepe::Vector2<T>> : std::formatter<std::string> {
+ format_context::iterator format(crepe::Vector2<T> vec, format_context & ctx) const;
+};
+
#include "Vector2.hpp"
diff --git a/src/crepe/api/Vector2.hpp b/src/crepe/api/Vector2.hpp
index e195760..30441d2 100644
--- a/src/crepe/api/Vector2.hpp
+++ b/src/crepe/api/Vector2.hpp
@@ -168,4 +168,19 @@ bool Vector2<T>::is_nan() const {
return std::isnan(x) && std::isnan(y);
}
+template <class T>
+Vector2<T> Vector2<T>::rotate(float deg) const {
+ float rad = -deg / 180 * M_PI;
+ return {
+ x * std::cos(rad) - y * std::sin(rad),
+ x * std::sin(rad) + y * std::cos(rad),
+ };
+}
+
} // namespace crepe
+
+template <typename T>
+std::format_context::iterator
+std::formatter<crepe::Vector2<T>>::format(crepe::Vector2<T> vec, format_context & ctx) const {
+ return formatter<string>::format(std::format("{{{}, {}}}", vec.x, vec.y), ctx);
+}
diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp
index d4e8b9f..3c2232f 100644
--- a/src/crepe/system/AudioSystem.cpp
+++ b/src/crepe/system/AudioSystem.cpp
@@ -36,6 +36,8 @@ void AudioSystem::diff_update(AudioSource & component, Sound & resource) {
if (component.oneshot_play) {
component.voice = context.play(resource);
+ context.set_loop(component.voice, component.loop);
+ context.set_volume(component.voice, component.volume);
component.oneshot_play = false;
}
if (component.oneshot_stop) {
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..ae3a054
--- /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_settings::default_size ".window_settings.default_size"|\copybrief Config::window_settings::default_size|
+|\ref Config::window_settings::window_title ".window_settings.window_title"|\copybrief Config::window_settings::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/scene.dox b/src/doc/feature/scene.dox
index 4124e37..b680eec 100644
--- a/src/doc/feature/scene.dox
+++ b/src/doc/feature/scene.dox
@@ -40,31 +40,28 @@ added to the loop/scene manger via loop_mgr::add_scene<>(). The templated
argument should define the concrete scene to be added.
```cpp
-#include <crepe/api/LoopManager.h>
-#include <crepe/api/GameObject.h>
+#include <crepe/api/Engine.h>
#include <crepe/api/Scene.h>
-#include <crepe/types.h>
using namespace crepe;
class MyScene : public Scene {
public:
void load_scene() {
- ComponentManager & mgr = this->component_manager;
- GameObject object1 = mgr.new_object("object1", "tag_my_scene", vec2{0, 0}, 0, 1);
- GameObject object2 = mgr.new_object("object2", "tag_my_scene", vec2{1, 0}, 0, 1);
+ GameObject object1 = new_object("object1", "tag_my_scene", vec2{0, 0}, 0, 1);
+ GameObject object2 = new_object("object2", "tag_my_scene", vec2{1, 0}, 0, 1);
}
string get_name() const { return "my_scene"; }
};
int main() {
- LoopManager loop_mgr;
+ Engine foo;
// Add the scenes to the loop manager
- loop_mgr.add_scene<MyScene>();
+ foo.add_scene<MyScene>();
- loop_mgr.start();
+ return foo.main();
}
```
diff --git a/src/doc/feature/script.dox b/src/doc/feature/script.dox
index d25a63b..162b0f5 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 three functions (\ref Script::init "\c init()",
+\ref Script::fixed_update "\c fixed_update()" and \ref Script::frame_update
+"\c frame_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>
@@ -36,25 +34,33 @@ class MyScript : public crepe::Script {
void init() {
// called once
}
- void update() {
+
+ void fixed_update(crepe::duration_t delta_time) {
// called on fixed update
}
+ void frame_update(crepe::duration_t delta_time) {
+ // called for every rendered frame
+ }
};
```
-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..8bd3376
--- /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>();
+ logf("My name is {}", own_metadata.name);
+ }
+
+ void list_enemies() {
+ RefVector<Metadata> enemies = get_components_by_tag<Metadata>("enemy");
+ logf("There are {} enemies:", enemies.size());
+ for (const Metadata & enemy : enemies) {
+ 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/index.dox b/src/doc/index.dox
index 7796f34..342db98 100644
--- a/src/doc/index.dox
+++ b/src/doc/index.dox
@@ -5,7 +5,14 @@
Welcome to the documentation for the crêpe game engine.
-\see feature
+\see \ref install "Engine installation instructions"
+\see \ref feature "Example code and usage instructions"
+\see [API documentation](annotated.html)
+
+\noop No bold links in "See also" section
+\htmlonly
+<style> .section.see a { font-weight: normal; } </style>
+\endhtmlonly
*/
diff --git a/src/doc/layout.xml b/src/doc/layout.xml
index 6336655..c98c790 100644
--- a/src/doc/layout.xml
+++ b/src/doc/layout.xml
@@ -4,7 +4,7 @@
<tab type="mainpage" visible="yes" title="Intro"/>
<tab type="user" url="@ref install" title="Installation"/>
<tab type="user" url="@ref feature" title="Features"/>
- <tab type="user" url="@ref internal" title="Internals"/>
+ <!-- <tab type="user" url="@ref internal" title="Internals"/> -->
<tab type="pages" visible="no" title="" intro=""/>
<tab type="topics" visible="no" title="" intro=""/>
<tab type="modules" visible="no" title="" intro="">
@@ -22,7 +22,7 @@
<tab type="interfaceindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="interfacehierarchy" visible="yes" title="" intro=""/>
</tab>
- <tab type="classes" visible="yes" title="">
+ <tab type="classes" visible="yes" title="API">
<tab type="classlist" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="hierarchy" visible="yes" title="" intro=""/>
@@ -50,6 +50,7 @@
<inheritancegraph visible="yes"/>
<collaborationgraph visible="yes"/>
<memberdecl>
+ <publicmethods title=""/>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<services title=""/>
@@ -58,7 +59,6 @@
<signals title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
- <publicmethods title=""/>
<publicstaticmethods title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
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/AudioTest.cpp b/src/test/AudioTest.cpp
index 3844c73..e548221 100644
--- a/src/test/AudioTest.cpp
+++ b/src/test/AudioTest.cpp
@@ -60,6 +60,8 @@ TEST_F(AudioTest, Play) {
InSequence seq;
EXPECT_CALL(context, play(_)).Times(0);
+ EXPECT_CALL(context, set_loop(_, _)).Times(0);
+ EXPECT_CALL(context, set_volume(_, _)).Times(0);
component.play();
}
@@ -67,6 +69,8 @@ TEST_F(AudioTest, Play) {
InSequence seq;
EXPECT_CALL(context, play(_)).Times(1);
+ EXPECT_CALL(context, set_loop(_, _)).Times(1);
+ EXPECT_CALL(context, set_volume(_, _)).Times(1);
system.fixed_update();
}
}
@@ -146,6 +150,9 @@ TEST_F(AudioTest, PlayOnActive) {
InSequence seq;
EXPECT_CALL(context, play(_)).Times(1);
+ EXPECT_CALL(context, set_loop(_, _)).Times(1);
+ EXPECT_CALL(context, set_volume(_, _)).Times(1);
+
component.active = true;
system.fixed_update();
}
@@ -156,6 +163,8 @@ TEST_F(AudioTest, PlayImmediately) {
component.play();
EXPECT_CALL(context, play(_)).Times(1);
+ EXPECT_CALL(context, set_volume(_, _)).Times(1);
+ EXPECT_CALL(context, set_loop(_, _)).Times(1);
system.fixed_update();
}
diff --git a/src/test/InputTest.cpp b/src/test/InputTest.cpp
index 9a541a0..a1fe59a 100644
--- a/src/test/InputTest.cpp
+++ b/src/test/InputTest.cpp
@@ -216,7 +216,8 @@ TEST_F(InputTest, testButtonClick) {
EXPECT_EQ(event.metadata.game_object_id, button_obj.id);
return false;
});
- auto & button = button_obj.add_component<Button>(vec2 {100, 100}, vec2 {0, 0});
+ auto & button
+ = button_obj.add_component<Button>(vec2 {100, 100}, Button::Data {}, vec2 {0, 0});
bool hover = false;
button.active = true;
@@ -238,9 +239,14 @@ TEST_F(InputTest, buttonPositionCamera) {
EXPECT_EQ(event.metadata.game_object_id, button_obj.id);
return false;
});
- auto & button = button_obj.add_component<Button>(vec2 {10, 10}, vec2 {0, 0});
+ auto & button = button_obj.add_component<Button>(
+ vec2 {10, 10},
+ Button::Data {
+ .world_space = false,
+ },
+ vec2 {0, 0}
+ );
- button.world_space = false;
bool hover = false;
button.active = true;
this->simulate_mouse_click(999, 999, SDL_BUTTON_LEFT);
@@ -261,8 +267,13 @@ TEST_F(InputTest, buttonPositionWorld) {
EXPECT_EQ(event.metadata.game_object_id, button_obj.id);
return false;
});
- auto & button = button_obj.add_component<Button>(vec2 {10, 10}, vec2 {0, 0});
- button.world_space = true;
+ auto & button = button_obj.add_component<Button>(
+ vec2 {10, 10},
+ Button::Data {
+ .world_space = true,
+ },
+ vec2 {0, 0}
+ );
bool hover = false;
button.active = true;
this->simulate_mouse_click(999, 999, SDL_BUTTON_LEFT);
@@ -288,8 +299,13 @@ TEST_F(InputTest, testButtonHover) {
EXPECT_EQ(event.metadata.game_object_id, button_obj.id);
return false;
});
- auto & button = button_obj.add_component<Button>(vec2 {100, 100}, vec2 {0, 0});
- button.active = true;
+ auto & button = button_obj.add_component<Button>(
+ vec2 {100, 100},
+ Button::Data {
+ .world_space = true,
+ },
+ vec2 {0, 0}
+ );
// Mouse on button
SDL_Event hover_event;
SDL_zero(hover_event);
diff --git a/src/test/Vector2Test.cpp b/src/test/Vector2Test.cpp
index 1e21af9..b17f95a 100644
--- a/src/test/Vector2Test.cpp
+++ b/src/test/Vector2Test.cpp
@@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include <crepe/api/Vector2.h>
+#include <crepe/types.h>
using namespace crepe;
@@ -530,3 +531,12 @@ TEST_F(Vector2Test, Perpendicular) {
EXPECT_FLOAT_EQ(result4.x, -4.0f);
EXPECT_FLOAT_EQ(result4.y, 3.0f);
}
+
+TEST_F(Vector2Test, Rotate) {
+ vec2 foo {0, 1};
+
+ foo = foo.rotate(90);
+ const float GOOD_ENOUGH = 0.001;
+ EXPECT_NEAR(foo.x, 1, GOOD_ENOUGH);
+ EXPECT_NEAR(foo.y, 0, GOOD_ENOUGH);
+}