Adds player spawner and greatly improves input identity handling

This commit is contained in:
Maximilian Giller 2023-05-20 00:10:03 +02:00
parent c3bc72fb4c
commit 875fab8c46
14 changed files with 1707 additions and 99 deletions

View file

@ -51,7 +51,10 @@ set(SOURCES
src/utilities/smart_list.h src/utilities/smart_list.h
src/utilities/vector_utils.hpp src/utilities/vector_utils.hpp
src/game/world/ITrackable.h src/game/world/ITrackable.h
src/game/input/input_identity.h) src/game/input/input_identity.h
src/utilities/magic_enum.hpp
src/game/player/player_spawner.cpp
src/game/player/player_spawner.hpp)
set(PHYSICS_00_SOURCES set(PHYSICS_00_SOURCES
src/prototypes/physics_00.cpp) src/prototypes/physics_00.cpp)

View file

@ -3,7 +3,6 @@
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <map> #include <map>
#include "game/input/"
#include "game/input/input_device_group.h" #include "game/input/input_device_group.h"
#define DEVELOPER_MODE true #define DEVELOPER_MODE true

View file

@ -48,9 +48,12 @@ void Game::drawFrame()
window->clear(sf::Color::Black); window->clear(sf::Color::Black);
for (auto &gameObject: gameObjects) for (auto &gameObject: gameObjects)
{
if (gameObject->isActive)
{ {
gameObject->draw(window.get()); gameObject->draw(window.get());
} }
}
window->display(); window->display();
} }
@ -64,29 +67,39 @@ void Game::update()
{ {
// Basic Updates // Basic Updates
for (auto &gameObject: gameObjects) for (auto &gameObject: gameObjects)
{
if (gameObject->isActive)
{ {
gameObject->update(this); gameObject->update(this);
} }
}
// Late updates // Late updates
for (auto &gameObject: gameObjects) for (auto &gameObject: gameObjects)
{
if (gameObject->isActive)
{ {
gameObject->lateUpdate(this); gameObject->lateUpdate(this);
} }
}
InputMapper::getInstance()->updateIdentityEvents();
} }
std::shared_ptr<Game> Game::getInstance() std::shared_ptr<Game> Game::getInstance()
{ {
if (singletonInstance == nullptr) { if (singletonInstance == nullptr)
{
throw std::runtime_error("Game instance has to be initialized first."); throw std::runtime_error("Game instance has to be initialized first.");
} }
return singletonInstance; return singletonInstance;
} }
std::shared_ptr<Game> Game::constructInstance(const std::shared_ptr<sf::RenderWindow>& window) std::shared_ptr<Game> Game::constructInstance(const std::shared_ptr<sf::RenderWindow> &window)
{ {
if (singletonInstance != nullptr) { if (singletonInstance != nullptr)
{
throw std::runtime_error("Game instance has already been initialized."); throw std::runtime_error("Game instance has already been initialized.");
} }

View file

@ -25,6 +25,7 @@ public:
{} {}
TranslatedCoordinates coordinates; TranslatedCoordinates coordinates;
bool isActive = true;
}; };
#endif //HOLESOME_GAME_OBJECT_H #endif //HOLESOME_GAME_OBJECT_H

View file

@ -14,6 +14,10 @@ HardDirection Direction::getKeyDirection(sf::Keyboard::Key key)
map[sf::Keyboard::Down] = HardDirection::DOWN; map[sf::Keyboard::Down] = HardDirection::DOWN;
map[sf::Keyboard::Left] = HardDirection::LEFT; map[sf::Keyboard::Left] = HardDirection::LEFT;
map[sf::Keyboard::Right] = HardDirection::RIGHT; map[sf::Keyboard::Right] = HardDirection::RIGHT;
map[sf::Keyboard::I] = HardDirection::UP;
map[sf::Keyboard::K] = HardDirection::DOWN;
map[sf::Keyboard::J] = HardDirection::LEFT;
map[sf::Keyboard::L] = HardDirection::RIGHT;
if (map.find(key) == map.end()) if (map.find(key) == map.end())
return HardDirection::NONE; return HardDirection::NONE;

View file

