diff --git a/TODO.md b/TODO.md index 1ac6651..bfadb70 100644 --- a/TODO.md +++ b/TODO.md @@ -2,18 +2,19 @@ ## Next -- Player spawns initially at (0,0) and almost fails to jump to target spawn +- Damage other players on contact ## Bugs +- Player spawns initially at (0,0) and almost fails to jump to target spawn - Player disconnect in multiplayer sometimes targeting disconnected player or something like that ## High priority -- Procedural level generation - Physics -- Damage other players on contact - Players-join-screen before the game starts + +- Procedural points generation - Game over screen - Proper player graphics - Collectables with graphics diff --git a/src/config.h b/src/config.h index 0d3e706..905e599 100644 --- a/src/config.h +++ b/src/config.h @@ -8,8 +8,9 @@ // Player #define DEFAULT_PLAYER_SPEED 5.f // World units per second -#define DEFAULT_PLAYER_RADIUS .5f // In World units -#define PLAYER_PROPORTIONAL_SIZE_CHANGE_SPEED 0.4f +#define DEFAULT_PLAYER_POINTS 0 +#define PLAYER_MIN_RADIUS 0.5f // World units +#define PLAYER_RADIUS_PER_LEVEL 0.25f // World #define WORLD_GRAVITY b2Vec2(0.f, 9.8f) diff --git a/src/game/physics/map/map_player.cpp b/src/game/physics/map/map_player.cpp index 27140dd..5342635 100644 --- a/src/game/physics/map/map_player.cpp +++ b/src/game/physics/map/map_player.cpp @@ -1,4 +1,5 @@ #include "map_player.hpp" +#include "map_simulation.hpp" void MapPlayer::updateSimulationPosition() { @@ -42,4 +43,56 @@ void MapPlayer::updateShape() fixtureDef.density = 1.0f; body->CreateFixture(&fixtureDef); -} \ No newline at end of file +} + +void MapPlayer::updateCollidingWithPlayers() +{ + collidingWithPlayers.clear(); + + for (b2ContactEdge *contactEdge = body->GetContactList(); contactEdge != nullptr; contactEdge = contactEdge->next) + { + b2Contact *contact = contactEdge->contact; + if (!contact->IsTouching()) + { + continue; + } + + b2Fixture *fixtureA = contact->GetFixtureA(); + b2Fixture *fixtureB = contact->GetFixtureB(); + + if (fixtureA->IsSensor() || fixtureB->IsSensor()) + { + continue; + } + + b2Body *bodyA = fixtureA->GetBody(); + b2Body *bodyB = fixtureB->GetBody(); + + if (bodyA->GetType() != b2_dynamicBody || bodyB->GetType() != b2_dynamicBody) + { + continue; + } + + std::shared_ptr mapPlayerA = MapSimulation::getInstance()->getMapPlayerByBody(bodyA); + std::shared_ptr mapPlayerB = MapSimulation::getInstance()->getMapPlayerByBody(bodyA); + + if (mapPlayerA == nullptr || mapPlayerB == nullptr) + { + continue; + } + + if (mapPlayerA->player->getPlayerId() == player->getPlayerId()) + { + collidingWithPlayers.push_back(mapPlayerB->player->getPlayerId()); + } else if (mapPlayerB->player->getPlayerId() == player->getPlayerId()) + { + collidingWithPlayers.push_back(mapPlayerA->player->getPlayerId()); + } + } +} + +void MapPlayer::updatePlayer() +{ + updatePlayerPosition(); + updateCollidingWithPlayers(); +} diff --git a/src/game/physics/map/map_player.hpp b/src/game/physics/map/map_player.hpp index a469dcc..efa3c20 100644 --- a/src/game/physics/map/map_player.hpp +++ b/src/game/physics/map/map_player.hpp @@ -14,6 +14,7 @@ public: std::shared_ptr player; b2Body *body; float shapeRadius = 0; + std::vector collidingWithPlayers = {}; MapPlayer(std::shared_ptr player, b2Body *body) : player(std::move(player)), body(body) { @@ -21,10 +22,15 @@ public: } void updateSimulationPosition(); + void updatePlayer(); + + void updateShape(); + +private: void updatePlayerPosition() const; - void updateShape(); + void updateCollidingWithPlayers(); }; diff --git a/src/game/physics/map/map_simulation.cpp b/src/game/physics/map/map_simulation.cpp index 33fe263..39650a1 100644 --- a/src/game/physics/map/map_simulation.cpp +++ b/src/game/physics/map/map_simulation.cpp @@ -26,10 +26,10 @@ void MapSimulation::physicsUpdate() world->Step(FRAME_TIME.asSeconds(), MAPSIM_VELOCITY_ITERATIONS, MAPSIM_POSITION_ITERATIONS); - // Update player positions + // Update players for (auto &mapPlayer: mapPlayersById) { - mapPlayer.second->updatePlayerPosition(); + mapPlayer.second->updatePlayer(); } } @@ -45,10 +45,15 @@ void MapSimulation::resetMap(sf::Vector2 worldMapSize) world = std::make_shared(b2Vec2(0.0f, 0.0f)); // Create map borders - constructSquareObstacle(-MAPSIM_WALL_THICKNESS, -MAPSIM_WALL_THICKNESS, 0, worldMapSize.y + MAPSIM_WALL_THICKNESS); // Bottom left - constructSquareObstacle(0, -MAPSIM_WALL_THICKNESS, worldMapSize.x, 0); // Bottom right - constructSquareObstacle(worldMapSize.x, -MAPSIM_WALL_THICKNESS, worldMapSize.x + MAPSIM_WALL_THICKNESS, worldMapSize.y + MAPSIM_WALL_THICKNESS); // Top right - constructSquareObstacle(0, worldMapSize.y, worldMapSize.x, worldMapSize.y + MAPSIM_WALL_THICKNESS); // Top left + constructSquareObstacle(-MAPSIM_WALL_THICKNESS, -MAPSIM_WALL_THICKNESS, + 0, worldMapSize.y + MAPSIM_WALL_THICKNESS); // Bottom left + constructSquareObstacle(0, -MAPSIM_WALL_THICKNESS, + worldMapSize.x, 0); // Bottom right + constructSquareObstacle(worldMapSize.x, -MAPSIM_WALL_THICKNESS, + worldMapSize.x + MAPSIM_WALL_THICKNESS, + worldMapSize.y + MAPSIM_WALL_THICKNESS); // Top right + constructSquareObstacle(0, worldMapSize.y, + worldMapSize.x, worldMapSize.y + MAPSIM_WALL_THICKNESS); // Top left } void MapSimulation::constructSquareObstacle(float minX, float minY, float maxX, float maxY) @@ -99,3 +104,15 @@ void MapSimulation::removePlayer(std::shared_ptr &player) world->DestroyBody(mapPlayersById[playerId]->body); mapPlayersById.erase(playerId); } + +std::shared_ptr MapSimulation::getMapPlayerByBody(b2Body *body) const +{ + for (auto &mapPlayer: mapPlayersById) + { + if (mapPlayer.second->body == body) + { + return mapPlayer.second; + } + } + return nullptr; +} diff --git a/src/game/physics/map/map_simulation.hpp b/src/game/physics/map/map_simulation.hpp index 5b57bd6..244ffe4 100644 --- a/src/game/physics/map/map_simulation.hpp +++ b/src/game/physics/map/map_simulation.hpp @@ -22,6 +22,7 @@ public: void addPlayer(const std::shared_ptr& player); + [[nodiscard]] std::shared_ptr getMapPlayerByBody(b2Body* body) const; private: static inline std::shared_ptr singletonInstance = nullptr; diff --git a/src/game/player/player.cpp b/src/game/player/player.cpp index 02143f7..c88280b 100644 --- a/src/game/player/player.cpp +++ b/src/game/player/player.cpp @@ -9,12 +9,13 @@ Player::Player(std::shared_ptr assignedInput, const std::string & { playerId = playerCreationCounter++; coordinates->setTranslated(spawnPosition); - input = std::move(assignedInput); skinSprite = std::make_shared(skinRessourceName, getIsoSize()); addChildScreenOffset(skinSprite, IsometricCoordinates(-getIsoSize() / 2.f)); + updateRadiusBasedOnLevel(); + LOG(INFO) << "Player " << playerId << " created."; } @@ -42,17 +43,17 @@ void Player::update() if (input->isPerformingAction(GameAction::GROW)) { - setWorldRadius(radiusInWorld * (1 + PLAYER_PROPORTIONAL_SIZE_CHANGE_SPEED * FRAME_TIME.asSeconds())); + points = (points + 1) * (1 + 1 * FRAME_TIME.asSeconds()); } else if (input->isPerformingAction(GameAction::SHRINK)) { - auto newRadius = radiusInWorld * (1 - PLAYER_PROPORTIONAL_SIZE_CHANGE_SPEED * FRAME_TIME.asSeconds()); - if (newRadius <= DEFAULT_PLAYER_RADIUS) - { - newRadius = DEFAULT_PLAYER_RADIUS; + points *= 1 - 1 * FRAME_TIME.asSeconds(); + if (points < 0) { + points = 0; } - setWorldRadius(newRadius); } + updateRadiusBasedOnLevel(); + GameObject::update(); } @@ -94,3 +95,16 @@ void Player::setWorldRadius(float newWorldRadius) skinSprite->setSize(newSize); skinSprite->coordinates->setScreenOffset(IsometricCoordinates(-newSize / 2.f)); } + +long Player::getPoints() const +{ + return points; +} + +void Player::updateRadiusBasedOnLevel() +{ + long points = getPoints(); + float newWorldRadius = PLAYER_MIN_RADIUS + PLAYER_RADIUS_PER_LEVEL * pow(points / 100.f, 2); + + setWorldRadius(newWorldRadius); +} diff --git a/src/game/player/player.hpp b/src/game/player/player.hpp index cd59d08..90cef17 100644 --- a/src/game/player/player.hpp +++ b/src/game/player/player.hpp @@ -29,16 +29,22 @@ public: [[nodiscard]] float getWorldRadius() const; + [[nodiscard]] long getPoints() const; + TranslatedCoordinates spawnPosition; private: std::shared_ptr input; - float radiusInWorld = DEFAULT_PLAYER_RADIUS; + float radiusInWorld = 0.5f; // In world units std::shared_ptr skinSprite; + long points = DEFAULT_PLAYER_POINTS; + int playerId; static inline int playerCreationCounter = 0; void setWorldRadius(float newWorldRadius); + + void updateRadiusBasedOnLevel(); }; diff --git a/src/game/player/player_collection.cpp b/src/game/player/player_collection.cpp index 26aadda..e9758f4 100644 --- a/src/game/player/player_collection.cpp +++ b/src/game/player/player_collection.cpp @@ -118,3 +118,15 @@ std::vector> PlayerCollection::getPlayers() const } return players; } + +std::shared_ptr PlayerCollection::getPlayerById(int playerId) const +{ + for (auto &player: getPlayers()) + { + if (player->getPlayerId() == playerId) + { + return player; + } + } + throw std::runtime_error("Player with id " + std::to_string(playerId) + " not found"); +} diff --git a/src/game/player/player_collection.hpp b/src/game/player/player_collection.hpp index 2d7ef8f..c3d5bfb 100644 --- a/src/game/player/player_collection.hpp +++ b/src/game/player/player_collection.hpp @@ -18,11 +18,13 @@ public: void removePlayer(const std::shared_ptr& player); - std::vector> getPlayers() const; + [[nodiscard]] std::vector> getPlayers() const; - std::vector> getNewPlayers() const; + [[nodiscard]] std::shared_ptr getPlayerById(int playerId) const; - std::vector> getRemovedPlayers() const; + [[nodiscard]] std::vector> getNewPlayers() const; + + [[nodiscard]] std::vector> getRemovedPlayers() const; void lateUpdate() override;