Fixed player attacks

This commit is contained in:
Maximilian Giller 2023-07-10 21:54:35 +02:00
parent 851e591c3c
commit 36aa2fa245
11 changed files with 152 additions and 17 deletions

View file

@ -4,9 +4,10 @@
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <box2d/box2d.h> #include <box2d/box2d.h>
#define DEVELOPER_MODE true #define DEVELOPER_MODE false
#define GAME_NAME "Holesome" #define GAME_NAME "Holesome"
#define CLOSE_GAME_BTN sf::Keyboard::Escape
// Player // Player
#define DEFAULT_PLAYER_SPEED 5.f // World units per second #define DEFAULT_PLAYER_SPEED 5.f // World units per second
@ -15,6 +16,9 @@
#define PLAYER_RADIUS_PER_LEVEL 0.25f #define PLAYER_RADIUS_PER_LEVEL 0.25f
#define DEFAULT_MAX_PLAYER_NUMBER 4 #define DEFAULT_MAX_PLAYER_NUMBER 4
#define MIN_PLAYER_COUNT 2 #define MIN_PLAYER_COUNT 2
#define REDUCED_POINT_DELTA_FOR_ATTACK 20
#define ATTACK_PER_SECOND 5.f
#define PLAYER_ALIVE_THRESHOLD -10
// World // World
#define WORLD_GRAVITY b2Vec2(0.f, -9.8f) #define WORLD_GRAVITY b2Vec2(0.f, -9.8f)

View file

