Overhauled input system to support Game actions for buttons. Linked box2d as well

This commit is contained in:
Maximilian Giller 2023-06-08 00:54:01 +02:00
parent 68f2e407f1
commit d2a06324c9
20 changed files with 304 additions and 160 deletions

View file

@ -11,9 +11,9 @@ include_directories(${SFML_INCLUDE_DIR})
find_package(Eigen3 3.3 REQUIRED NO_MODULE)
include_directories(${EIGEN3_INCLUDE_DIR})
# Find and include Box2D
#find_package(Box2D REQUIRED)
# Include Box2D
find_package(box2d REQUIRED)
include_directories(${BOX2D_INCLUDE_DIR})
# Set up your project's source files
set(SOURCES
@ -44,7 +44,6 @@ set(SOURCES
src/game/input/direction.cpp
src/game/player/player.cpp
src/game/player/player.hpp
src/game/input/key_features.hpp
src/game/camera/tracking_view.cpp
src/game/camera/tracking_view.h
src/utilities/smart_list.cpp
@ -58,7 +57,7 @@ set(SOURCES
src/game/camera/tracking_area.h
src/game/camera/tracking_view_options.hpp
src/game/collectables/environment_collectable.cpp
src/game/collectables/environment_collectable.hpp src/sprites/texture_manager.cpp src/sprites/texture_manager.hpp src/sprites/sprite_sheet.cpp src/sprites/sprite_sheet.hpp src/sprites/animated_sprite.cpp src/sprites/animated_sprite.hpp src/sprites/single_sprite.cpp src/sprites/single_sprite.hpp src/texture_config.h src/sprites/configs/sprite_config.hpp src/sprites/configs/sheet_config.hpp src/sprites/configs/animation_config.hpp src/sprites/versatile_sprite.cpp src/sprites/versatile_sprite.hpp src/sprites/sprite.hpp src/sprites/sprite_factory.cpp src/sprites/sprite_factory.hpp)
src/game/collectables/environment_collectable.hpp src/sprites/texture_manager.cpp src/sprites/texture_manager.hpp src/sprites/sprite_sheet.cpp src/sprites/sprite_sheet.hpp src/sprites/animated_sprite.cpp src/sprites/animated_sprite.hpp src/sprites/single_sprite.cpp src/sprites/single_sprite.hpp src/texture_config.h src/sprites/configs/sprite_config.hpp src/sprites/configs/sheet_config.hpp src/sprites/configs/animation_config.hpp src/sprites/versatile_sprite.cpp src/sprites/versatile_sprite.hpp src/sprites/sprite.hpp src/sprites/sprite_factory.cpp src/sprites/sprite_factory.hpp src/input_config.h src/game/input/button_config.hpp src/game/input/game_action.hpp src/game/input/button_config_factory.cpp src/game/input/button_config_factory.hpp src/game/input/game_action_config.hpp src/game/input/gamepad_buttons.hpp)
set(PHYSICS_00_SOURCES
src/prototypes/physics_00.cpp)
@ -75,9 +74,9 @@ add_executable(Math_00 ${MATH_00_SOURCES})
# Link SFML and other libraries to your executable target
target_link_libraries(Holesome sfml-graphics sfml-audio)
target_link_libraries(Holesome Eigen3::Eigen)
#target_link_libraries(Holesome Box2D::Box2D)
target_link_libraries(Holesome box2d::box2d)
#target_link_libraries(Physics_00 Box2D::Box2D)
target_link_libraries(Physics_00 box2d::box2d)
target_link_libraries(Math_00 Eigen3::Eigen)

View file

@ -1,3 +1,3 @@
# Holesome - ToDos
- [ ] Link box2d???
- [ ] Try button mapping for other controllers

View file

@ -2,8 +2,6 @@
#define HOLESOME_CONFIG_H
#include <SFML/Graphics.hpp>
#include <map>
#include "game/input/input_device_group.h"
#define DEVELOPER_MODE true
@ -29,44 +27,6 @@
#define DEF_TV_MAX_VIEW_SIZE sf::Vector2f(0, 0)
#define DEF_TV_VIEW_SIZE_PADDING sf::Vector2f(0.5f, 0.5f)
// Inputs
#define JOYSTICK_DEADZONE 0.1f
// Key groups
const std::map<InputDeviceGroup, std::set<sf::Keyboard::Key>> KEY_GROUPS = {
{InputDeviceGroup::KEYBOARD_WASD,
{
sf::Keyboard::W,
sf::Keyboard::A,
sf::Keyboard::S,
sf::Keyboard::D,
sf::Keyboard::Q,
sf::Keyboard::E
}
},
{InputDeviceGroup::KEYBOARD_ARROWS,
{
sf::Keyboard::Up,
sf::Keyboard::Left,
sf::Keyboard::Down,
sf::Keyboard::Right,
sf::Keyboard::RShift,
sf::Keyboard::PageDown,
sf::Keyboard::PageUp,
sf::Keyboard::RControl,
}
},
{InputDeviceGroup::KEYBOARD_IJKL,
{
sf::Keyboard::I,
sf::Keyboard::J,
sf::Keyboard::K,
sf::Keyboard::L,
sf::Keyboard::U,
sf::Keyboard::O
}
}
};
// Directions
#define DIRECTION_HARD_ACTIVATION_THRESHOLD 0.1f

View file

@ -84,7 +84,7 @@ void Game::update()
}
}
InputMapper::getInstance()->updateIdentityEvents();
InputMapper::getInstance()->updateIdentities();
}
std::shared_ptr<Game> Game::getInstance()