@ -4,20 +4,23 @@
#include <set> #include <set>
#include "direction.h" #include "direction.h"
#include "input_device_group.h" #include "input_device_group.h"
#include "key_features.hpp"
#include "../../utilities/magic_enum.hpp"
struct InputIdentity struct InputIdentity
{ {
Direction direction = Direction(); Direction direction = Direction();
InputDeviceGroup deviceType = InputDeviceGroup::UNKNOWN; InputDeviceGroup deviceGroup = InputDeviceGroup::UNKNOWN;
unsigned int gamepadId = 0; unsigned int gamepadId = 0;
unsigned int inputOrder = 0;
bool isActive = true; bool isActive = true;
explicit InputIdentity(InputDeviceGroup type, unsigned int gamepad = 0) explicit InputIdentity(InputDeviceGroup type, unsigned int gamepad = 0)
{ {
deviceType = type; deviceGroup = type;
gamepadId = gamepad; gamepadId = gamepad;
LOG(INFO) << "Created input identity [" << magic_enum::enum_name(type) << ", gamepad " << gamepadId << "]";
}; };
static InputDeviceGroup getDeviceTypeFromEvent(sf::Event event) static InputDeviceGroup getDeviceTypeFromEvent(sf::Event event)
@ -26,13 +29,7 @@ struct InputIdentity
{ {
case sf::Event::KeyPressed: case sf::Event::KeyPressed:
case sf::Event::KeyReleased: case sf::Event::KeyReleased:
if (wasd_keys.contains(event.key.code)) return KeyFeatures(event.key.code).deviceGroup;
{
return InputDeviceGroup::KEYBOARD_WASD;
} else
{
return InputDeviceGroup::KEYBOARD_ARROWS;
}
case sf::Event::JoystickButtonPressed: case sf::Event::JoystickButtonPressed:
case sf::Event::JoystickButtonReleased: case sf::Event::JoystickButtonReleased:
case sf::Event::JoystickConnected: case sf::Event::JoystickConnected:

View file

@ -4,10 +4,9 @@
InputMapper::InputMapper() InputMapper::InputMapper()
{ {
// Initialize identities inputIdentities = std::set<std::shared_ptr<InputIdentity>>();
allIdentity = std::make_shared<InputIdentity>(InputDeviceGroup::ALL); newInputIdentities = std::set<std::shared_ptr<InputIdentity>>();
keyboardIdentity = std::make_shared<InputIdentity>(InputDeviceGroup::KEYBOARD); deprecatedInputIdentities = std::set<std::shared_ptr<InputIdentity>>();
gamepadIdentities = std::map<unsigned int, std::shared_ptr<InputIdentity>>();
} }
@ -33,10 +32,10 @@ void InputMapper::processEvents()
handleJoystickMovement(event.joystickMove); handleJoystickMovement(event.joystickMove);
break; break;
case sf::Event::JoystickConnected: case sf::Event::JoystickConnected:
addGamepadIdentity(event.joystickConnect.joystickId); getInputIdentity(InputDeviceGroup::GAMEPAD, event.joystickConnect.joystickId);
break; break;
case sf::Event::JoystickDisconnected: case sf::Event::JoystickDisconnected:
deactivateGamepadIdentity(event.joystickConnect.joystickId); deactivateIdentity(getInputIdentity(InputDeviceGroup::GAMEPAD, event.joystickConnect.joystickId));
break; break;
default: default:
break; break;
@ -54,20 +53,21 @@ void InputMapper::handleKeyPress(sf::Event::KeyEvent event)
} }
// Handle directionVector // Handle directionVector
auto direction = Direction::getKeyDirection(event.code); auto feature = KeyFeatures(event.code);
if (direction != HardDirection::NONE) if (feature.deviceGroup != InputDeviceGroup::UNKNOWN)
{ {
getInputIdentity(InputDeviceGroup::KEYBOARD)->direction.add(direction); getInputIdentity(feature.deviceGroup)->direction.add(feature.hardDirection);
return;
} }
} }
void InputMapper::handleKeyRelease(sf::Event::KeyEvent event) void InputMapper::handleKeyRelease(sf::Event::KeyEvent event)
{ {
// Handle directionVector auto feature = KeyFeatures(event.code);
auto direction = Direction::getKeyDirection(event.code); if (feature.deviceGroup != InputDeviceGroup::UNKNOWN)
if (direction != HardDirection::NONE)
{ {
getInputIdentity(InputDeviceGroup::KEYBOARD)->direction.remove(direction); getInputIdentity(feature.deviceGroup)->direction.remove(feature.hardDirection);
return;
} }
} }
@ -94,43 +94,40 @@ void InputMapper::handleJoystickMovement(sf::Event::JoystickMoveEvent event)
} }
} }
std::shared_ptr<InputIdentity> InputMapper::getInputIdentity(InputDeviceGroup deviceType, unsigned int gamepadId) std::shared_ptr<InputIdentity> InputMapper::getInputIdentity(InputDeviceGroup deviceGroup, unsigned int gamepadId)
{ {
switch (deviceType) if (deviceGroup == InputDeviceGroup::UNKNOWN)
{ {
case InputDeviceGroup::KEYBOARD: throw std::invalid_argument("InputDeviceGroup cannot be UNKNOWN");
return keyboardIdentity; }
case InputDeviceGroup::GAMEPAD:
if (!gamepadIdentities.contains(gamepadId)) for (auto &identity: inputIdentities)
{ {
// Create if it does not exist yet // Device group must be matched, and gamepad id if it is a gamepad
addGamepadIdentity(gamepadId); if (identity->deviceGroup == deviceGroup &&
(deviceGroup != InputDeviceGroup::GAMEPAD ||
identity->gamepadId == gamepadId))
{
return identity;
} }
return gamepadIdentities[gamepadId];
default:
return allIdentity;
} }
// No identity found, create new
auto newIdentity = std::make_shared<InputIdentity>(deviceGroup, gamepadId);
inputIdentities.insert(newIdentity);
newInputIdentities.insert(newIdentity);
return newIdentity;
} }
void InputMapper::addGamepadIdentity(unsigned int gamepadId) void InputMapper::deactivateIdentity(const std::shared_ptr<InputIdentity> &identity)
{ {
// Exists already? LOG(INFO) << "Destroyed input identity [" << magic_enum::enum_name(identity->deviceGroup) << ", gamepad "
if (gamepadIdentities.contains(gamepadId)) << identity->gamepadId
{ << "]";
gamepadIdentities[gamepadId]->isActive = true;
return;
}
// Does not exist yet, create new
auto newIdentity = std::make_shared<InputIdentity>(InputDeviceGroup::GAMEPAD, gamepadId);
gamepadIdentities[gamepadId] = newIdentity;
}
void InputMapper::deactivateGamepadIdentity(unsigned int gamepadId)
{
auto gamepadIdentity = getInputIdentity(InputDeviceGroup::GAMEPAD, gamepadId);
gamepadIdentity->isActive = false;
identity->isActive = false;
deprecatedInputIdentities.insert(identity);
inputIdentities.erase(identity);
} }
std::shared_ptr<InputMapper> InputMapper::getInstance() std::shared_ptr<InputMapper> InputMapper::getInstance()
@ -143,17 +140,13 @@ std::shared_ptr<InputMapper> InputMapper::getInstance()
return singletonInstance; return singletonInstance;
} }
std::vector<std::shared_ptr<InputIdentity>> InputMapper::getAllInputIdentities() std::set<std::shared_ptr<InputIdentity>> InputMapper::getInputIdentities()
{ {
std::vector<std::shared_ptr<InputIdentity>> allIdentities; return inputIdentities;
}
allIdentities.push_back(allIdentity);
allIdentities.push_back(keyboardIdentity); void InputMapper::updateIdentityEvents()
{
for (auto const &[key, val]: gamepadIdentities) newInputIdentities.clear();
{ deprecatedInputIdentities.clear();
allIdentities.push_back(val);
}
return allIdentities;
} }