@ -162,17 +162,17 @@ void Game::startCountdown(int durationInSeconds)
std::shared_ptr<Player> Game::checkForWinner() std::shared_ptr<Player> Game::checkForWinner()
{ {
std::vector<std::shared_ptr<Player>> players = PlayerCollection::getInstance()->getPlayers(); std::vector<std::shared_ptr<Player>> remainingPlayers = PlayerCollection::getInstance()->getRemainingPlayers();
// Has timer run out or is only one player left? // Has timer run out or is only one player left?
if (!countdown->isFinished() && players.size() > 1) if (!countdown->isFinished() && remainingPlayers.size() > 1)
{ {
return nullptr; return nullptr;
} }
// Return player with highest score as winner // Return player with highest score as winner
std::shared_ptr<Player> winner = nullptr; std::shared_ptr<Player> winner = nullptr;
for (const auto &player: players) for (const auto &player: remainingPlayers)
{ {
if (winner == nullptr || player->getPoints() > winner->getPoints()) if (winner == nullptr || player->getPoints() > winner->getPoints())
{ {

View file

@ -52,8 +52,8 @@ void InputMapper::processEvents()
void InputMapper::handleKeyPress(sf::Event::KeyEvent event) void InputMapper::handleKeyPress(sf::Event::KeyEvent event)
{ {
// Close game on Escape or Q in DEV Mode // Close game on Special button
if (DEVELOPER_MODE && event.code == sf::Keyboard::Escape) if (event.code == CLOSE_GAME_BTN)
{ {
Game::getInstance()->exit(); Game::getInstance()->exit();
return; return;

View file

@ -8,7 +8,7 @@ LevelConfig LevelGenerator::generateLevel(const std::string &name)
std::vector<CollectableInLevel> collectables = generateRandomCollectables(levelSize, levelSize); std::vector<CollectableInLevel> collectables = generateRandomCollectables(levelSize, levelSize);
return LevelConfig(name, return LevelConfig(name,
120, 90,
{ {
{1, 2}, {1, 2},
{2, 1}, {2, 1},

View file

@ -84,11 +84,13 @@ void MapPlayer::updateCollidingWithPlayers()
if (mapPlayerA->player->getPlayerId() == player->getPlayerId()) if (mapPlayerA->player->getPlayerId() == player->getPlayerId())
{ {
collidingWithPlayers.push_back(mapPlayerB->player->getPlayerId()); collidingWithPlayers.push_back(mapPlayerB->player->getPlayerId());
} else if (mapPlayerB->player->getPlayerId() == player->getPlayerId()) } else
{ {
collidingWithPlayers.push_back(mapPlayerA->player->getPlayerId()); collidingWithPlayers.push_back(mapPlayerA->player->getPlayerId());
} }
} }
player->setCollidingPlayers(collidingWithPlayers);
} }
void MapPlayer::updatePlayer() void MapPlayer::updatePlayer()

View file

@ -117,3 +117,15 @@ std::shared_ptr<MapPlayer> MapSimulation::getMapPlayerByBody(b2Body *body) const
} }
return nullptr; return nullptr;
} }
void MapSimulation::removePlayer(int playerId)
{
// Still in simulation?
if (mapPlayersById.find(playerId) == mapPlayersById.end())
{
return;
}
world->DestroyBody(mapPlayersById[playerId]->body);
mapPlayersById.erase(playerId);
}

View file

@ -22,6 +22,8 @@ public:
void addPlayer(const std::shared_ptr<Player>& player); void addPlayer(const std::shared_ptr<Player>& player);
void removePlayer(int playerId);
[[nodiscard]] std::shared_ptr<MapPlayer> getMapPlayerByBody(b2Body* body) const; [[nodiscard]] std::shared_ptr<MapPlayer> getMapPlayerByBody(b2Body* body) const;
private: private:

View file

@ -1,5 +1,8 @@
#include "player.hpp" #include "player.hpp"
#include "../../logging/easylogging++.h" #include "../../logging/easylogging++.h"
#include "player_collection.hpp"
#include "../../typography/font_manager.hpp"
#include "../physics/map/map_simulation.hpp"
#include <utility> #include <utility>
@ -37,10 +40,13 @@ void Player::update()
return; return;
} }
if (!passiveMode) { if (!passiveMode)
{
performInteractiveUpdates(); performInteractiveUpdates();
} }
handlePlayerCollisions();
GameObject::update(); GameObject::update();
} }
@ -83,23 +89,23 @@ void Player::setWorldRadius(float newWorldRadius)
skinSprite->coordinates->setScreenOffset(IsometricCoordinates(-newSize / 2.f)); skinSprite->coordinates->setScreenOffset(IsometricCoordinates(-newSize / 2.f));
} }
long Player::getPoints() const int Player::getPoints() const
{ {
return points; return points;
} }
void Player::updateRadiusBasedOnPoints() void Player::updateRadiusBasedOnPoints()
{ {
long points = getPoints(); int points = getPoints();
float newWorldRadius = PLAYER_MIN_RADIUS + PLAYER_RADIUS_PER_LEVEL * points / 10.f; float newWorldRadius = PLAYER_MIN_RADIUS + PLAYER_RADIUS_PER_LEVEL * points / 10.f;
setWorldRadius(newWorldRadius); setWorldRadius(newWorldRadius);
} }
void Player::consume(int points) void Player::consume(int consumedPoints)
{ {
this->points += points; this->points += consumedPoints;
LOG(INFO) << "Player " << playerId << " consumed " << points << " points. Total: " << this->points; LOG(INFO) << "Player " << playerId << " consumed " << consumedPoints << " points. Total: " << this->points;
updateRadiusBasedOnPoints(); updateRadiusBasedOnPoints();
} }
@ -125,3 +131,85 @@ void Player::performInteractiveUpdates()
auto moveDelta = moveDirection * speed * FRAME_TIME.asSeconds(); auto moveDelta = moveDirection * speed * FRAME_TIME.asSeconds();
coordinates->move(moveDelta); coordinates->move(moveDelta);
} }
void Player::setCollidingPlayers(const std::vector<int>& collidingPlayerIds)
{
collidingPlayers.clear();
for (auto collidingPlayerId: collidingPlayerIds)
{
collidingPlayers.push_back(PlayerCollection::getInstance()->getPlayerById(collidingPlayerId));
}
}
void Player::handlePlayerCollisions()
{
if (collidingPlayers.empty())
{
return;
}
// Count number of players that are bigger than this player by the required margin
float numAttackingPlayers = 0;
for (const auto& collidingPlayer: collidingPlayers)
{
if (collidingPlayer->getPoints() >= points + REDUCED_POINT_DELTA_FOR_ATTACK)
{
numAttackingPlayers++;
}
}
// Reduce points if necessary
float damage = numAttackingPlayers * ATTACK_PER_SECOND * FRAME_TIME.asSeconds();
points -= damage;
if (damage > 0) {
LOG(INFO) << "Player " << playerId << " lost " << damage << " points due to collisions. Total: " << points;
}
if (points <= PLAYER_ALIVE_THRESHOLD)
{
setAlive(false);
}
updateRadiusBasedOnPoints();
}
bool Player::getAlive() const
{
return isAlive;
}
void Player::setAlive(bool newAlive)
{
if (isAlive == newAlive)
{
return;
}
if (!newAlive)
{
setPassiveMode(true);
MapSimulation::getInstance()->removePlayer(getPlayerId());
}
isAlive = newAlive;
}
void Player::draw(sf::RenderWindow *window)
{
if (isAlive) {
GameObject::draw(window);
return;
}
// Print "You were consumed" message
sf::Text text;
text.setFont(*FontManager::getInstance()->getDefaultFont());
text.setString("x-x");
text.setCharacterSize(15);
text.setFillColor(sf::Color::Red);
text.setOutlineColor(sf::Color::Black);
text.setOutlineThickness(2);
text.setPosition(coordinates->isometric().x - text.getLocalBounds().width / 2.f,
coordinates->isometric().y - text.getLocalBounds().height / 2.f);
window->draw(text);
}

