aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/api/Script.h
blob: 4d98e4d3d7cdff926212fed60df4c3b704a4b111 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#pragma once

#include <vector>

#include "../types.h"

#include "EventManager.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().
 */
class Script {
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() {}
	//! \}

	//! 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 matching 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>
	std::vector<std::reference_wrapper<T>> get_components() 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);

	game_object_id_t get_game_object_id() const { return this->game_object_id; };

	/**
	 * \brief Subscribe to an event
	 *
	 * \see EventManager::subscribe
	 */
	template <typename EventType>
	void subscribe(const EventHandler<EventType> & callback, event_channel_t channel = EventManager::CHANNEL_ALL);

	//! \}

protected:
	// 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.
	Script() = default;
	//! Only \c BehaviorScript instantiates Script
	friend class BehaviorScript;
public:
	// std::unique_ptr destroys script
	virtual ~Script();

	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.
	 *
	 * \{
	 */
	//! Game object ID of game object parent BehaviorScript is attached to
	game_object_id_t game_object_id = -1;
	//! Reference to component manager instance
	ComponentManager * component_manager_ref = nullptr;
	//! Reference to event manager instance
	EventManager * event_manager_ref = nullptr;
	//! \}

private:
	//! Flag to indicate if \c init() has been called already
	bool initialized = false;
	//! List of subscribed events
	std::vector<subscription_t> listeners;
};

} // namespace crepe

#include "Script.hpp"