View file

@ -0,0 +1,37 @@
#ifndef HOLESOME_BUTTON_CONFIG_HPP
#define HOLESOME_BUTTON_CONFIG_HPP
#include <vector>
#include "game_action.hpp"
#include "input_device_group.h"
#include "direction.h"
struct ButtonConfig {
std::vector<GameAction> actions;
InputDeviceGroup deviceGroup;
HardDirection direction;
bool isValid;
ButtonConfig(InputDeviceGroup group, std::vector<GameAction> actions, HardDirection direction = HardDirection::NONE) :
actions(std::move(actions)),
deviceGroup(group),
direction(direction),
isValid(true)
{}
ButtonConfig(InputDeviceGroup group, HardDirection direction) :
actions({}),
deviceGroup(group),
direction(direction),
isValid(true)
{}
ButtonConfig() :
actions({}),
deviceGroup(InputDeviceGroup::UNKNOWN),
direction(HardDirection::NONE),
isValid(false)
{}
};
#endif //HOLESOME_BUTTON_CONFIG_HPP

View file

@ -0,0 +1,22 @@
#include "button_config_factory.hpp"
#include "../../input_config.h"
ButtonConfig ButtonConfigFactory::fromKey(sf::Keyboard::Key key)
{
if (KEY_CONFIGS.find(key) != KEY_CONFIGS.end())
{
return KEY_CONFIGS.at(key);
}
return {};
}
ButtonConfig ButtonConfigFactory::fromGamepadButton(int button)
{
if (GAMEPAD_BUTTON_CONFIGS.find(button) != GAMEPAD_BUTTON_CONFIGS.end())
{
return GAMEPAD_BUTTON_CONFIGS.at(button);
}
return {};
}

View file

@ -0,0 +1,17 @@
#ifndef HOLESOME_BUTTON_CONFIG_FACTORY_HPP
#define HOLESOME_BUTTON_CONFIG_FACTORY_HPP
#include <SFML/Window/Keyboard.hpp>
#include "button_config.hpp"
class ButtonConfigFactory
{
public:
static ButtonConfig fromKey(sf::Keyboard::Key key);
static ButtonConfig fromGamepadButton(int button);
};
#endif //HOLESOME_BUTTON_CONFIG_FACTORY_HPP