View file

@ -29,27 +29,37 @@ public:
[[nodiscard]] float getWorldRadius() const; [[nodiscard]] float getWorldRadius() const;
[[nodiscard]] long getPoints() const; [[nodiscard]] int getPoints() const;
void consume(int points); void consume(int consumedPoints);
std::string getSkinName() const; std::string getSkinName() const;
void setAlive(bool newAlive);
[[nodiscard]] bool getAlive() const;
std::shared_ptr<InputIdentity> getInput() const; std::shared_ptr<InputIdentity> getInput() const;
void setPassiveMode(bool newPassiveMode); void setPassiveMode(bool newPassiveMode);
void setCollidingPlayers(const std::vector<int>& collidingPlayerIds);
void draw(sf::RenderWindow *window) override;
TranslatedCoordinates spawnPosition; TranslatedCoordinates spawnPosition;
private: private:
std::shared_ptr<InputIdentity> input; std::shared_ptr<InputIdentity> input;
float radiusInWorld = 0.5f; // In world units float radiusInWorld = 0.5f; // In world units
std::shared_ptr<VersatileSprite> skinSprite; std::shared_ptr<VersatileSprite> skinSprite;
std::vector<std::shared_ptr<Player>> collidingPlayers;
bool passiveMode = true; bool passiveMode = true;
bool isAlive = true;
std::string skinName; std::string skinName;
long points = DEFAULT_PLAYER_POINTS; float points = DEFAULT_PLAYER_POINTS;
int playerId; int playerId;
static inline int playerCreationCounter = 0; static inline int playerCreationCounter = 0;
@ -59,6 +69,8 @@ private:
void updateRadiusBasedOnPoints(); void updateRadiusBasedOnPoints();
void performInteractiveUpdates(); void performInteractiveUpdates();
void handlePlayerCollisions();
}; };

View file

@ -227,3 +227,16 @@ void PlayerCollection::resetPlayers()
spawnPlayer(player->getInput(), player->getSkinName()); spawnPlayer(player->getInput(), player->getSkinName());
} }
} }
std::vector<std::shared_ptr<Player>> PlayerCollection::getRemainingPlayers() const
{
std::vector<std::shared_ptr<Player>> remainingPlayers = {};
for (auto &player: getPlayers())
{
if (player->getAlive())
{
remainingPlayers.push_back(player);
}
}
return remainingPlayers;
}

View file

@ -28,6 +28,8 @@ public:
[[nodiscard]] std::vector<std::shared_ptr<Player>> getRemovedPlayers() const; [[nodiscard]] std::vector<std::shared_ptr<Player>> getRemovedPlayers() const;
[[nodiscard]] std::vector<std::shared_ptr<Player>> getRemainingPlayers() const;
[[nodiscard]] int getMaxPlayerCount() const; [[nodiscard]] int getMaxPlayerCount() const;
void lateUpdate() override; void lateUpdate() override;