View file

@ -19,15 +19,20 @@ public:
static std::shared_ptr<InputMapper> getInstance(); static std::shared_ptr<InputMapper> getInstance();
void processEvents(); void processEvents();
void updateIdentityEvents();
std::shared_ptr<InputIdentity> getInputIdentity(InputDeviceGroup deviceType, unsigned int gamepadId = 0); std::shared_ptr<InputIdentity> getInputIdentity(InputDeviceGroup deviceGroup, unsigned int gamepadId = 0);
std::vector<std::shared_ptr<InputIdentity>> getAllInputIdentities();
std::set<std::shared_ptr<InputIdentity>> getInputIdentities();
public:
std::set<std::shared_ptr<InputIdentity>> newInputIdentities;
std::set<std::shared_ptr<InputIdentity>> deprecatedInputIdentities;
private: private:
static inline std::shared_ptr<InputMapper> singletonInstance = nullptr; static inline std::shared_ptr<InputMapper> singletonInstance = nullptr;
std::shared_ptr<InputIdentity> keyboardIdentity; std::set<std::shared_ptr<InputIdentity>> inputIdentities;
std::map<unsigned int, std::shared_ptr<InputIdentity>> gamepadIdentities;
void handleKeyPress(sf::Event::KeyEvent event); void handleKeyPress(sf::Event::KeyEvent event);
@ -35,9 +40,7 @@ private:
void handleJoystickMovement(sf::Event::JoystickMoveEvent event); void handleJoystickMovement(sf::Event::JoystickMoveEvent event);
void addGamepadIdentity(unsigned int gamepadId); void deactivateIdentity(const std::shared_ptr<InputIdentity>& identity);
void deactivateGamepadIdentity(unsigned int gamepadId);
}; };

