aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/api/Script.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe/api/Script.h')
-rw-r--r--src/crepe/api/Script.h222
1 files changed, 209 insertions, 13 deletions
diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h
index 49e625f..65306cd 100644
--- a/src/crepe/api/Script.h
+++ b/src/crepe/api/Script.h
@@ -2,37 +2,233 @@
#include <vector>
-namespace crepe {
-class ScriptSystem;
-}
+#include "../api/KeyCodes.h"
+#include "../manager/EventManager.h"
+#include "../manager/Mediator.h"
+#include "../system/CollisionSystem.h"
+#include "../types.h"
+#include "../util/OptionalRef.h"
namespace crepe {
+class ScriptSystem;
class BehaviorScript;
+class ComponentManager;
+/**
+ * \brief Script interface
+ *
+ * This class is used as a base class for user-defined scripts that can be added to game
+ * objects using the \c BehaviorScript component.
+ *
+ * \note Additional *events* (like Unity's OnDisable and OnEnable) should be implemented as
+ * member or lambda methods in derivative user script classes and registered in \c init().
+ *
+ * \warning Concrete scripts are allowed do create a custom constructor, but the utility
+ * functions should not be called inside the constructor as they rely on late references that
+ * are only available after the constructor returns.
+ *
+ * \see feature_script
+ */
class Script {
- friend class crepe::ScriptSystem;
-
protected:
+ /**
+ * \name Interface functions
+ * \{
+ */
+ /**
+ * \brief Script initialization function (empty by default)
+ *
+ * This function is called during the ScriptSystem::update() routine *before*
+ * Script::update() if it (a) has not yet been called and (b) the \c BehaviorScript component
+ * holding this script instance is active.
+ */
virtual void init() {}
+ /**
+ * \brief Script update function (empty by default)
+ *
+ * This function is called during the ScriptSystem::update() routine if the \c BehaviorScript
+ * component holding this script instance is active.
+ */
virtual void update() {}
- // NOTE: additional *events* (like unity's OnDisable and OnEnable) should be
- // implemented as member methods in derivative user script classes and
- // registered in init(), otherwise this class will balloon in size with each
- // added event.
+ //! \}
+
+ //! ScriptSystem calls \c init() and \c update()
+ friend class crepe::ScriptSystem;
protected:
+ /**
+ * \name Utility functions
+ * \{
+ */
+
+ /**
+ * \brief Get single component of type \c T on this game object
+ *
+ * \tparam T Type of component
+ *
+ * \returns Reference to component
+ *
+ * \throws std::runtime_error if this game object does not have a component with type \c T
+ */
+ template <typename T>
+ T & get_component() const;
+ // TODO: make get_component calls for component types that can have more than 1 instance
+ // cause compile-time errors
+
+ /**
+ * \brief Get all components of type \c T on this game object
+ *
+ * \tparam T Type of component
+ *
+ * \returns List of component references
+ */
template <typename T>
- T & get_component();
+ RefVector<T> get_components() const;
+ /**
+ * \copydoc ComponentManager::get_components_by_id
+ * \see ComponentManager::get_components_by_id
+ */
template <typename T>
- std::vector<std::reference_wrapper<T>> get_components();
+ RefVector<T> get_components_by_id(game_object_id_t id) const;
+ /**
+ * \copydoc ComponentManager::get_components_by_name
+ * \see ComponentManager::get_components_by_name
+ */
+ template <typename T>
+ RefVector<T> get_components_by_name(const std::string & name) const;
+ /**
+ * \copydoc ComponentManager::get_components_by_tag
+ * \see ComponentManager::get_components_by_tag
+ */
+ template <typename T>
+ RefVector<T> get_components_by_tag(const std::string & tag) const;
+
+ /**
+ * \brief Log a message using Log::logf
+ *
+ * \tparam Args Log::logf parameters
+ * \param args Log::logf parameters
+ */
+ template <typename... Args>
+ void logf(Args &&... args);
+
+ /**
+ * \brief Subscribe to an event with an explicit channel
+ * \see EventManager::subscribe
+ */
+ template <typename EventType>
+ void subscribe(const EventHandler<EventType> & callback, event_channel_t channel);
+ /**
+ * \brief Subscribe to an event on EventManager::CHANNEL_ALL
+ * \see EventManager::subscribe
+ */
+ template <typename EventType>
+ void subscribe(const EventHandler<EventType> & callback);
+
+ /**
+ * \brief Set the next scene using SceneManager
+ * \see SceneManager::set_next_scene
+ */
+ void set_next_scene(const std::string & name);
+
+ //! Retrieve SaveManager reference
+ SaveManager & get_save_manager() const;
+ /**
+ * \brief Utility function to retrieve the keyboard state
+ * \see SDLContext::get_keyboard_state
+ *
+ * \return current keyboard state map with Keycode as key and bool as value(true = pressed, false = not pressed)
+ *
+ */
+ const keyboard_state_t & get_keyboard_state() const;
+ /**
+ * \brief Utility function to retrieve a single key state.
+ * \see SDLContext::get_keyboard_state
+ *
+ * \return Keycode state (true if pressed, false if not pressed).
+ *
+ */
+ bool get_key_state(Keycode key) const noexcept;
+ //! \}
private:
- friend class crepe::BehaviorScript;
- BehaviorScript * parent = nullptr;
+ /**
+ * \brief Internal subscribe function
+ *
+ * This function exists so certain template specializations of Script::subscribe can be
+ * explicitly deleted, and does the following:
+ * - Wrap the user-provided callback in a check that tests if the parent BehaviorScript
+ * component is still active
+ * - Store the subscriber handle returned by the event manager so this listener is
+ * automatically unsubscribed at the end of this Script instance's life
+ *
+ * \tparam EventType concrete Event class
+ * \param callback User-provided callback function
+ * \param channel Event channel (may have been overridden by template specializations)
+ */
+ template <typename EventType>
+ void subscribe_internal(const EventHandler<EventType> & callback, event_channel_t channel);
+
+protected:
+ // NOTE: This must be the only constructor on Script, see "Late references" below
+ Script() = default;
+ //! Only \c BehaviorScript instantiates Script
+ friend class BehaviorScript;
+
+public:
+ // std::unique_ptr destroys script
+ virtual ~Script();
+
+private:
+ Script(const Script &) = delete;
+ Script(Script &&) = delete;
+ Script & operator=(const Script &) = delete;
+ Script & operator=(Script &&) = delete;
+
+private:
+ /**
+ * \name Late references
+ *
+ * These references are set by BehaviorScript immediately after calling the constructor of
+ * Script.
+ *
+ * \note Script must have a constructor without arguments so the game programmer doesn't need
+ * to manually add `using Script::Script` to their concrete script class if they want to
+ * implement a non-default constructor (e.g. for passing references to their own concrete
+ * Script classes).
+ *
+ * \{
+ */
+ //! Game object ID of game object parent BehaviorScript is attached to
+ game_object_id_t game_object_id;
+ //! Reference to parent component
+ OptionalRef<bool> active;
+ //! Mediator reference
+ OptionalRef<Mediator> mediator;
+ //! \}
+
+private:
+ //! Flag to indicate if \c init() has been called already
+ bool initialized = false;
+ //! List of subscribed events
+ std::vector<subscription_t> listeners;
};
+/**
+ * \brief Subscribe to CollisionEvent for the current GameObject
+ *
+ * This is a template specialization for Script::subscribe which automatically sets the event
+ * channel so the callback handler is only called for CollisionEvent events that apply to the
+ * current GameObject the parent BehaviorScript is attached to.
+ */
+template <>
+void Script::subscribe(const EventHandler<CollisionEvent> & callback);
+template <>
+void Script::subscribe(const EventHandler<CollisionEvent> & callback, event_channel_t)
+ = delete;
+
} // namespace crepe
#include "Script.hpp"