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/vector_utils.hpp
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
src/prototypes/physics_00.cpp)

View file

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

View file

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

View file

@ -25,6 +25,7 @@ public:
{}
TranslatedCoordinates coordinates;
bool isActive = true;
};
#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::Left] = HardDirection::LEFT;
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())
return HardDirection::NONE;

View file

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

View file

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

View file

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

View file

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

View file

@ -15,6 +15,11 @@ sf::Vector2f Player::getTrackableSize() const
void Player::update(Game *game)
{
if (!input->isActive) {
isActive = false;
return;
}
auto moveDirection = input->direction.asVector();
auto moveDelta = moveDirection * 30.0f * FRAME_TIME.asSeconds();
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 "logging/easylogging++.h"
#include "game/game_factory.hpp"
#include "debug/grid_debug_layer.h"
#include "game/world/world_view.h"
#include "game/player/player.hpp"
#include "game/player/player_spawner.hpp"
INITIALIZE_EASYLOGGINGPP
@ -14,12 +13,12 @@ int main(int argc, char *argv[])
auto game = GameFactory::createWindowed("Holesome");
auto player = new Player(sf::Color::Green, {0, 0});
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 PlayerSpawner());
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