View file

@ -2,6 +2,7 @@
#define HOLESOME_KEY_FEATURES_HPP #define HOLESOME_KEY_FEATURES_HPP
#include <memory>
#include "direction.h" #include "direction.h"
#include "input_identity.h" #include "input_identity.h"
#include "../../config.h" #include "../../config.h"
@ -13,16 +14,13 @@ struct KeyFeatures
HardDirection hardDirection = HardDirection::NONE; HardDirection hardDirection = HardDirection::NONE;
InputDeviceGroup deviceGroup = InputDeviceGroup::UNKNOWN; InputDeviceGroup deviceGroup = InputDeviceGroup::UNKNOWN;
explicit KeyFeatures(sf::Keyboard::Key key); explicit KeyFeatures(sf::Keyboard::Key key)
}; {
KeyFeatures::KeyFeatures(sf::Keyboard::Key key)
{
this->key = key; this->key = key;
hardDirection = Direction::getKeyDirection(key); hardDirection = Direction::getKeyDirection(key);
// Determine device group // Determine device group
for (const auto& groupKeys: KEY_GROUPS) for (const auto &groupKeys: KEY_GROUPS)
{ {
if (groupKeys.second.contains(key)) if (groupKeys.second.contains(key))
{ {
@ -30,6 +28,7 @@ KeyFeatures::KeyFeatures(sf::Keyboard::Key key)
break; break;
} }
} }
} }
};
#endif //HOLESOME_KEY_FEATURES_HPP #endif //HOLESOME_KEY_FEATURES_HPP

View file

@ -15,6 +15,11 @@ sf::Vector2f Player::getTrackableSize() const
void Player::update(Game *game) void Player::update(Game *game)
{ {
if (!input->isActive) {
isActive = false;
return;
}
auto moveDirection = input->direction.asVector(); auto moveDirection = input->direction.asVector();
auto moveDelta = moveDirection * 30.0f * FRAME_TIME.asSeconds(); auto moveDelta = moveDirection * 30.0f * FRAME_TIME.asSeconds();
coordinates.move(moveDelta); coordinates.move(moveDelta);

View file

@ -0,0 +1,12 @@
#include "player_spawner.hpp"
#include "player.hpp"
void PlayerSpawner::update(Game *game)
{
// Create player for new input identities
for (auto &inputIdentity: InputMapper::getInstance()->newInputIdentities)
{
auto player = new Player(inputIdentity, sf::Color::Red, {0, 0});
game->addGameObject(player);
}
}

View file

@ -0,0 +1,14 @@
#ifndef HOLESOME_PLAYER_SPAWNER_HPP
#define HOLESOME_PLAYER_SPAWNER_HPP
#include "../game_object.h"
class PlayerSpawner : public GameObject
{
public:
void update(Game *game) override;
};
#endif //HOLESOME_PLAYER_SPAWNER_HPP

View file

@ -1,10 +1,9 @@
#include <SFML/Graphics.hpp>
#include <iostream> #include <iostream>
#include "logging/easylogging++.h" #include "logging/easylogging++.h"
#include "game/game_factory.hpp" #include "game/game_factory.hpp"
#include "debug/grid_debug_layer.h" #include "debug/grid_debug_layer.h"
#include "game/world/world_view.h" #include "game/world/world_view.h"
#include "game/player/player.hpp" #include "game/player/player_spawner.hpp"
INITIALIZE_EASYLOGGINGPP INITIALIZE_EASYLOGGINGPP
@ -14,12 +13,12 @@ int main(int argc, char *argv[])
auto game = GameFactory::createWindowed("Holesome"); auto game = GameFactory::createWindowed("Holesome");
auto player = new Player(sf::Color::Green, {0, 0});
game->addGameObject(new GridDebugLayer(0, 50, 0, 50)); game->addGameObject(new GridDebugLayer(0, 50, 0, 50));
game->addGameObject(player);
game->addGameObject(new Player(sf::Color::Blue, {0, 0}));
game->addGameObject(new WorldView()); game->addGameObject(new WorldView());
game->addGameObject(new PlayerSpawner());
game->run(); game->run();
InputMapper::getInstance().reset();
game.reset();
} }

1566
src/utilities/magic_enum.hpp Normal file

File diff suppressed because it is too large Load diff