View file

@ -3,28 +3,6 @@
#include "../../utilities/vector_utils.hpp"
#include "../../config.h"
HardDirection Direction::getKeyDirection(sf::Keyboard::Key key)
{
auto map = std::map<sf::Keyboard::Key, HardDirection>();
map[sf::Keyboard::W] = HardDirection::UP;
map[sf::Keyboard::S] = HardDirection::DOWN;
map[sf::Keyboard::A] = HardDirection::LEFT;
map[sf::Keyboard::D] = HardDirection::RIGHT;
map[sf::Keyboard::Up] = HardDirection::UP;
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;
return map[key];
}
sf::Vector2f Direction::getScreenVector(HardDirection direction)
{
auto vector = getVector(direction);

View file

@ -22,8 +22,6 @@ public:
explicit Direction(HardDirection direction);
static HardDirection getKeyDirection(sf::Keyboard::Key key);
static sf::Vector2f getVector(HardDirection direction);
static sf::Vector2f getScreenVector(HardDirection direction);

View file

@ -0,0 +1,13 @@
#ifndef HOLESOME_GAME_ACTION_HPP
#define HOLESOME_GAME_ACTION_HPP
enum GameAction
{
CONFIRM,
CANCEL,
MENU,
JUMP
};
#endif //HOLESOME_GAME_ACTION_HPP

View file

@ -0,0 +1,19 @@
#ifndef HOLESOME_GAME_ACTION_CONFIG_HPP
#define HOLESOME_GAME_ACTION_CONFIG_HPP
enum InteractionMode
{
PRESS,
HOLD
};
struct GameActionConfig
{
InteractionMode mode;
GameActionConfig(InteractionMode mode) :
mode(mode)
{}
};
#endif //HOLESOME_GAME_ACTION_CONFIG_HPP

View file

@ -0,0 +1,23 @@
#ifndef HOLESOME_GAMEPAD_BUTTONS_HPP
#define HOLESOME_GAMEPAD_BUTTONS_HPP
enum GamepadButton {
SOUTH = 0,
EAST = 1,
NORTH = 2,
WEST = 3,
LEFT_SHOULDER = 4,
RIGHT_SHOULDER = 5,
LEFT_TRIGGER = 6,
RIGHT_TRIGGER = 7,
SELECT = 8,
START = 9,
HOME = 10,
LEFT_STICK = 11,
RIGHT_STICK = 12
};
#endif //HOLESOME_GAMEPAD_BUTTONS_HPP

View file

@ -1,7 +1,6 @@
#ifndef HOLESOME_INPUT_DEVICE_GROUP_H
#define HOLESOME_INPUT_DEVICE_GROUP_H
#include "direction.h"
#include <set>
enum InputDeviceGroup

View file

@ -4,14 +4,18 @@
#include <set>
#include "direction.h"
#include "input_device_group.h"
#include "key_features.hpp"
#include "../../utilities/magic_enum.hpp"
#include "../../logging/easylogging++.h"
#include "../../input_config.h"
#include <SFML/Window/Joystick.hpp>
struct InputIdentity
{
std::set<GameAction> current_actions = {};
std::set<GameAction> previous_actions = {};
Direction direction = Direction();
InputDeviceGroup deviceGroup = InputDeviceGroup::UNKNOWN;
unsigned int gamepadId = 0;
bool isActive = true;
@ -22,25 +26,56 @@ struct InputIdentity
gamepadId = gamepad;
LOG(INFO) << "Created input identity [" << magic_enum::enum_name(type) << ", gamepad " << gamepadId << "]";
if (type == InputDeviceGroup::GAMEPAD)
{
auto numberOfButtons = sf::Joystick::getButtonCount(gamepadId);
LOG(INFO) << "Gamepad has " << numberOfButtons << " buttons";
}
};
static InputDeviceGroup getDeviceTypeFromEvent(sf::Event event)
bool isPerformingAction(GameAction action)
{
switch (event.type)
bool currently_performing = current_actions.find(action) != current_actions.end();
bool previously_performing = previous_actions.find(action) != previous_actions.end();
auto action_config = GAME_ACTION_CONFIGS.at(action);
if (action_config.mode == InteractionMode::PRESS)
{
case sf::Event::KeyPressed:
case sf::Event::KeyReleased:
return KeyFeatures(event.key.code).deviceGroup;
case sf::Event::JoystickButtonPressed:
case sf::Event::JoystickButtonReleased:
case sf::Event::JoystickConnected:
case sf::Event::JoystickDisconnected:
case sf::Event::JoystickMoved:
return InputDeviceGroup::GAMEPAD;
default:
return InputDeviceGroup::UNKNOWN;
return currently_performing && !previously_performing;
} else if (action_config.mode == InteractionMode::HOLD)
{
return currently_performing;
} else
{
LOG(ERROR) << "Unknown interaction mode [" << magic_enum::enum_name(action_config.mode) << "]";
return false;
}
}
void press(const ButtonConfig &button)
{
for (auto &action: button.actions)
{
current_actions.insert(action);
}
direction.add(button.direction);
}
void release(const ButtonConfig &button)
{
for (auto &action: button.actions)
{
current_actions.erase(action);
}
direction.remove(button.direction);
}
void update()
{
previous_actions = current_actions;
}
};

View file

@ -1,5 +1,6 @@
#include "input_mapper.h"
#include "input_device_group.h"
#include "button_config_factory.hpp"
InputMapper::InputMapper()
@ -26,7 +27,13 @@ void InputMapper::processEvents()
case sf::Event::Closed:
Game::getInstance()->exit();
break;
case sf::Event::Resized:
case sf::Event::JoystickButtonPressed:
getInputIdentity(InputDeviceGroup::GAMEPAD, event.joystickButton.joystickId)->press(
ButtonConfigFactory::fromGamepadButton(event.joystickButton.button));
break;
case sf::Event::JoystickButtonReleased:
getInputIdentity(InputDeviceGroup::GAMEPAD, event.joystickButton.joystickId)->release(
ButtonConfigFactory::fromGamepadButton(event.joystickButton.button));
break;
case sf::Event::JoystickMoved:
handleJoystickMovement(event.joystickMove);
@ -46,27 +53,27 @@ void InputMapper::processEvents()
void InputMapper::handleKeyPress(sf::Event::KeyEvent event)
{
// Close game on Escape or Q in DEV Mode
if (DEVELOPER_MODE && (event.code == sf::Keyboard::Escape || event.code == sf::Keyboard::Q))
if (DEVELOPER_MODE && event.code == sf::Keyboard::Escape)
{
Game::getInstance()->exit();
return;
}
// Handle directionVector
auto feature = KeyFeatures(event.code);
if (feature.deviceGroup != InputDeviceGroup::UNKNOWN)
auto button = ButtonConfigFactory::fromKey(event.code);
if (button.deviceGroup != InputDeviceGroup::UNKNOWN)
{
getInputIdentity(feature.deviceGroup)->direction.add(feature.hardDirection);
getInputIdentity(button.deviceGroup)->press(button);
return;
}
}
void InputMapper::handleKeyRelease(sf::Event::KeyEvent event)
{
auto feature = KeyFeatures(event.code);
if (feature.deviceGroup != InputDeviceGroup::UNKNOWN)
auto button = ButtonConfigFactory::fromKey(event.code);
if (button.deviceGroup != InputDeviceGroup::UNKNOWN)
{
getInputIdentity(feature.deviceGroup)->direction.remove(feature.hardDirection);
getInputIdentity(button.deviceGroup)->release(button);
return;
}
}
@ -75,7 +82,7 @@ void InputMapper::handleJoystickMovement(sf::Event::JoystickMoveEvent event)
{
auto gamepadIdentity = getInputIdentity(InputDeviceGroup::GAMEPAD, event.joystickId);
auto value = event.position / 100.f;
auto value = event.position / 100.f; // Normalize to -1 to 1
auto axis = event.axis;
// Handle deadzone and joystick drift
@ -145,8 +152,13 @@ std::set<std::shared_ptr<InputIdentity>> InputMapper::getInputIdentities()
return inputIdentities;
}
void InputMapper::updateIdentityEvents()
void InputMapper::updateIdentities()
{
for (auto &identity: inputIdentities)
{
identity->update();
}
newInputIdentities.clear();
deprecatedInputIdentities.clear();
}

View file

@ -19,7 +19,7 @@ public:
static std::shared_ptr<InputMapper> getInstance();
void processEvents();
void updateIdentityEvents();
void updateIdentities();
std::shared_ptr<InputIdentity> getInputIdentity(InputDeviceGroup deviceGroup, unsigned int gamepadId = 0);

View file

@ -1,34 +0,0 @@
#ifndef HOLESOME_KEY_FEATURES_HPP
#define HOLESOME_KEY_FEATURES_HPP
#include <memory>
#include "direction.h"
#include "input_identity.h"
#include "../../config.h"
#include "input_device_group.h"
struct KeyFeatures
{
sf::Keyboard::Key key;
HardDirection hardDirection = HardDirection::NONE;
InputDeviceGroup deviceGroup = InputDeviceGroup::UNKNOWN;
explicit KeyFeatures(sf::Keyboard::Key key)
{
this->key = key;
hardDirection = Direction::getKeyDirection(key);
// Determine device group
for (const auto &groupKeys: KEY_GROUPS)
{
if (groupKeys.second.contains(key))
{
deviceGroup = groupKeys.first;
break;
}
}
}
};
#endif //HOLESOME_KEY_FEATURES_HPP

View file

@ -1,4 +1,5 @@
#include "player.hpp"
#include "../../config.h"
#include <utility>
@ -35,6 +36,11 @@ void Player::update()
auto moveDelta = moveDirection * speed * FRAME_TIME.asSeconds();
coordinates->move(moveDelta);
if (input->isPerformingAction(GameAction::JUMP))
{
coordinates->move({0, 0, 10});
}
GameObject::update();
}

47
src/input_config.h Normal file
View file

