Skip to content

Commit

Permalink
changed input logic, added controller support
Browse files Browse the repository at this point in the history
  • Loading branch information
RiverHillbug committed Mar 23, 2024
1 parent b80e438 commit 1ba73a7
Show file tree
Hide file tree
Showing 19 changed files with 480 additions and 127 deletions.
1 change: 1 addition & 0 deletions Minigin/BaseInputDevice.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "BaseInputDevice.h"
22 changes: 22 additions & 0 deletions Minigin/BaseInputDevice.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

enum class InputState : unsigned int
{
Pressed,
Released,
Previous
};

class BaseInputDevice
{
public:
virtual ~BaseInputDevice() = default;

virtual void Update() = 0;

virtual bool IsPressed(unsigned int) = 0;
virtual bool IsReleased(unsigned int) = 0;
virtual bool IsPrevious(unsigned int) = 0;

virtual void HandleInput() = 0;
};
2 changes: 1 addition & 1 deletion Minigin/Command.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ class Command
{
public:
virtual ~Command() = default;
virtual void Execute(class GameObject*, SDL_Scancode) {};
virtual void Execute() {};
};
85 changes: 85 additions & 0 deletions Minigin/Controller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Xinput.h>
#include "Controller.h"
#include "Command.h"

void Controller::Update()
{
XINPUT_STATE currentState{};
ZeroMemory(&currentState, sizeof(XINPUT_STATE));
DWORD dwResult = XInputGetState(m_ControllerIndex, &currentState);

if (dwResult != ERROR_SUCCESS)
{
ZeroMemory(&m_InputState, sizeof(XINPUT_STATE));
m_PreviousButtons = 0;
m_PressedButtons = 0;
m_ReleasedButtons = 0;
return;
}

const unsigned int buttonChanges = currentState.Gamepad.wButtons ^ m_PreviousButtons;
m_PressedButtons = buttonChanges & currentState.Gamepad.wButtons;
m_ReleasedButtons = buttonChanges & m_PreviousButtons;
m_PreviousButtons = currentState.Gamepad.wButtons;

CopyMemory(&m_InputState, &currentState, sizeof(XINPUT_STATE));
}

bool Controller::IsPressed(unsigned int button)
{
return m_PressedButtons & button;
}

bool Controller::IsReleased(unsigned int button)
{
return m_ReleasedButtons & button;
}

bool Controller::IsPrevious(unsigned int button)
{
return m_PreviousButtons & button;
}

void Controller::HandleInput()
{
for (const auto& binding : m_ButtonBindings)
{
switch (binding.first.inputState)
{
case InputState::Previous:
{
if (IsPrevious(unsigned int(binding.first.button)))
{
binding.second->Execute();
}

break;
}
case InputState::Pressed:
{
if (IsPressed(unsigned int(binding.first.button)))
{
binding.second->Execute();
}

break;
}
case InputState::Released:
{
if (IsReleased(unsigned int(binding.first.button)))
{
binding.second->Execute();
}
break;
}
}
}
}

void Controller::AddCommand(ControllerInput input, std::unique_ptr<class Command> command)
{
m_ButtonBindings.insert({ input, std::move(command) });
}
86 changes: 86 additions & 0 deletions Minigin/Controller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#pragma once
#include "BaseInputDevice.h"
#include <unordered_map>
#include <memory>
#include <sstream>
#include <type_traits>
#include <string>
#include <Xinput.h>

enum class Button : unsigned int
{
NONE = 0x0000,

XINPUT_CONTROLLER_A = 0x1000,
XINPUT_CONTROLLER_B = 0x2000,
XINPUT_CONTROLLER_X = 0x4000,
XINPUT_CONTROLLER_Y = 0x8000,

XINPUT_GAMEPAD_DRAD_UP = 0x0001,
XINPUT_GAMEPAD_DRAD_DOWN = 0x0002,
XINPUT_GAMEPAD_DRAD_LEFT = 0x0004,
XINPUT_GAMEPAD_DRAD_RIGHT = 0x0008
};

struct ControllerInput
{
Button button;
InputState inputState;

bool operator!=(const ControllerInput& other) const
{
return button != other.button ||
inputState != other.inputState;
}

bool operator==(const ControllerInput& other) const
{
return !(*this != other);
}
};

template <>
struct std::hash<ControllerInput>
{
auto operator()(const ControllerInput& input) const -> size_t
{
std::stringstream hashStr;
hashStr << unsigned int(input.button) << unsigned int(input.inputState);

return std::hash<std::string>()(hashStr.str());
}
};

class Controller final : public BaseInputDevice
{
public:
Controller() = default;
~Controller() = default;

Controller(const Controller& other) = delete;
Controller& operator=(const Controller& other) = delete;
Controller(Controller&& other) noexcept = delete;
Controller& operator=(Controller&& other) noexcept = delete;

void Update() override;

bool IsPressed(unsigned int button) override;
bool IsReleased(unsigned int button) override;
bool IsPrevious(unsigned int button) override;

void HandleInput() override;

void AddCommand(ControllerInput input, std::unique_ptr<class Command> command);

private:
int m_ControllerIndex;

XINPUT_STATE m_InputState{};

unsigned int m_PressedButtons;
unsigned int m_ReleasedButtons;
unsigned int m_PreviousButtons;

std::unordered_map<ControllerInput, std::unique_ptr<class Command>> m_ButtonBindings;
};

