Simulant  21.12-574
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
behaviour.h
1 /* * Copyright (c) 2011-2017 Luke Benstead https://simulant-engine.appspot.com
2  *
3  * This file is part of Simulant.
4  *
5  * Simulant is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Simulant is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with Simulant. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef behaviour_H
20 #define behaviour_H
21 
22 #include <vector>
23 #include <set>
24 #include <memory>
25 #include <type_traits>
26 
27 #include "../logging.h"
28 
29 #include "../generic/property.h"
30 #include "../generic/managed.h"
31 #include "../interfaces/updateable.h"
32 #include "../input/input_manager.h"
33 
34 namespace smlt {
35 
36 class InputManager;
37 class Material;
38 class Behaviour;
39 class Organism;
40 
41 typedef std::shared_ptr<Behaviour> BehaviourPtr;
42 
43 class Behaviour:
44  public Updateable {
45 public:
46  virtual ~Behaviour() {}
47 
48  virtual const char* name() const = 0;
49 
50  void enable();
51  void disable();
52 
53  void _update_thunk(float dt) override;
54  void _late_update_thunk(float dt) override;
55  void _fixed_update_thunk(float step) override;
56 
58  this, &Behaviour::organism_
59  };
60 
61  bool attached() const { return organism_ != nullptr; }
62 private:
63  friend class Organism;
64 
65  Organism* organism_ = nullptr;
66  void set_organism(Organism* organism) {
67  if(organism) {
68  if(organism_) {
69  on_behaviour_removed(organism_);
70  }
71 
72  organism_ = organism;
73 
74  on_behaviour_added(organism);
75  } else if(organism_) {
76  organism_ = nullptr;
77 
78  on_behaviour_removed(organism_);
79  }
80  }
81 
82  /* Don't call these directly, use set_organism instead */
83  virtual void on_behaviour_added(Organism* controllable) {
84  _S_UNUSED(controllable);
85  }
86 
87  virtual void on_behaviour_removed(Organism* controllable) {
88  _S_UNUSED(controllable);
89  }
90 
91  /* Called on the first update after being enabled */
92  virtual void on_behaviour_first_update(Organism* controllable) {
93  _S_UNUSED(controllable);
94  }
95 
96  bool is_enabled_ = true;
97  bool first_update_done_ = false;
98 };
99 
101 public:
103  input_(input) {}
104 
105 protected:
107  this, &BehaviourWithInput::input_
108  };
109 
110 private:
111  InputManager* input_;
112 };
113 
114 class MaterialBehaviour : public Behaviour {
115 public:
116  MaterialBehaviour(Material* material):
117  Behaviour(),
118  material_(material) {
119  }
120 
121 private:
122  Material* material_;
123 
124 protected:
125  Property<decltype(&MaterialBehaviour::material_)> material = {
126  this, &MaterialBehaviour::material_
127  };
128  Material* get_material() const { return material_; }
129 
130 };
131 
132 class Organism {
133 public:
134  virtual ~Organism();
135 
136  template<typename T>
137  bool has_behaviour() const {
138  return behaviour_types_.count(typeid(T).hash_code()) > 0;
139  }
140 
141  template<typename T>
142  T* behaviour() const {
143  auto hash_code = typeid(T).hash_code();
144  if(!behaviour_types_.count(hash_code)) {
145  return nullptr;
146  }
147 
148  return dynamic_cast<T*>(behaviour_types_.at(hash_code).get());
149  }
150 
151  template<typename T>
152  T* new_behaviour() {
153  static_assert(std::is_base_of<Behaviour, T>::value, "Behaviours must derive smlt::Behaviour");
154  static_assert(std::is_base_of<RefCounted<T>, T>::value, "Behaviours must derive RefCounted<T>");
155  std::shared_ptr<T> ret = T::create();
156  add_behaviour<T>(ret);
157  return ret.get();
158  }
159 
160  template<typename T, typename ...Params>
161  T* new_behaviour(Params&&... params) {
162  static_assert(std::is_base_of<Behaviour, T>::value, "Behaviours must derive smlt::Behaviour");
163  static_assert(std::is_base_of<RefCounted<T>, T>::value, "Behaviours must derive RefCounted<T>");
164  std::shared_ptr<T> ret = T::create(std::forward<Params>(params)...);
165  add_behaviour<T>(ret);
166  return ret.get();
167  }
168 
169  void fixed_update_behaviours(float step) {
170  for(auto& behaviour: behaviours_) {
171  behaviour->_fixed_update_thunk(step);
172  }
173  }
174 
175  void update_behaviours(float dt) {
176  for(auto& behaviour: behaviours_) {
177 
178  // Call any overridden functions looking for first update
179  if(!behaviour->first_update_done_) {
180  behaviour->on_behaviour_first_update(this);
181  behaviour->first_update_done_ = true;
182  }
183 
184  behaviour->_update_thunk(dt);
185  }
186  }
187 
188  void late_update_behaviours(float dt) {
189  for(auto& behaviour: behaviours_) {
190  behaviour->_late_update_thunk(dt);
191  }
192  }
193 
194 private:
195  template<typename T>
196  void add_behaviour(std::shared_ptr<T> behaviour) {
197  static_assert(std::is_base_of<Behaviour, T>::value, "Behaviours must derive smlt::Behaviour");
198 
199  if(!behaviour) {
200  S_WARN("Tried to add a null behaviour to the controllable");
201  return;
202  }
203 
204  {
205  if(behaviour_names_.count(behaviour->name())) {
206  S_WARN("Tried to add a duplicate behaviour: {0}", (std::string)behaviour->name());
207  return;
208  }
209 
210  behaviour_types_.insert(std::make_pair(typeid(T).hash_code(), behaviour));
211  behaviour_names_.insert(behaviour->name());
212  behaviours_.push_back(behaviour);
213  }
214 
215  // Call outside the lock to prevent deadlocking if
216  // this call triggers the addition/removal of another behaviour
217  behaviour->set_organism(this);
218  }
219 
220  std::vector<BehaviourPtr> behaviours_;
221  std::unordered_set<std::string> behaviour_names_;
222  std::unordered_map<std::size_t, BehaviourPtr> behaviour_types_;
223 
224 };
225 
226 
227 }
228 #endif // behaviour_H
smlt::Property
Definition: property.h:202
smlt::MaterialBehaviour
Definition: behaviour.h:114
smlt::Organism
Definition: behaviour.h:132
smlt::Material
Definition: material.h:95
smlt::Updateable
The Updateable class.
Definition: updateable.h:13
smlt::RefCounted
Definition: managed.h:65
smlt
Definition: animation.cpp:25
smlt::InputManager
Definition: input_manager.h:48
Material
Definition: dcm.h:77
smlt::Behaviour
Definition: behaviour.h:44
smlt::BehaviourWithInput
Definition: behaviour.h:100