Fixed player attacks
This commit is contained in:
parent
851e591c3c
commit
36aa2fa245
11 changed files with 152 additions and 17 deletions
|
@ -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)
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue