diff --git a/CMakeLists.txt b/CMakeLists.txt index 32b424a..d340689 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,7 +121,12 @@ set(SOURCES src/game/physics/holes/layouts/hole_layout.cpp src/game/physics/holes/layouts/hole_layout.hpp src/game/physics/holes/layouts/depth_hole_layout.hpp - src/game/physics/holes/layouts/depth_hole_description.hpp src/game/physics/holes/collectable_sim_ground_segment.hpp src/game/physics/holes/collectable_sim_ground_segment.cpp) + src/game/physics/holes/layouts/depth_hole_description.hpp + src/game/physics/holes/ground/collectable_sim_ground_segment.hpp + src/game/physics/holes/ground/collectable_sim_ground.cpp + src/game/physics/holes/ground/collectable_sim_ground.hpp + src/game/physics/body_adapter.cpp + src/game/physics/body_adapter.hpp) set(PHYSICS_00_SOURCES src/prototypes/physics_00.cpp) diff --git a/src/config.h b/src/config.h index ed180d7..8200033 100644 --- a/src/config.h +++ b/src/config.h @@ -11,6 +11,7 @@ #define DEFAULT_PLAYER_POINTS 0 #define PLAYER_MIN_RADIUS 0.5f // World units #define PLAYER_RADIUS_PER_LEVEL 0.25f +#define DEFAULT_MAX_PLAYER_NUMBER 4 // World #define WORLD_GRAVITY b2Vec2(0.f, -9.8f) diff --git a/src/game/physics/body_adapter.cpp b/src/game/physics/body_adapter.cpp new file mode 100644 index 0000000..30bd17c --- /dev/null +++ b/src/game/physics/body_adapter.cpp @@ -0,0 +1,82 @@ +#include "body_adapter.hpp" + +#include "../../config.h" + +BodyAdapter::BodyAdapter(std::shared_ptr world) + : world(std::move(world)), bodyObject(nullptr) +{} + +BodyAdapter::~BodyAdapter() +{ + destroyBody(); +} + +void BodyAdapter::destroyBody() +{ + if (bodyObject != nullptr) + { + world->DestroyBody(bodyObject); + } +} + + +void BodyAdapter::createSquare(b2BodyType type, sf::Vector2f center, sf::Vector2f size) +{ + destroyBody(); + + b2BodyDef bodyDef; + bodyDef.type = type; + bodyDef.angularDamping = COLLECTABLES_SIM_ANGULAR_DAMPING; + bodyDef.linearDamping = COLLECTABLES_SIM_LINEAR_DAMPING; + bodyDef.position.Set(center.x, center.y); + bodyObject = world->CreateBody(&bodyDef); + + setBoxSize(size); +} + +b2Body *BodyAdapter::body() const +{ + return bodyObject; +} + +sf::Vector2f BodyAdapter::getCenter() const +{ + auto position = bodyObject->GetPosition(); + auto velocity = bodyObject->GetLinearVelocity(); + return sf::Vector2f(position.x, position.y) + sf::Vector2f(velocity.x, velocity.y); +} + +sf::Vector2f BodyAdapter::getSize() const +{ + return boundingBox; +} + +void BodyAdapter::setCenter(sf::Vector2f center) +{ + // Set via velocity + auto velocity = bodyObject->GetLinearVelocity(); + velocity += b2Vec2(center.x, center.y) - bodyObject->GetPosition(); + bodyObject->SetLinearVelocity(velocity); +} + +void BodyAdapter::setBoxSize(sf::Vector2f size) +{ + // Remove old fixture + if (bodyObject->GetFixtureList() != nullptr) + { + bodyObject->DestroyFixture(bodyObject->GetFixtureList()); + } + + // Recreates a square fixture + b2PolygonShape shape; + shape.SetAsBox(size.x / 2.f, size.y / 2.f); + boundingBox = size; + + b2FixtureDef fixtureDef; + fixtureDef.shape = &shape; + fixtureDef.friction = COLLECTABLES_SIM_FRICTION; + fixtureDef.restitution = COLLECTABLES_SIM_RESTITUTION; + fixtureDef.density = COLLECTABLES_SIM_DENSITY; + + bodyObject->CreateFixture(&fixtureDef); +} diff --git a/src/game/physics/body_adapter.hpp b/src/game/physics/body_adapter.hpp new file mode 100644 index 0000000..1597d43 --- /dev/null +++ b/src/game/physics/body_adapter.hpp @@ -0,0 +1,37 @@ +#ifndef HOLESOME_BODY_ADAPTER_HPP +#define HOLESOME_BODY_ADAPTER_HPP + + +#include +#include +#include + +class BodyAdapter +{ +public: + explicit BodyAdapter(std::shared_ptr world); + ~BodyAdapter(); + + [[nodiscard]] b2Body *body() const; + + void createSquare(b2BodyType type, sf::Vector2f center, sf::Vector2f size); + + [[nodiscard]] sf::Vector2f getCenter() const; + + void setCenter(sf::Vector2f center); + + [[nodiscard]] sf::Vector2f getSize() const; + + void setBoxSize(sf::Vector2f size); + +private: + std::shared_ptr world; + b2Body *bodyObject; + + sf::Vector2f boundingBox; + + void destroyBody(); +}; + + +#endif //HOLESOME_BODY_ADAPTER_HPP diff --git a/src/game/physics/holes/collectable_sim_ground_segment.cpp b/src/game/physics/holes/collectable_sim_ground_segment.cpp deleted file mode 100644 index 91fbc67..0000000 --- a/src/game/physics/holes/collectable_sim_ground_segment.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "collectable_sim_ground_segment.hpp" \ No newline at end of file diff --git a/src/game/physics/holes/collectable_sim_ground_segment.hpp b/src/game/physics/holes/collectable_sim_ground_segment.hpp deleted file mode 100644 index 39d5347..0000000 --- a/src/game/physics/holes/collectable_sim_ground_segment.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP -#define HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP - -#include - -class CollectableSimGroundSegment -{ -public: - int leftHoleId; - int rightHoleId; - b2Body *body; -}; - -#endif //HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP diff --git a/src/game/physics/holes/collectable_simulation.cpp b/src/game/physics/holes/collectable_simulation.cpp index 127d565..dc91abd 100644 --- a/src/game/physics/holes/collectable_simulation.cpp +++ b/src/game/physics/holes/collectable_simulation.cpp @@ -11,9 +11,14 @@ CollectableSimulation::CollectableSimulation(const std::shared_ptr world = std::make_shared(WORLD_GRAVITY); world->SetAllowSleeping(COLLECTABLES_SIM_SLEEPING); + // Create ground + simGround = std::make_shared(world); +// Todo: Set proper ground width + // Create body + collectableBody = std::make_shared(world); auto coordinates = collectable->coordinates->diagonalWorld(); - body = addSquareBody(b2_dynamicBody, {coordinates.horizontal, coordinates.vertical}, sf::Vector2f(1, 1)); + collectableBody->createSquare(b2_dynamicBody, {coordinates.horizontal, coordinates.vertical}, sf::Vector2f(1, 1)); } void CollectableSimulation::physicsUpdate() @@ -25,28 +30,6 @@ void CollectableSimulation::physicsUpdate() updateCollectable(); } -b2Body *CollectableSimulation::addSquareBody(b2BodyType type, sf::Vector2f center, sf::Vector2f size) -{ - b2BodyDef bodyDef; - bodyDef.type = type; - bodyDef.angularDamping = COLLECTABLES_SIM_ANGULAR_DAMPING; - bodyDef.linearDamping = COLLECTABLES_SIM_LINEAR_DAMPING; - bodyDef.position.Set(center.x, center.y); - b2Body *body = world->CreateBody(&bodyDef); - - b2PolygonShape shape; - shape.SetAsBox(size.x / 2.f, size.y / 2.f); - - b2FixtureDef fixtureDef; - fixtureDef.shape = &shape; - fixtureDef.friction = COLLECTABLES_SIM_FRICTION; - fixtureDef.restitution = COLLECTABLES_SIM_RESTITUTION; - fixtureDef.density = COLLECTABLES_SIM_DENSITY; - - body->CreateFixture(&fixtureDef); - return body; -} - std::shared_ptr CollectableSimulation::getCollectable() const { return collectable; @@ -56,15 +39,25 @@ void CollectableSimulation::updateGroundHole() { auto holeLayout = HoleLayout::getInstance()->atDepth(collectable->getDepth()); + if (holeLayout.holes.empty()) + { + simGround->closeAllHoles(); + return; + } + // TODO: Remove assumption + // Assume only one hole + auto hole = holeLayout.holes[0]; + +// todo: Update ground hole } void CollectableSimulation::updateCollectable() { - auto bodyPosition = body->GetPosition(); + auto bodyPosition = collectableBody->body()->GetPosition(); collectable->coordinates->setDiagonal({bodyPosition.x, bodyPosition.y, collectable->getDepth()}); // Convert radians to degrees - float angle = body->GetAngle() * 180 / M_PI; + float angle = collectableBody->body()->GetAngle() * 180 / M_PI; collectable->setRotation(angle); } diff --git a/src/game/physics/holes/collectable_simulation.hpp b/src/game/physics/holes/collectable_simulation.hpp index a24e5d2..8ce1cdf 100644 --- a/src/game/physics/holes/collectable_simulation.hpp +++ b/src/game/physics/holes/collectable_simulation.hpp @@ -3,8 +3,12 @@ #include +#include #include "../../game_object.h" #include "../../collectables/collectable.hpp" +#include "ground/collectable_sim_ground_segment.hpp" +#include "ground/collectable_sim_ground.hpp" +#include "../body_adapter.hpp" class CollectableSimulation : public GameObject { @@ -17,15 +21,15 @@ public: private: std::shared_ptr world; - b2Body* body; + std::shared_ptr collectableBody; std::shared_ptr collectable; + std::shared_ptr simGround; + void updateGroundHole(); void updateCollectable(); - - b2Body *addSquareBody(b2BodyType type, sf::Vector2f center, sf::Vector2f size); }; diff --git a/src/game/physics/holes/ground/collectable_sim_ground.cpp b/src/game/physics/holes/ground/collectable_sim_ground.cpp new file mode 100644 index 0000000..09f72dc --- /dev/null +++ b/src/game/physics/holes/ground/collectable_sim_ground.cpp @@ -0,0 +1,102 @@ +#include "collectable_sim_ground.hpp" + +#include +#include "../../../../config.h" + +void CollectableSimGround::closeAllHoles() +{ + segments.clear(); + + // Create one segment for the ground + auto groundSegment = std::make_shared(world); + groundSegment->body->createSquare(b2_kinematicBody, + {0, -COLLECTABLES_SIM_GROUND_THICKNESS / 2.f}, + {groundWidth, COLLECTABLES_SIM_GROUND_THICKNESS}); + + segments.push_back(groundSegment); +} + +CollectableSimGround::CollectableSimGround(std::shared_ptr world, float groundWidth) + : world(std::move(world)) +{ + setGroundWidth(groundWidth); + closeAllHoles(); +} + +void CollectableSimGround::setGroundWidth(float width) +{ + if (width <= 0) + { + throw std::runtime_error("Ground width must be greater than 0"); + } + + if (width == groundWidth) + { + return; + } + + groundWidth = width; + updateOuterSegmentsToWidth(); +} + +void CollectableSimGround::updateOuterSegmentsToWidth() +{ + auto outerSegments = getOuterSegments(); + auto borderPoints = groundWidth / 2.f; + + // Left segment + if (outerSegments.left != nullptr) + { + auto leftSegment = outerSegments.left->body; + auto leftCenter = leftSegment->getCenter(); + auto leftSize = leftSegment->getSize(); + auto deltaToBorder = borderPoints - abs(leftCenter.x - leftSize.x / 2.f); + + // Increase width if positive, decrease if negative + leftSize.x += deltaToBorder; + leftCenter.x -= deltaToBorder / 2.f; + + leftSegment->setBoxSize(leftSize); + leftSegment->setCenter(leftCenter); + } + + // Right segment + if (outerSegments.right != nullptr) + { + auto rightSegment = outerSegments.right->body; + auto rightCenter = rightSegment->getCenter(); + auto rightSize = rightSegment->getSize(); + auto deltaToBorder = borderPoints - abs(rightCenter.x + rightSize.x / 2.f); + + // Increase width if positive, decrease if negative + rightSize.x += deltaToBorder; + rightCenter.x += deltaToBorder / 2.f; + + rightSegment->setBoxSize(rightSize); + rightSegment->setCenter(rightCenter); + } +} + +CollectableSimGround::SideSegments CollectableSimGround::getOuterSegments(int holeId) +{ + SideSegments sideSegments; + + for (const auto &segment: segments) + { + // If valid holeId, match left hole id + // If invalid holeId, get outer segment + if ((segment->leftHoleId == holeId && holeId >= 0) + || (segment->rightHoleId < 0 && holeId < 0)) + { + sideSegments.right = segment; + } + + if ((segment->rightHoleId == holeId && holeId >= 0) + || (segment->leftHoleId < 0 && holeId < 0)) + { + sideSegments.left = segment; + } + } + + return sideSegments; +} diff --git a/src/game/physics/holes/ground/collectable_sim_ground.hpp b/src/game/physics/holes/ground/collectable_sim_ground.hpp new file mode 100644 index 0000000..3306082 --- /dev/null +++ b/src/game/physics/holes/ground/collectable_sim_ground.hpp @@ -0,0 +1,34 @@ +#ifndef HOLESOME_COLLECTABLE_SIM_GROUND_HPP +#define HOLESOME_COLLECTABLE_SIM_GROUND_HPP + + +#include +#include +#include "collectable_sim_ground_segment.hpp" + +class CollectableSimGround +{ +public: + CollectableSimGround(std::shared_ptr world, float groundWidth = 1000); + + void closeAllHoles(); + + void setGroundWidth(float width); + +private: + std::vector> segments; + std::shared_ptr world; + float groundWidth; + + struct SideSegments { + std::shared_ptr left; + std::shared_ptr right; + }; + + SideSegments getOuterSegments(int holeId = -1); + + void updateOuterSegmentsToWidth(); +}; + + +#endif //HOLESOME_COLLECTABLE_SIM_GROUND_HPP diff --git a/src/game/physics/holes/ground/collectable_sim_ground_segment.hpp b/src/game/physics/holes/ground/collectable_sim_ground_segment.hpp new file mode 100644 index 0000000..28632f2 --- /dev/null +++ b/src/game/physics/holes/ground/collectable_sim_ground_segment.hpp @@ -0,0 +1,22 @@ +#ifndef HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP +#define HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP + +#include +#include +#include "../layouts/depth_hole_description.hpp" +#include "../../body_adapter.hpp" + +class CollectableSimGroundSegment +{ +public: + explicit CollectableSimGroundSegment(const std::shared_ptr& world) + { + body = std::make_shared(world); + } + + int leftHoleId = -1; + int rightHoleId = -1; + std::shared_ptr body; +}; + +#endif //HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP diff --git a/src/game/physics/holes/layouts/depth_hole_layout.hpp b/src/game/physics/holes/layouts/depth_hole_layout.hpp index f57c793..8fbea95 100644 --- a/src/game/physics/holes/layouts/depth_hole_layout.hpp +++ b/src/game/physics/holes/layouts/depth_hole_layout.hpp @@ -3,6 +3,7 @@ #include #include "depth_hole_description.hpp" +#include "../../../../logging/easylogging++.h" struct DepthHoleLayout { @@ -12,6 +13,26 @@ struct DepthHoleLayout DepthHoleLayout(float depth, std::vector holes) : depth(depth), holes(std::move(holes)) {} + + [[nodiscard]] DepthHoleDescription getHole(int playerId) const + { + for (const auto &hole: holes) + { + if (hole.playerId == playerId) + { + return hole; + } + } + + throw std::runtime_error( + "No hole for player " + std::to_string(playerId) + " at depth " + std::to_string(depth) + + " in layout."); + } + + [[nodiscard]] bool hasHole(int playerId) const + { + return std::ranges::any_of(holes, [playerId](const auto &hole) { return hole.playerId == playerId; }); + } }; #endif //HOLESOME_DEPTH_HOLE_LAYOUT_HPP diff --git a/src/game/player/player_collection.cpp b/src/game/player/player_collection.cpp index 7018075..00aa517 100644 --- a/src/game/player/player_collection.cpp +++ b/src/game/player/player_collection.cpp @@ -4,7 +4,8 @@ #include "../input/input_mapper.h" #include "../../texture_config.h" -PlayerCollection::PlayerCollection() +PlayerCollection::PlayerCollection(int maxPlayerCount) + : maxPlayerCount(maxPlayerCount) { // Set default spawn point setSpawnPoints({{0, 0}}); @@ -29,6 +30,7 @@ void PlayerCollection::addPlayer(const std::shared_ptr &player) { newPlayerBuffer.push_back(player); addDetachedChild(player); + updateInputIdentityAllowance(); } void PlayerCollection::clear() @@ -47,6 +49,7 @@ void PlayerCollection::clear() } clearChildren(); + updateInputIdentityAllowance(); } void PlayerCollection::lateUpdate() @@ -77,6 +80,7 @@ void PlayerCollection::removePlayer(const std::shared_ptr &player) { removedPlayerBuffer.push_back(player); removeChild(player); + updateInputIdentityAllowance(); } std::vector> PlayerCollection::getNewPlayers() const @@ -130,3 +134,13 @@ std::shared_ptr PlayerCollection::getPlayerById(int playerId) const } throw std::runtime_error("Player with id " + std::to_string(playerId) + " not found"); } + +int PlayerCollection::getMaxPlayerCount() const +{ + return maxPlayerCount; +} + +void PlayerCollection::updateInputIdentityAllowance() const +{ + InputMapper::getInstance()->allowNewInputIdentities = getPlayers().size() < maxPlayerCount; +} diff --git a/src/game/player/player_collection.hpp b/src/game/player/player_collection.hpp index c3d5bfb..ac3aaaf 100644 --- a/src/game/player/player_collection.hpp +++ b/src/game/player/player_collection.hpp @@ -8,7 +8,7 @@ class PlayerCollection : public GameObject { public: - PlayerCollection(); + explicit PlayerCollection(int maxPlayerCount = DEFAULT_MAX_PLAYER_NUMBER); static std::shared_ptr getInstance(); @@ -26,6 +26,8 @@ public: [[nodiscard]] std::vector> getRemovedPlayers() const; + [[nodiscard]] int getMaxPlayerCount() const; + void lateUpdate() override; void clear(); @@ -40,6 +42,10 @@ private: int nextSpawnPointIndex = 0; void spawnPlayer(const std::shared_ptr &inputIdentity); + + int maxPlayerCount; + + void updateInputIdentityAllowance() const; }; diff --git a/src/levels.hpp b/src/levels.hpp index b155794..344c8d2 100644 --- a/src/levels.hpp +++ b/src/levels.hpp @@ -12,7 +12,7 @@ std::map const all_levels = { {18, 18}, {0, 18}, {18, 0}}, { - CollectableInLevel("box", {0, 0}) + CollectableInLevel("box", {3, 5}) }, { // Blues