Refactored InputProxy to gracefully handle cases where multiple origins send the same command
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "../GLM.h"
|
#include "../GLM.h"
|
||||||
#include "../Core/InputController.h"
|
#include "../Core/InputController.h"
|
||||||
|
#include "../Core/ELockMouse.h"
|
||||||
|
|
||||||
template <typename EventContext>
|
template <typename EventContext>
|
||||||
class FirstPersonInputController : public InputController<EventContext>
|
class FirstPersonInputController : public InputController<EventContext>
|
||||||
@@ -11,30 +12,59 @@ public:
|
|||||||
FirstPersonInputController(EventBroker* eventBroker, unsigned int playerID)
|
FirstPersonInputController(EventBroker* eventBroker, unsigned int playerID)
|
||||||
: InputController(eventBroker)
|
: InputController(eventBroker)
|
||||||
, m_PlayerID(playerID)
|
, m_PlayerID(playerID)
|
||||||
{ }
|
{
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_ELockMouse, &FirstPersonInputController::OnLockMouse);
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EUnlockMouse, &FirstPersonInputController::OnUnlockMouse);
|
||||||
|
}
|
||||||
|
|
||||||
const glm::quat Orientation() const { return m_Orientation; }
|
const glm::quat Orientation() const { return m_Orientation; }
|
||||||
|
|
||||||
|
void LockMouse()
|
||||||
|
{
|
||||||
|
Events::LockMouse e;
|
||||||
|
m_EventBroker->Publish(e);
|
||||||
|
m_MouseLocked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnlockMouse()
|
||||||
|
{
|
||||||
|
Events::UnlockMouse e;
|
||||||
|
m_EventBroker->Publish(e);
|
||||||
|
m_MouseLocked = false;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool OnCommand(const Events::InputCommand& e) override
|
virtual bool OnCommand(const Events::InputCommand& e) override
|
||||||
{
|
{
|
||||||
if (m_PlayerID != e.PlayerID) {
|
if (m_PlayerID != e.PlayerID) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.Command == "Pitch") {
|
if (m_MouseLocked) {
|
||||||
float val = glm::radians(e.Value);
|
if (e.Command == "Pitch") {
|
||||||
m_Orientation = m_Orientation * glm::angleAxis<float>(-val, glm::vec3(1, 0, 0));
|
float val = glm::radians(e.Value);
|
||||||
|
m_Orientation = m_Orientation * glm::angleAxis<float>(-val, glm::vec3(1, 0, 0));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.Command == "Yaw") {
|
||||||
|
float val = glm::radians(e.Value);
|
||||||
|
m_Orientation = glm::angleAxis<float>(-val, glm::vec3(0, 1, 0)) * m_Orientation;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.Command == "Yaw") {
|
return false;
|
||||||
float val = glm::radians(e.Value);
|
|
||||||
m_Orientation = glm::angleAxis<float>(-val, glm::vec3(0, 1, 0)) * m_Orientation;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
const unsigned int m_PlayerID;
|
const unsigned int m_PlayerID;
|
||||||
glm::quat m_Orientation;
|
glm::quat m_Orientation;
|
||||||
|
bool m_MouseLocked = false;
|
||||||
|
|
||||||
|
EventRelay<EventContext, Events::LockMouse> m_ELockMouse;
|
||||||
|
bool OnLockMouse(const Events::LockMouse& e) { m_MouseLocked = true; return true; }
|
||||||
|
EventRelay<EventContext, Events::UnlockMouse> m_EUnlockMouse;
|
||||||
|
bool OnUnlockMouse(const Events::UnlockMouse& e) { m_MouseLocked = false; return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -13,8 +13,9 @@ public:
|
|||||||
, m_InputProxy(inputProxy)
|
, m_InputProxy(inputProxy)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual void Update(double dt) { }
|
|
||||||
virtual bool BindOrigin(std::string origin, std::string command, float value) = 0;
|
virtual bool BindOrigin(std::string origin, std::string command, float value) = 0;
|
||||||
|
virtual void Update(double dt) { }
|
||||||
|
virtual float GetCommandValue(std::string command) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
EventBroker* m_EventBroker;
|
EventBroker* m_EventBroker;
|
||||||
|
|||||||
@@ -20,13 +20,17 @@ public:
|
|||||||
void Process();
|
void Process();
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void AddHandler();
|
void AddHandler();
|
||||||
void Publish(const Events::InputCommand& e);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
EventBroker* m_EventBroker;
|
EventBroker* m_EventBroker;
|
||||||
std::vector<InputHandler*> m_Handlers;
|
std::vector<InputHandler*> m_Handlers;
|
||||||
|
std::map<std::string, std::set<InputHandler*>> m_CommandHandlers;
|
||||||
|
|
||||||
// Represents every unique command (has of PlayerID & Command) and all values reported for that command this frame
|
// Represents every unique command (has of PlayerID & Command) and all values reported for that command this frame
|
||||||
std::map<std::pair<unsigned int, std::string>, std::vector<float>> m_CommandQueue;
|
//std::map<std::pair<unsigned int, std::string>, std::vector<float>> m_CommandQueue;
|
||||||
|
|
||||||
|
std::map<std::string, float> m_CurrentCommandValues;
|
||||||
|
std::map<std::string, float> m_LastCommandValues;
|
||||||
|
|
||||||
EventRelay<InputProxy, Events::BindOrigin> m_EBindOrigin;
|
EventRelay<InputProxy, Events::BindOrigin> m_EBindOrigin;
|
||||||
bool OnBindOrigin(const Events::BindOrigin& e);
|
bool OnBindOrigin(const Events::BindOrigin& e);
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ public:
|
|||||||
KeyboardInputHandler(EventBroker* eventBroker, InputProxy* inputProxy);
|
KeyboardInputHandler(EventBroker* eventBroker, InputProxy* inputProxy);
|
||||||
|
|
||||||
bool BindOrigin(std::string origin, std::string command, float value) override;
|
bool BindOrigin(std::string origin, std::string command, float value) override;
|
||||||
|
virtual float GetCommandValue(std::string command) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, int> m_OriginKeyCodes;
|
std::unordered_map<std::string, int> m_OriginKeyCodes;
|
||||||
std::unordered_map<int, std::tuple<std::string, float>> m_KeyBindings; // GLFW_KEY... -> command string & value
|
std::unordered_map<int, std::tuple<std::string, float>> m_KeyBindings; // GLFW_KEY... -> command string & value
|
||||||
|
std::unordered_map<std::string, float> m_CommandValues;
|
||||||
|
|
||||||
EventRelay<InputHandler, Events::KeyDown> m_EKeyDown;
|
EventRelay<InputHandler, Events::KeyDown> m_EKeyDown;
|
||||||
bool OnKeyDown(const Events::KeyDown& e);
|
bool OnKeyDown(const Events::KeyDown& e);
|
||||||
|
|||||||
@@ -3,10 +3,13 @@ Sensitivity=0.5
|
|||||||
InvertPitch=false
|
InvertPitch=false
|
||||||
|
|
||||||
[Bindings]
|
[Bindings]
|
||||||
W=Forward
|
MouseLeft=PrimaryFire
|
||||||
A=Left
|
MouseX=Yaw
|
||||||
S=Back
|
MouseY=Pitch
|
||||||
D=Right
|
W=+Forward
|
||||||
|
S=-Forward
|
||||||
|
D=+Right
|
||||||
|
A=-Right
|
||||||
R=Reload
|
R=Reload
|
||||||
Space=Jump
|
Space=Jump
|
||||||
LeftControl=Crouch
|
LeftControl=Crouch
|
||||||
|
|||||||
@@ -22,7 +22,16 @@ void InputProxy::LoadBindings(std::string file)
|
|||||||
e.Origin = origin.first;
|
e.Origin = origin.first;
|
||||||
e.Command = origin.second;
|
e.Command = origin.second;
|
||||||
e.Value = 1.f;
|
e.Value = 1.f;
|
||||||
OnBindOrigin(e);
|
if (!e.Command.empty()) {
|
||||||
|
char prefix = e.Command.at(0);
|
||||||
|
if (prefix == '+' || prefix == '-') {
|
||||||
|
e.Command = e.Command.substr(1);
|
||||||
|
if (prefix == '-') {
|
||||||
|
e.Value *= -1.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OnBindOrigin(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,26 +46,26 @@ void InputProxy::Update(double dt)
|
|||||||
|
|
||||||
void InputProxy::Process()
|
void InputProxy::Process()
|
||||||
{
|
{
|
||||||
// Accumulate the input values of all unique commands published by input handlers
|
for (auto& pair : m_CommandHandlers) {
|
||||||
for (auto& pair : m_CommandQueue) {
|
const std::string& command = pair.first;
|
||||||
Events::InputCommand e;
|
auto handlers = pair.second;
|
||||||
e.PlayerID = pair.first.first;
|
m_CurrentCommandValues[command] = 0.f;
|
||||||
e.Command = pair.first.second;
|
for (auto& handler : handlers) {
|
||||||
e.Value = 0;
|
m_CurrentCommandValues[command] += handler->GetCommandValue(command);
|
||||||
for (auto& value : pair.second) {
|
|
||||||
e.Value += value;
|
|
||||||
}
|
}
|
||||||
//e.Value = std::max(-1.f, std::min(e.Value, 1.f));
|
|
||||||
m_EventBroker->Publish(e);
|
|
||||||
LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID);
|
|
||||||
}
|
|
||||||
m_CommandQueue.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InputProxy::Publish(const Events::InputCommand& e)
|
auto last = m_LastCommandValues.find(command);
|
||||||
{
|
float currentValue = m_CurrentCommandValues[command];
|
||||||
auto key = std::make_pair(e.PlayerID, e.Command);
|
if (last == m_LastCommandValues.end() || last->second != currentValue) {
|
||||||
m_CommandQueue[key].push_back(e.Value);
|
Events::InputCommand e;
|
||||||
|
e.PlayerID = -1;
|
||||||
|
e.Command = command;
|
||||||
|
e.Value = currentValue;
|
||||||
|
m_EventBroker->Publish(e);
|
||||||
|
LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID);
|
||||||
|
m_LastCommandValues[command] = currentValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputProxy::OnBindOrigin(const Events::BindOrigin& e)
|
bool InputProxy::OnBindOrigin(const Events::BindOrigin& e)
|
||||||
@@ -65,6 +74,8 @@ bool InputProxy::OnBindOrigin(const Events::BindOrigin& e)
|
|||||||
for (auto& handler : m_Handlers) {
|
for (auto& handler : m_Handlers) {
|
||||||
bool result = handler->BindOrigin(e.Origin, e.Command, e.Value);
|
bool result = handler->BindOrigin(e.Origin, e.Command, e.Value);
|
||||||
if (result) {
|
if (result) {
|
||||||
|
m_CommandHandlers[e.Command].insert(handler);
|
||||||
|
m_LastCommandValues[e.Command] = 0.f;
|
||||||
if (originBound) {
|
if (originBound) {
|
||||||
LOG_WARNING("Multiple handlers responded to binding input origin \"%s\"!", e.Origin.c_str());
|
LOG_WARNING("Multiple handlers responded to binding input origin \"%s\"!", e.Origin.c_str());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,10 +146,10 @@ bool KeyboardInputHandler::OnKeyDown(const Events::KeyDown& e)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Events::InputCommand ic;
|
std::string command;
|
||||||
ic.PlayerID = 0;
|
float value;
|
||||||
std::tie(ic.Command, ic.Value) = it->second;
|
std::tie(command, value) = it->second;
|
||||||
m_InputProxy->Publish(ic);
|
m_CommandValues[command] += value;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -161,12 +161,21 @@ bool KeyboardInputHandler::OnKeyUp(const Events::KeyUp& e)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Events::InputCommand ic;
|
std::string command;
|
||||||
ic.PlayerID = 0;
|
float value;
|
||||||
std::tie(ic.Command, std::ignore) = it->second;
|
std::tie(command, value) = it->second;
|
||||||
ic.Value = 0;
|
m_CommandValues[command] -= value;
|
||||||
m_InputProxy->Publish(ic);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float KeyboardInputHandler::GetCommandValue(std::string command)
|
||||||
|
{
|
||||||
|
auto it = m_CommandValues.find(command);
|
||||||
|
if (it != m_CommandValues.end()) {
|
||||||
|
return m_CommandValues[command];
|
||||||
|
} else {
|
||||||
|
return 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user