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 <box2d/box2d.h>
#define DEVELOPER_MODE true
#define DEVELOPER_MODE false
#define GAME_NAME "Holesome"
#define CLOSE_GAME_BTN sf::Keyboard::Escape
// Player
#define DEFAULT_PLAYER_SPEED 5.f // World units per second
@ -15,6 +16,9 @@
#define PLAYER_RADIUS_PER_LEVEL 0.25f
#define DEFAULT_MAX_PLAYER_NUMBER 4
#define MIN_PLAYER_COUNT 2
#define REDUCED_POINT_DELTA_FOR_ATTACK 20
#define ATTACK_PER_SECOND 5.f
#define PLAYER_ALIVE_THRESHOLD -10
// World
#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::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?
if (!countdown->isFinished() && players.size() > 1)
if (!countdown->isFinished() && remainingPlayers.size() > 1)
{
return nullptr;
}
// Return player with highest score as winner
std::shared_ptr<Player> winner = nullptr;
for (const auto &player: players)
for (const auto &player: remainingPlayers)
{
if (winner == nullptr || player->getPoints() > winner->getPoints())
{

View file

@ -52,8 +52,8 @@ 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)
// Close game on Special button
if (event.code == CLOSE_GAME_BTN)
{
Game::getInstance()->exit();
return;

View file

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

View file

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

View file

@ -117,3 +117,15 @@ std::shared_ptr<MapPlayer> MapSimulation::getMapPlayerByBody(b2Body *body) const
}
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 removePlayer(int playerId);
[[nodiscard]] std::shared_ptr<MapPlayer> getMapPlayerByBody(b2Body* body) const;
private:

View file

@ -1,5 +1,8 @@
#include "player.hpp"
#include "../../logging/easylogging++.h"
#include "player_collection.hpp"
#include "../../typography/font_manager.hpp"
#include "../physics/map/map_simulation.hpp"
#include <utility>
@ -37,10 +40,13 @@ void Player::update()
return;
}
if (!passiveMode) {
if (!passiveMode)
{
performInteractiveUpdates();
}
handlePlayerCollisions();
GameObject::update();
}
@ -83,23 +89,23 @@ void Player::setWorldRadius(float newWorldRadius)
skinSprite->coordinates->setScreenOffset(IsometricCoordinates(-newSize / 2.f));
}
long Player::getPoints() const
int Player::getPoints() const
{
return points;
}
void Player::updateRadiusBasedOnPoints()
{
long points = getPoints();
int points = getPoints();
float newWorldRadius = PLAYER_MIN_RADIUS + PLAYER_RADIUS_PER_LEVEL * points / 10.f;
setWorldRadius(newWorldRadius);
}
void Player::consume(int points)
void Player::consume(int consumedPoints)
{
this->points += points;
LOG(INFO) << "Player " << playerId << " consumed " << points << " points. Total: " << this->points;
this->points += consumedPoints;
LOG(INFO) << "Player " << playerId << " consumed " << consumedPoints << " points. Total: " << this->points;
updateRadiusBasedOnPoints();
}
@ -125,3 +131,85 @@ void Player::performInteractiveUpdates()
auto moveDelta = moveDirection * speed * FRAME_TIME.asSeconds();
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]] long getPoints() const;
[[nodiscard]] int getPoints() const;
void consume(int points);
void consume(int consumedPoints);
std::string getSkinName() const;
void setAlive(bool newAlive);
[[nodiscard]] bool getAlive() const;
std::shared_ptr<InputIdentity> getInput() const;
void setPassiveMode(bool newPassiveMode);
void setCollidingPlayers(const std::vector<int>& collidingPlayerIds);
void draw(sf::RenderWindow *window) override;
TranslatedCoordinates spawnPosition;
private:
std::shared_ptr<InputIdentity> input;
float radiusInWorld = 0.5f; // In world units
std::shared_ptr<VersatileSprite> skinSprite;
std::vector<std::shared_ptr<Player>> collidingPlayers;
bool passiveMode = true;
bool isAlive = true;
std::string skinName;
long points = DEFAULT_PLAYER_POINTS;
float points = DEFAULT_PLAYER_POINTS;
int playerId;
static inline int playerCreationCounter = 0;
@ -59,6 +69,8 @@ private:
void updateRadiusBasedOnPoints();
void performInteractiveUpdates();
void handlePlayerCollisions();
};

View file

@ -227,3 +227,16 @@ void PlayerCollection::resetPlayers()
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>> getRemainingPlayers() const;
[[nodiscard]] int getMaxPlayerCount() const;
void lateUpdate() override;