Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e48df894cf | |||
| 4102756e33 |
@@ -38,6 +38,7 @@ public:
|
|||||||
m_InputManager->Update(dt);
|
m_InputManager->Update(dt);
|
||||||
m_World->Update(dt);
|
m_World->Update(dt);
|
||||||
m_Renderer->Draw(dt);
|
m_Renderer->Draw(dt);
|
||||||
|
m_EventBroker->Clear();
|
||||||
|
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-4
@@ -1,5 +1,6 @@
|
|||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
#include "EventBroker.h"
|
#include "EventBroker.h"
|
||||||
|
#include "Events/BindKey.h"
|
||||||
|
|
||||||
BaseEventRelay::~BaseEventRelay()
|
BaseEventRelay::~BaseEventRelay()
|
||||||
{
|
{
|
||||||
@@ -11,12 +12,18 @@ BaseEventRelay::~BaseEventRelay()
|
|||||||
|
|
||||||
void EventBroker::Unsubscribe(BaseEventRelay &relay) // ?
|
void EventBroker::Unsubscribe(BaseEventRelay &relay) // ?
|
||||||
{
|
{
|
||||||
auto itpair = m_Subscribers.equal_range(relay.m_TypeName);
|
auto contextIt = m_ContextRelays.find(relay.m_ContextTypeName);
|
||||||
|
if (contextIt == m_ContextRelays.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto eventRelays = contextIt->second;
|
||||||
|
|
||||||
|
auto itpair = eventRelays.equal_range(relay.m_EventTypeName);
|
||||||
for (auto it = itpair.first; it != itpair.second; ++it)
|
for (auto it = itpair.first; it != itpair.second; ++it)
|
||||||
{
|
{
|
||||||
if (it->second == &relay)
|
if (it->second == &relay)
|
||||||
{
|
{
|
||||||
m_Subscribers.erase(it);
|
eventRelays.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,5 +32,37 @@ void EventBroker::Unsubscribe(BaseEventRelay &relay) // ?
|
|||||||
void EventBroker::Subscribe(BaseEventRelay &relay)
|
void EventBroker::Subscribe(BaseEventRelay &relay)
|
||||||
{
|
{
|
||||||
relay.m_Broker = this;
|
relay.m_Broker = this;
|
||||||
m_Subscribers.insert(std::make_pair(relay.m_TypeName, &relay));
|
m_ContextRelays[relay.m_ContextTypeName].insert(std::make_pair(relay.m_EventTypeName, &relay));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int EventBroker::Process(std::string contextTypeName)
|
||||||
|
{
|
||||||
|
auto it = m_ContextRelays.find(contextTypeName);
|
||||||
|
if (it == m_ContextRelays.end())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
EventRelays_t &relays = it->second;
|
||||||
|
|
||||||
|
int eventsProcessed = 0;
|
||||||
|
for (auto &pair : *m_EventQueueRead)
|
||||||
|
{
|
||||||
|
std::string &eventTypeName = pair.first;
|
||||||
|
std::shared_ptr<Event> event = pair.second;
|
||||||
|
|
||||||
|
auto itpair = relays.equal_range(eventTypeName);
|
||||||
|
for (auto it2 = itpair.first; it2 != itpair.second; ++it2)
|
||||||
|
{
|
||||||
|
auto relay = it2->second;
|
||||||
|
relay->Receive(event);
|
||||||
|
eventsProcessed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return eventsProcessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventBroker::Clear()
|
||||||
|
{
|
||||||
|
std::swap(m_EventQueueRead, m_EventQueueWrite);
|
||||||
|
m_EventQueueWrite->clear();
|
||||||
|
}
|
||||||
|
|||||||
+69
-16
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
@@ -23,19 +24,22 @@ class BaseEventRelay
|
|||||||
friend class EventBroker;
|
friend class EventBroker;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BaseEventRelay(std::string typeName)
|
BaseEventRelay(std::string contextTypeName, std::string eventTypeName)
|
||||||
: m_TypeName(typeName), m_Broker(nullptr) { }
|
: m_ContextTypeName(contextTypeName)
|
||||||
|
, m_EventTypeName(eventTypeName)
|
||||||
|
, m_Broker(nullptr) { }
|
||||||
~BaseEventRelay();
|
~BaseEventRelay();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool Receive(const Event &event) = 0;
|
virtual bool Receive(const std::shared_ptr<Event> event) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string m_TypeName;
|
std::string m_ContextTypeName;
|
||||||
|
std::string m_EventTypeName;
|
||||||
EventBroker* m_Broker;
|
EventBroker* m_Broker;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename EventType>
|
template <typename ContextType, typename EventType>
|
||||||
class EventRelay : public BaseEventRelay
|
class EventRelay : public BaseEventRelay
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -43,24 +47,24 @@ public:
|
|||||||
|
|
||||||
EventRelay()
|
EventRelay()
|
||||||
: m_Callback(nullptr)
|
: m_Callback(nullptr)
|
||||||
, BaseEventRelay(typeid(EventType).name()) { }
|
, BaseEventRelay(typeid(ContextType).name(), typeid(EventType).name()) { }
|
||||||
EventRelay(CallbackType callback)
|
EventRelay(CallbackType callback)
|
||||||
: m_Callback(callback)
|
: m_Callback(callback)
|
||||||
, BaseEventRelay(typeid(EventType).name()) { }
|
, BaseEventRelay(typeid(ContextType).name(), typeid(EventType).name()) { }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool Receive(const Event &event) override;
|
bool Receive(const std::shared_ptr<Event> event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CallbackType m_Callback;
|
CallbackType m_Callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename EventType>
|
template <typename ContextType, typename EventType>
|
||||||
bool EventRelay<EventType>::Receive(const Event &event)
|
bool EventRelay<ContextType, EventType>::Receive(const std::shared_ptr<Event> event)
|
||||||
{
|
{
|
||||||
if (m_Callback != nullptr)
|
if (m_Callback != nullptr)
|
||||||
{
|
{
|
||||||
return m_Callback(static_cast<const EventType&>(event));
|
return m_Callback(*static_cast<const EventType*>(event.get()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -70,26 +74,75 @@ bool EventRelay<EventType>::Receive(const Event &event)
|
|||||||
|
|
||||||
class EventBroker
|
class EventBroker
|
||||||
{
|
{
|
||||||
template <typename EventType> friend class EventRelay;
|
template <typename ContextType, typename EventType> friend class EventRelay;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
EventBroker()
|
||||||
|
{
|
||||||
|
m_EventQueueRead = std::make_shared<EventQueue_t>();
|
||||||
|
m_EventQueueWrite = std::make_shared<EventQueue_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Subscribe(BaseEventRelay &relay);
|
||||||
template <typename EventType>
|
template <typename EventType>
|
||||||
void Publish(const EventType &event);
|
void Publish(const EventType &event);
|
||||||
void Subscribe(BaseEventRelay &relay);
|
// Process all events no matter the context.
|
||||||
|
/*void Process()
|
||||||
|
{
|
||||||
|
|
||||||
|
}*/
|
||||||
|
/*
|
||||||
|
Process all events in a given context.
|
||||||
|
Returns: Number of events processed
|
||||||
|
*/
|
||||||
|
template <typename ContextType>
|
||||||
|
int Process();
|
||||||
|
int Process(std::string contextTypeName);
|
||||||
|
void Clear();
|
||||||
void Unsubscribe(BaseEventRelay &relay);
|
void Unsubscribe(BaseEventRelay &relay);
|
||||||
|
template <typename ContextType>
|
||||||
|
void UnsubscribeAll();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_multimap<std::string, BaseEventRelay*> m_Subscribers;
|
typedef std::string ContextTypeName_t; // typeid(ContextType).name()
|
||||||
};
|
typedef std::string EventTypeName_t; // typeid(EventType).name()
|
||||||
|
|
||||||
|
typedef std::unordered_multimap<EventTypeName_t, BaseEventRelay*> EventRelays_t;
|
||||||
|
typedef std::unordered_map<ContextTypeName_t, EventRelays_t> ContextRelays_t;
|
||||||
|
ContextRelays_t m_ContextRelays;
|
||||||
|
|
||||||
|
typedef std::list<std::pair<EventTypeName_t, std::shared_ptr<Event>>> EventQueue_t;
|
||||||
|
std::shared_ptr<EventQueue_t> m_EventQueueRead;
|
||||||
|
std::shared_ptr<EventQueue_t> m_EventQueueWrite;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename EventType>
|
template <typename EventType>
|
||||||
void EventBroker::Publish(const EventType &event)
|
void EventBroker::Publish(const EventType &event)
|
||||||
{
|
{
|
||||||
auto itpair = m_Subscribers.equal_range(typeid(EventType).name());
|
/*auto itpair = m_Subscribers.equal_range(typeid(EventType).name());
|
||||||
for (auto it = itpair.first; it != itpair.second; ++it)
|
for (auto it = itpair.first; it != itpair.second; ++it)
|
||||||
{
|
{
|
||||||
it->second->Receive(event);
|
it->second->Receive(event);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
m_EventQueueWrite->push_back(std::make_pair(typeid(EventType).name(), std::shared_ptr<EventType>(new EventType(event))));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ContextType>
|
||||||
|
int EventBroker::Process()
|
||||||
|
{
|
||||||
|
const std::string contextTypeName = typeid(ContextType).name();
|
||||||
|
return Process(contextTypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ContextType>
|
||||||
|
void EventBroker::UnsubscribeAll()
|
||||||
|
{
|
||||||
|
const std::string contextTypeName = typeid(ContextType).name();
|
||||||
|
auto contextIt = m_ContextRelays.find(contextTypeName);
|
||||||
|
if (contextIt != m_ContextRelays.end())
|
||||||
|
{
|
||||||
|
m_ContextRelays.erase(contextIt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "Events/InputCommand.h"
|
#include "Events/InputCommand.h"
|
||||||
#include "Events/MouseMove.h"
|
#include "Events/MouseMove.h"
|
||||||
|
|
||||||
|
template <typename EventContext>
|
||||||
class InputController
|
class InputController
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -26,8 +27,8 @@ protected:
|
|||||||
std::shared_ptr<::EventBroker> EventBroker;
|
std::shared_ptr<::EventBroker> EventBroker;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EventRelay<Events::InputCommand> m_EInputCommand;
|
EventRelay<EventContext, Events::InputCommand> m_EInputCommand;
|
||||||
EventRelay<Events::MouseMove> m_EMouseMove;
|
EventRelay<EventContext, Events::MouseMove> m_EMouseMove;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // InputController_h__
|
#endif // InputController_h__
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ void InputManager::Initialize()
|
|||||||
|
|
||||||
void InputManager::Update(double dt)
|
void InputManager::Update(double dt)
|
||||||
{
|
{
|
||||||
|
EventBroker->Process<InputManager>();
|
||||||
|
|
||||||
m_LastKeyState = m_CurrentKeyState;
|
m_LastKeyState = m_CurrentKeyState;
|
||||||
m_LastMouseState = m_CurrentMouseState;
|
m_LastMouseState = m_CurrentMouseState;
|
||||||
m_LastMouseX = m_CurrentMouseX;
|
m_LastMouseX = m_CurrentMouseX;
|
||||||
|
|||||||
+2
-2
@@ -39,9 +39,9 @@ private:
|
|||||||
GLFWwindow* m_GLFWWindow;
|
GLFWwindow* m_GLFWWindow;
|
||||||
std::shared_ptr<::EventBroker> EventBroker;
|
std::shared_ptr<::EventBroker> EventBroker;
|
||||||
|
|
||||||
EventRelay<Events::LockMouse> m_ELockMouse;
|
EventRelay<InputManager, Events::LockMouse> m_ELockMouse;
|
||||||
bool OnLockMouse(const Events::LockMouse &event);
|
bool OnLockMouse(const Events::LockMouse &event);
|
||||||
EventRelay<Events::UnlockMouse> m_EUnlockMouse;
|
EventRelay<InputManager, Events::UnlockMouse> m_EUnlockMouse;
|
||||||
bool OnUnlockMouse(const Events::UnlockMouse &event);
|
bool OnUnlockMouse(const Events::UnlockMouse &event);
|
||||||
|
|
||||||
std::array<int, GLFW_KEY_LAST+1> m_CurrentKeyState;
|
std::array<int, GLFW_KEY_LAST+1> m_CurrentKeyState;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public:
|
|||||||
|
|
||||||
void Update(double dt) override;
|
void Update(double dt) override;
|
||||||
|
|
||||||
EventRelay<Events::KeyDown> m_EKeyDown;
|
EventRelay<DebugSystem, Events::KeyDown> m_EKeyDown;
|
||||||
bool OnKeyDown(const Events::KeyDown &event);
|
bool OnKeyDown(const Events::KeyDown &event);
|
||||||
|
|
||||||
//void UpdateEntity(double dt, EntityID entity, EntityID parent) override;
|
//void UpdateEntity(double dt, EntityID entity, EntityID parent) override;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ private:
|
|||||||
std::unique_ptr<FreeSteeringInputController> m_InputController;
|
std::unique_ptr<FreeSteeringInputController> m_InputController;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FreeSteeringSystem::FreeSteeringInputController : InputController
|
class FreeSteeringSystem::FreeSteeringInputController : InputController<FreeSteeringSystem>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FreeSteeringInputController(std::shared_ptr<::EventBroker> eventBroker)
|
FreeSteeringInputController(std::shared_ptr<::EventBroker> eventBroker)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ private:
|
|||||||
std::map<EntityID, double> m_TimeSinceLastShot;
|
std::map<EntityID, double> m_TimeSinceLastShot;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HelicopterSteeringSystem::HelicopterSteeringInputController : InputController
|
class HelicopterSteeringSystem::HelicopterSteeringInputController : InputController<HelicopterSteeringSystem>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HelicopterSteeringInputController(std::shared_ptr<::EventBroker> eventBroker)
|
HelicopterSteeringInputController(std::shared_ptr<::EventBroker> eventBroker)
|
||||||
|
|||||||
+11
-11
@@ -45,28 +45,28 @@ private:
|
|||||||
std::unordered_map<Gamepad::Button, std::tuple<std::string, float>> m_GamepadButtonBindings; // Gamepad::Button -> command string
|
std::unordered_map<Gamepad::Button, std::tuple<std::string, float>> m_GamepadButtonBindings; // Gamepad::Button -> command string
|
||||||
|
|
||||||
// Input events
|
// Input events
|
||||||
EventRelay<Events::KeyDown> m_EKeyDown;
|
EventRelay<InputSystem, Events::KeyDown> m_EKeyDown;
|
||||||
bool OnKeyDown(const Events::KeyDown &event);
|
bool OnKeyDown(const Events::KeyDown &event);
|
||||||
EventRelay<Events::KeyUp> m_EKeyUp;
|
EventRelay<InputSystem, Events::KeyUp> m_EKeyUp;
|
||||||
bool OnKeyUp(const Events::KeyUp &event);
|
bool OnKeyUp(const Events::KeyUp &event);
|
||||||
EventRelay<Events::MousePress> m_EMousePress;
|
EventRelay<InputSystem, Events::MousePress> m_EMousePress;
|
||||||
bool OnMousePress(const Events::MousePress &event);
|
bool OnMousePress(const Events::MousePress &event);
|
||||||
EventRelay<Events::MouseRelease> m_EMouseRelease;
|
EventRelay<InputSystem, Events::MouseRelease> m_EMouseRelease;
|
||||||
bool OnMouseRelease(const Events::MouseRelease &event);
|
bool OnMouseRelease(const Events::MouseRelease &event);
|
||||||
EventRelay<Events::GamepadAxis> m_EGamepadAxis;
|
EventRelay<InputSystem, Events::GamepadAxis> m_EGamepadAxis;
|
||||||
bool OnGamepadAxis(const Events::GamepadAxis &event);
|
bool OnGamepadAxis(const Events::GamepadAxis &event);
|
||||||
EventRelay<Events::GamepadButtonDown> m_EGamepadButtonDown;
|
EventRelay<InputSystem, Events::GamepadButtonDown> m_EGamepadButtonDown;
|
||||||
bool OnGamepadButtonDown(const Events::GamepadButtonDown &event);
|
bool OnGamepadButtonDown(const Events::GamepadButtonDown &event);
|
||||||
EventRelay<Events::GamepadButtonUp> m_EGamepadButtonUp;
|
EventRelay<InputSystem, Events::GamepadButtonUp> m_EGamepadButtonUp;
|
||||||
bool OnGamepadButtonUp(const Events::GamepadButtonUp &event);
|
bool OnGamepadButtonUp(const Events::GamepadButtonUp &event);
|
||||||
// Input binding events
|
// Input binding events
|
||||||
EventRelay<Events::BindKey> m_EBindKey;
|
EventRelay<InputSystem, Events::BindKey> m_EBindKey;
|
||||||
bool OnBindKey(const Events::BindKey &event);
|
bool OnBindKey(const Events::BindKey &event);
|
||||||
EventRelay<Events::BindMouseButton> m_EBindMouseButton;
|
EventRelay<InputSystem, Events::BindMouseButton> m_EBindMouseButton;
|
||||||
bool OnBindMouseButton(const Events::BindMouseButton &event);
|
bool OnBindMouseButton(const Events::BindMouseButton &event);
|
||||||
EventRelay<Events::BindGamepadAxis> m_EBindGamepadAxis;
|
EventRelay<InputSystem, Events::BindGamepadAxis> m_EBindGamepadAxis;
|
||||||
bool OnBindGamepadAxis(const Events::BindGamepadAxis &event);
|
bool OnBindGamepadAxis(const Events::BindGamepadAxis &event);
|
||||||
EventRelay<Events::BindGamepadButton> m_EBindGamepadButton;
|
EventRelay<InputSystem, Events::BindGamepadButton> m_EBindGamepadButton;
|
||||||
bool OnBindGamepadButton(const Events::BindGamepadButton &event);
|
bool OnBindGamepadButton(const Events::BindGamepadButton &event);
|
||||||
|
|
||||||
float GetCommandTotalValue(std::string command);
|
float GetCommandTotalValue(std::string command);
|
||||||
|
|||||||
@@ -113,13 +113,13 @@ private:
|
|||||||
hkpWorld* m_PhysicsWorld;
|
hkpWorld* m_PhysicsWorld;
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
EventRelay<Events::TankSteer> m_ETankSteer;
|
EventRelay<PhysicsSystem, Events::TankSteer> m_ETankSteer;
|
||||||
bool OnTankSteer(const Events::TankSteer &event);
|
bool OnTankSteer(const Events::TankSteer &event);
|
||||||
EventRelay<Events::SetVelocity> m_ESetVelocity;
|
EventRelay<PhysicsSystem, Events::SetVelocity> m_ESetVelocity;
|
||||||
bool OnSetVelocity(const Events::SetVelocity &event);
|
bool OnSetVelocity(const Events::SetVelocity &event);
|
||||||
EventRelay<Events::ApplyForce> m_EApplyForce;
|
EventRelay<PhysicsSystem, Events::ApplyForce> m_EApplyForce;
|
||||||
bool OnApplyForce(const Events::ApplyForce &event);
|
bool OnApplyForce(const Events::ApplyForce &event);
|
||||||
EventRelay<Events::ApplyPointImpulse> m_EApplyPointImpulse;
|
EventRelay<PhysicsSystem, Events::ApplyPointImpulse> m_EApplyPointImpulse;
|
||||||
bool OnApplyPointImpulse(const Events::ApplyPointImpulse &event);
|
bool OnApplyPointImpulse(const Events::ApplyPointImpulse &event);
|
||||||
|
|
||||||
void SetUpPhysicsState(EntityID entity, EntityID parent);
|
void SetUpPhysicsState(EntityID entity, EntityID parent);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ private:
|
|||||||
//unsigned long dataSize;
|
//unsigned long dataSize;
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
EventRelay<Events::PlaySound> m_EPlaySound;
|
EventRelay<SoundSystem, Events::PlaySound> m_EPlaySound;
|
||||||
bool OnPlaySound(const Events::PlaySound &event);
|
bool OnPlaySound(const Events::PlaySound &event);
|
||||||
|
|
||||||
std::map<Component*, ALuint> m_Sources;
|
std::map<Component*, ALuint> m_Sources;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace Systems
|
|||||||
std::map<EntityID, double> m_TimeSinceLastShot;
|
std::map<EntityID, double> m_TimeSinceLastShot;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TankSteeringSystem::TankSteeringInputController : InputController
|
class TankSteeringSystem::TankSteeringInputController : InputController<TankSteeringSystem>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TankSteeringInputController(std::shared_ptr<::EventBroker> eventBroker, int playerID)
|
TankSteeringInputController(std::shared_ptr<::EventBroker> eventBroker, int playerID)
|
||||||
|
|||||||
@@ -36,7 +36,9 @@ void World::Update(double dt)
|
|||||||
{
|
{
|
||||||
for (auto pair : m_Systems)
|
for (auto pair : m_Systems)
|
||||||
{
|
{
|
||||||
|
const std::string &type = pair.first;
|
||||||
auto system = pair.second;
|
auto system = pair.second;
|
||||||
|
m_EventBroker->Process(type);
|
||||||
system->Update(dt);
|
system->Update(dt);
|
||||||
RecursiveUpdate(system, dt, 0);
|
RecursiveUpdate(system, dt, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user