@ -0,0 +1,47 @@
#ifndef HOLESOME_INPUT_CONFIG_H
#define HOLESOME_INPUT_CONFIG_H
#include <map>
#include "game/input/input_device_group.h"
#include "game/input/button_config.hpp"
#include "game/input/game_action_config.hpp"
#include "game/input/gamepad_buttons.hpp"
#define JOYSTICK_DEADZONE 0.1f
// Keys
const std::map<sf::Keyboard::Key, ButtonConfig> KEY_CONFIGS = {
{sf::Keyboard::Up, ButtonConfig(InputDeviceGroup::KEYBOARD_ARROWS, HardDirection::UP)},
{sf::Keyboard::Down, ButtonConfig(InputDeviceGroup::KEYBOARD_ARROWS, HardDirection::DOWN)},
{sf::Keyboard::Left, ButtonConfig(InputDeviceGroup::KEYBOARD_ARROWS, HardDirection::LEFT)},
{sf::Keyboard::Right, ButtonConfig(InputDeviceGroup::KEYBOARD_ARROWS, HardDirection::RIGHT)},
{sf::Keyboard::RControl, ButtonConfig(InputDeviceGroup::KEYBOARD_ARROWS, {GameAction::JUMP})},
{sf::Keyboard::W, ButtonConfig(InputDeviceGroup::KEYBOARD_WASD, HardDirection::UP)},
{sf::Keyboard::S, ButtonConfig(InputDeviceGroup::KEYBOARD_WASD, HardDirection::DOWN)},
{sf::Keyboard::A, ButtonConfig(InputDeviceGroup::KEYBOARD_WASD, HardDirection::LEFT)},
{sf::Keyboard::D, ButtonConfig(InputDeviceGroup::KEYBOARD_WASD, HardDirection::RIGHT)},
{sf::Keyboard::Space, ButtonConfig(InputDeviceGroup::KEYBOARD_WASD, {GameAction::JUMP})},
{sf::Keyboard::I, ButtonConfig(InputDeviceGroup::KEYBOARD_IJKL, HardDirection::UP)},
{sf::Keyboard::K, ButtonConfig(InputDeviceGroup::KEYBOARD_IJKL, HardDirection::DOWN)},
{sf::Keyboard::J, ButtonConfig(InputDeviceGroup::KEYBOARD_IJKL, HardDirection::LEFT)},
{sf::Keyboard::L, ButtonConfig(InputDeviceGroup::KEYBOARD_IJKL, HardDirection::RIGHT)},
{sf::Keyboard::B, ButtonConfig(InputDeviceGroup::KEYBOARD_IJKL, {GameAction::JUMP})}
};
// Gamepad buttons
const std::map<int, ButtonConfig> GAMEPAD_BUTTON_CONFIGS = {
{20, ButtonConfig(InputDeviceGroup::GAMEPAD, {GameAction::JUMP})}
};
// Actions
const std::map<GameAction, GameActionConfig> GAME_ACTION_CONFIGS = {
{GameAction::JUMP, GameActionConfig(InteractionMode::PRESS)}
};
#endif //HOLESOME_INPUT_CONFIG_H

View file

@ -1,42 +1,55 @@
#include <reactphysics3d/reactphysics3d.h>
#include <iostream>
#include <box2d/box2d.h>
// ReactPhysics3D namespace
using namespace reactphysics3d;
// Main function
int main(int argc, char** argv) {
// Create the world
b2Vec2 gravity(0.0f, -10.0f);
b2World world = b2World(gravity);
// First you need to create the PhysicsCommon object.
// This is a factory module that you can use to create physics
// camera and other objects. It is also responsible for
// logging and memory management
PhysicsCommon physicsCommon;
// Define ground
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0.0f, -10.0f);
b2Body* groundBody = world.CreateBody(&groundBodyDef);
// Create a physics camera
PhysicsWorld* world = physicsCommon.createPhysicsWorld();
// Define ground shape
b2PolygonShape groundBox;
groundBox.SetAsBox(50.0f, 10.0f);
// Create a rigid body in the camera
Vector3 position(0, 20, 0);
Quaternion orientation = Quaternion::identity();
Transform transform(position, orientation);
RigidBody* body = world->createRigidBody(transform);
// Add ground fixture to body
groundBody->CreateFixture(&groundBox, 0.0f);
const decimal timeStep = 1.0f / 60.0f;
// Define dynamic body
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(0.0f, 4.0f);
b2Body* body = world.CreateBody(&bodyDef);
// Step the simulation a few steps
for (int i=0; i < 20; i++) {
// Define dynamic body shape
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(1.0f, 1.0f);
world->update(timeStep);
// Define dynamic body fixture
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
// Get the updated position of the body
const Transform& transform = body->getTransform();
const Vector3& position = transform.getPosition();
// Add fixture to body
body->CreateFixture(&fixtureDef);
// Display the position of the body
std::cout << "Body Position: (" << position.x << ", " <<
position.y << ", " << position.z << ")" << std::endl;
// Simulate the world
float timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
for (int32 i = 0; i < 60; ++i) {
world.Step(timeStep, velocityIterations, positionIterations);
b2Vec2 position = body->GetPosition();
float angle = body->GetAngle();
std::cout << position.x << " " << position.y << " " << angle << std::endl;
}
return 0;
}