31 changes: 6 additions & 25 deletions Minigin/InputManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,8 @@
#include "InputManager.h"
#include "backends/imgui_impl_sdl2.h"

/*
#include "xinput.h"
#include "winbase.h"*/

dae::InputManager::~InputManager()
{
for (auto& item : m_MappedInputs)
{
delete item.second;
}
}

bool dae::InputManager::ProcessInput()
{
/*ZeroMemory(&m_CurrentState, sizeof(XINPUT_STATE));
XInputGetState(0, &m_CurrentState);*/

SDL_Event e;
while (SDL_PollEvent(&e))
{
Expand All @@ -27,18 +12,14 @@ bool dae::InputManager::ProcessInput()
return false;
}

const auto& command = m_MappedInputs.find(e.key.keysym.scancode);

if (command != m_MappedInputs.end())
command->second->Execute(m_pInputReceiver, command->first);
for (const auto& pDevice : m_InputDevices)
{
pDevice->Update();
pDevice->HandleInput();
}

ImGui_ImplSDL2_ProcessEvent(&e);
//ImGui_ImplSDL2_ProcessEvent(&e);
}

return true;
}

void dae::InputManager::MapInput(SDL_Scancode input, Command* pCommand)
{
m_MappedInputs[input] = pCommand;
}
34 changes: 29 additions & 5 deletions Minigin/InputManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,44 @@
#include "Singleton.h"
#include "MoveCommand.h"
#include <SDL.h>
#include <memory>
#include "BaseInputDevice.h"

namespace dae
{
enum class InputDeviceType
{
Controller,
Keyboard
};

class InputManager final : public Singleton<InputManager>
{
public:
~InputManager();
inline void SetInputReceiver(GameObject* pReceiver) { m_pInputReceiver = pReceiver; }
InputManager() = default;
~InputManager() = default;

InputManager(const InputManager& other) = delete;
InputManager& operator=(const InputManager& other) = delete;
InputManager(InputManager&& other) = delete;
InputManager& operator=(InputManager&& other) = delete;

template<typename T>
void AddDevice(std::unique_ptr<T> pDevice)
{
m_InputDevices.push_back(std::move(pDevice));
}

template<typename T>
void RemoveDevice(std::unique_ptr<T> pDevice)
{
m_InputDevices.erase(std::ranges::find(m_InputDevices, pDevice));
}

bool ProcessInput();
void MapInput(SDL_Scancode input, Command* pCommand);

private:
GameObject* m_pInputReceiver{ nullptr };
std::unordered_map<SDL_Scancode, Command*> m_MappedInputs{};
std::vector<std::unique_ptr<BaseInputDevice>> m_InputDevices{};
};

}
84 changes: 84 additions & 0 deletions Minigin/Keyboard.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include "Keyboard.h"
#include "Command.h"
#include <functional>
#include <algorithm>

void Keyboard::Update()
{
int keyCount{};
const auto currentKeyboardState = SDL_GetKeyboardState(&keyCount);

m_PreviousKeys.resize(keyCount);
m_PressedKeys.resize(keyCount);
m_ReleasedKeys.resize(keyCount);

std::vector<Uint8> currentPressedKeys{ currentKeyboardState, currentKeyboardState + keyCount };
std::vector<Uint8> difference(currentPressedKeys.size());

// gives us the difference in current and previous keyboard states
std::transform(currentPressedKeys.begin(), currentPressedKeys.end(), m_PreviousKeys.begin(), difference.begin(), std::bit_xor<Uint8>());

// finds which keys are pressed
std::transform(difference.begin(), difference.end(), currentPressedKeys.begin(), m_PressedKeys.begin(), std::bit_and<Uint8>());

// finds which keys were released
std::transform(difference.begin(), difference.end(), m_PreviousKeys.begin(), m_ReleasedKeys.begin(), std::bit_and<Uint8>());

m_PreviousKeys = std::move(currentPressedKeys);
}

bool Keyboard::IsPressed(unsigned int key)
{
return m_PressedKeys[key];
}

bool Keyboard::IsReleased(unsigned int key)
{
return m_ReleasedKeys[key];
}

bool Keyboard::IsPrevious(unsigned int key)
{
return m_PreviousKeys[key];
}

void Keyboard::HandleInput()
{
for (const auto& binding : m_KeyBindings)
{
switch (binding.first.inputState)
{
case InputState::Previous:
{
if (IsPrevious(binding.first.key))
{
binding.second->Execute();
}

break;
}
case InputState::Pressed:
{
if (IsPressed(binding.first.key))
{
binding.second->Execute();
}

break;
}
case InputState::Released:
{
if (IsReleased(binding.first.key))
{
binding.second->Execute();
}
break;
}
}
}
}

void Keyboard::AddCommand(KeyboardInput input, std::unique_ptr<class Command> command)
{
m_KeyBindings.insert({ input, std::move(command) });
}
Loading

0 comments on commit 1ba73a7

Please sign in to comment.