diff --git a/Client.cpp b/Client.cpp index 2491652..17227e7 100644 --- a/Client.cpp +++ b/Client.cpp @@ -12,7 +12,7 @@ void Client::updatePacket() { sf::Packet packet; - packet << MsgType::ClientUpdate << _player->position().x() << _player->position().y() << _player->position().z() << _player->angle().y() << _player->headAngle(); + packet << MsgType::ClientUpdate << _player->position().x() << _player->position().y() << _player->position().z() << _player->angle().y() << _player->headAngle() << _player->playerName(); _socket.send(packet, _socket.serverId()); } @@ -35,20 +35,22 @@ void Client::processInit(sf::Packet& packet) { void Client::processUpdate(sf::Packet& packet) { sf::Uint16 targetId; double buf[6]; + std::string playerName; - while (packet >> targetId >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> buf[4] >> buf[5]) { + while (packet >> targetId >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> buf[4] >> buf[5] >> playerName) { if (_players.count(targetId)) { - std::string name = "Player_" + std::to_string(targetId); + std::string tagName = "Player_" + std::to_string(targetId); // old approach (no animation): //_players[targetId]->translateToPoint(Vec3D{buf[0], buf[1], buf[2]}); // new approach (linear extrapolational animations) double duration = 1.0 / Consts::NETWORK_WORLD_UPDATE_RATE; - Timeline::animate(AnimationListTag(name + "_linearTranslation"), new ATranslateToPoint(_players[targetId], Vec3D{buf[0], buf[1], buf[2]}, duration, Animation::LoopOut::None, Animation::InterpolationType::linear)); + Timeline::animate(AnimationListTag(tagName + "_linearTranslation"), new ATranslateToPoint(_players[targetId], Vec3D{buf[0], buf[1], buf[2]}, duration, Animation::LoopOut::None, Animation::InterpolationType::linear)); _players[targetId]->setHealth(buf[3]); _players[targetId]->rotateToAngle(Vec3D{0, buf[4], 0}); + _players[targetId]->setPlayerName(playerName); auto head = _players[targetId]->attached(ObjectNameTag("head")); auto weapon = _players[targetId]->attached(ObjectNameTag("Weapon")); diff --git a/Client.h b/Client.h index 6f4ddb9..e34394f 100644 --- a/Client.h +++ b/Client.h @@ -50,6 +50,7 @@ public: void changeWeapon(const std::string& weaponName); void addPlayer(sf::Uint16 id, std::shared_ptr player); + std::map>const & players() const { return _players; } }; diff --git a/Player.h b/Player.h index 6c58b15..1eb7bc6 100644 --- a/Player.h +++ b/Player.h @@ -30,6 +30,8 @@ private: std::vector> _weapons; size_t _selectedWeapon = 0; + std::string _name = ShooterConsts::PLAYER_NAME; + std::function _damagePlayerCallBack; std::function _addTraceCallBack; std::function _takeBonusCallBack; @@ -94,6 +96,9 @@ public: [[nodiscard]] double headAngle() const { return _headAngle; }; void collisionWithObject(const ObjectNameTag& tag, std::shared_ptr obj); + + [[nodiscard]] std::string playerName() const { return _name; } + void setPlayerName(const std::string& name) { _name = name; } }; diff --git a/Server.cpp b/Server.cpp index 8d500cd..282f270 100644 --- a/Server.cpp +++ b/Server.cpp @@ -9,8 +9,8 @@ void Server::broadcast() { sf::Packet updatePacket; updatePacket << MsgType::Update; - for (auto& player : _players) { - updatePacket << player.first << player.second->position().x() << player.second->position().y() << player.second->position().z() << player.second->health() << player.second->angle().y() << player.second->headAngle(); + for (auto& [playerId, player] : _players) { + updatePacket << playerId << player->position().x() << player->position().y() << player->position().z() << player->health() << player->angle().y() << player->headAngle() << player->playerName(); } for (auto& player : _players) { @@ -47,11 +47,13 @@ void Server::processConnect(sf::Uint16 targetId) { void Server::processClientUpdate(sf::Uint16 senderId, sf::Packet& packet) { double buf[5]; + std::string playerName; - packet >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> buf[4]; + packet >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> buf[4] >> playerName; _players.at(senderId)->translateToPoint(Vec3D{ buf[0], buf[1], buf[2] }); _players.at(senderId)->rotateToAngle(Vec3D{0, buf[3], 0}); _players.at(senderId)->setHeadAngle(buf[4]); + _players.at(senderId)->setPlayerName(playerName); } void Server::processDisconnect(sf::Uint16 senderId) { @@ -138,31 +140,31 @@ void Server::processStop() { } void Server::generateBonuses() { - _bonuses.insert({"Bonus_gun_1", std::make_shared(BonusInfo{Vec3D(-10, -2, -15), -2*_bonusRechargeTime, true})}); - _bonuses.insert({"Bonus_gun_2", std::make_shared(BonusInfo{Vec3D(10, -2, 15), -2*_bonusRechargeTime, true})}); + _bonuses.insert({"Bonus_gun_1", std::make_shared(BonusInfo{Vec3D(-10, -2, -15), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); + _bonuses.insert({"Bonus_gun_2", std::make_shared(BonusInfo{Vec3D(10, -2, 15), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); - _bonuses.insert({"Bonus_shotgun_1", std::make_shared(BonusInfo{Vec3D(-10, 13, -24), -2*_bonusRechargeTime, true})}); - _bonuses.insert({"Bonus_shotgun_2", std::make_shared(BonusInfo{Vec3D(10, 13, 24), -2*_bonusRechargeTime, true})}); + _bonuses.insert({"Bonus_shotgun_1", std::make_shared(BonusInfo{Vec3D(-10, 13, -24), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); + _bonuses.insert({"Bonus_shotgun_2", std::make_shared(BonusInfo{Vec3D(10, 13, 24), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); - _bonuses.insert({"Bonus_ak47_1", std::make_shared(BonusInfo{Vec3D(-25, 30, 50), -2*_bonusRechargeTime, true})}); - _bonuses.insert({"Bonus_ak47_2", std::make_shared(BonusInfo{Vec3D(25, 30, -50), -2*_bonusRechargeTime, true})}); + _bonuses.insert({"Bonus_ak47_1", std::make_shared(BonusInfo{Vec3D(-25, 30, 50), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); + _bonuses.insert({"Bonus_ak47_2", std::make_shared(BonusInfo{Vec3D(25, 30, -50), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); - _bonuses.insert({"Bonus_gold_ak47_1", std::make_shared(BonusInfo{Vec3D(-35, 80, 25), -2*_bonusRechargeTime, true})}); - _bonuses.insert({"Bonus_gold_ak47_2", std::make_shared(BonusInfo{Vec3D(35, 80, -25), -2*_bonusRechargeTime, true})}); + _bonuses.insert({"Bonus_gold_ak47_1", std::make_shared(BonusInfo{Vec3D(-35, 80, 25), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); + _bonuses.insert({"Bonus_gold_ak47_2", std::make_shared(BonusInfo{Vec3D(35, 80, -25), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); - _bonuses.insert({"Bonus_rifle_1", std::make_shared(BonusInfo{Vec3D(40, -2, 45), -2*_bonusRechargeTime, true})}); - _bonuses.insert({"Bonus_rifle_2", std::make_shared(BonusInfo{Vec3D(-40, -2, -45), -2*_bonusRechargeTime, true})}); + _bonuses.insert({"Bonus_rifle_1", std::make_shared(BonusInfo{Vec3D(40, -2, 45), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); + _bonuses.insert({"Bonus_rifle_2", std::make_shared(BonusInfo{Vec3D(-40, -2, -45), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); - _bonuses.insert({"Bonus_hill_1", std::make_shared(BonusInfo{Vec3D(-40, -2, 45), -2*_bonusRechargeTime, true})}); - _bonuses.insert({"Bonus_hill_2", std::make_shared(BonusInfo{Vec3D(40, -2, -45), -2*_bonusRechargeTime, true})}); + _bonuses.insert({"Bonus_hill_1", std::make_shared(BonusInfo{Vec3D(-40, -2, 45), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); + _bonuses.insert({"Bonus_hill_2", std::make_shared(BonusInfo{Vec3D(40, -2, -45), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); - _bonuses.insert({"Bonus_ability_1", std::make_shared(BonusInfo{Vec3D(25, 18, -33), -2*_bonusRechargeTime, true})}); - _bonuses.insert({"Bonus_ability_2", std::make_shared(BonusInfo{Vec3D(-25, 18, 33), -2*_bonusRechargeTime, true})}); + _bonuses.insert({"Bonus_ability_1", std::make_shared(BonusInfo{Vec3D(25, 18, -33), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); + _bonuses.insert({"Bonus_ability_2", std::make_shared(BonusInfo{Vec3D(-25, 18, 33), -2*ShooterConsts::BONUS_RECHARGE_TIME, true})}); } void Server::updateInfo() { for(auto& [bonusName, bonusInfo] : _bonuses) { - if(!bonusInfo->onTheMap && std::abs(Time::time() - bonusInfo->lastTake) > _bonusRechargeTime) { + if(!bonusInfo->onTheMap && std::abs(Time::time() - bonusInfo->lastTake) > ShooterConsts::BONUS_RECHARGE_TIME) { sf::Packet sendPacket; sendPacket << MsgType::AddBonus << bonusName << bonusInfo->position.x() << bonusInfo->position.y() << bonusInfo->position.z(); for (const auto& player : _players) diff --git a/Server.h b/Server.h index 952d94c..712fc37 100644 --- a/Server.h +++ b/Server.h @@ -19,8 +19,6 @@ class Server final : public ServerUDP { private: std::map> _players{}; std::map> _bonuses{}; - double _bonusRechargeTime = 60; - public: Server() = default; diff --git a/Shooter.cpp b/Shooter.cpp index 9840951..bc55af6 100644 --- a/Shooter.cpp +++ b/Shooter.cpp @@ -21,17 +21,19 @@ void Shooter::InitNetwork() std::string clientIp; sf::Uint16 clientPort; sf::Uint16 serverPort; + std::string playerName; std::ifstream connectFile("connect.txt", std::ifstream::in); // If failed to read client settings - if (!connectFile.is_open() || !(connectFile >> clientIp >> clientPort) || sf::IpAddress(clientIp) == sf::IpAddress::None) + if (!connectFile.is_open() || !(connectFile >> clientIp >> clientPort >> playerName) || sf::IpAddress(clientIp) == sf::IpAddress::None) { connectFile.close(); // Create file and write default settings clientIp = "127.0.0.1"; clientPort = 54000; + playerName = "PlayerName"; std::ofstream temp("connect.txt", std::ofstream::out); - temp << clientIp << std::endl << clientPort; + temp << clientIp << std::endl << clientPort << std::endl << playerName; temp.close(); } connectFile.close(); @@ -56,6 +58,7 @@ void Shooter::InitNetwork() } client->connect(clientIp, clientPort); + player->setPlayerName(playerName); // TODO: encapsulate call backs inside Client client->setSpawnPlayerCallBack([this](sf::Uint16 id){ spawnPlayer(id); }); @@ -68,7 +71,7 @@ void Shooter::InitNetwork() void Shooter::start() { // This code executed once in the beginning: - //setDebugText(false); + setDebugText(false); setUpdateWorld(false); mouse->setMouseCursorVisible(true); @@ -122,7 +125,6 @@ void Shooter::start() { mainMenu.addButton(screen->width()/2, 350, 200, 20, [this] () { this->player->translateToPoint(Vec3D{0, 0, 0}); this->player->setVelocity({}); this->play(); SoundController::playSound(SoundTag("click"), ShooterConsts::CLICK_SOUND);}, "Respawn", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255}); mainMenu.addButton(screen->width()/2, 500, 200, 20, [this] () { client->disconnect(); server->stop(); this->exit();}, "Exit", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255}); - } void Shooter::update() { @@ -162,11 +164,31 @@ void Shooter::gui() { sprite.setTextureRect(sf::IntRect(243, 3, 9, 9)); sprite.scale(3, 3); sprite.setPosition(screen->width() / 2.0f - 27.0f/2.0f, screen->height() / 2.0f - 27.0f/2.0f); - sprite.setColor(sf::Color(0, 0, 0, 200)); + sprite.setColor(sf::Color(0, 0, 0, 250)); screen->drawSprite(sprite); // health player stats drawPlayerStats(); + drawStatsTable(); +} + +void Shooter::drawStatsTable() { + int i = 0; + + vector> allPlayers; + allPlayers.push_back(player); + for(auto& [playerId, player] : client->players()) + allPlayers.push_back(player); + + std::sort(allPlayers.begin(), allPlayers.end(), [](std::shared_ptr p1, std::shared_ptr p2){ + return p1->kills() - p1->deaths() > p2->kills() - p2->deaths(); + } ); + + for(auto& p : allPlayers) { + screen->drawText(std::to_string(i + 1) + "\t" + p->playerName() + "\t" + std::to_string(p->kills()) + " / " + std::to_string(p->deaths()), + Vec2D{10, 10 + 35.0*i}, 25, sf::Color(0, 0, 0, 150)); + i++; + } } void Shooter::drawPlayerStats() { @@ -194,8 +216,8 @@ void Shooter::drawPlayerStats() { screen->drawText(std::to_string((int)balance.first), Vec2D{150, static_cast(screen->height() - 150)}, 100, sf::Color(0, 0, 0, 100)); screen->drawText(std::to_string((int)balance.second), Vec2D{50, static_cast(screen->height() - 100)}, 50, sf::Color(0, 0, 0, 70)); - screen->drawText("KILLS: " + std::to_string(player->kills()) + " | " + "DEATHS: " + std::to_string(player->deaths()), - Vec2D{10, 10},25, sf::Color(0, 0, 0, 100)); + //screen->drawText("KILLS: " + std::to_string(player->kills()) + " | " + "DEATHS: " + std::to_string(player->deaths()), + // Vec2D{10, 10},25, sf::Color(0, 0, 0, 100)); } void Shooter::play() { @@ -265,6 +287,7 @@ void Shooter::addBonus(const string &bonusName, const Vec3D &position) { void Shooter::removeBonus(const ObjectNameTag &bonusName) { world->removeBody(bonusName); + Timeline::deleteAnimationList(AnimationListTag(bonusName.str() + "_rotation")); } void Shooter::addWeapon(std::shared_ptr weapon) { diff --git a/Shooter.h b/Shooter.h index 969bf5f..23e631f 100644 --- a/Shooter.h +++ b/Shooter.h @@ -39,6 +39,7 @@ private: void play(); void drawPlayerStats(); + void drawStatsTable(); void InitNetwork(); void spawnPlayer(sf::Uint16 id); diff --git a/ShooterConsts.h b/ShooterConsts.h index 6dd8b38..c8ad50e 100644 --- a/ShooterConsts.h +++ b/ShooterConsts.h @@ -14,7 +14,9 @@ namespace ShooterConsts { const double MOUSE_SENSITIVITY = 1.0 / 1000.0; const double SLOW_MO_COEFFICIENT = 5; const double FIRE_DISTANCE = 1000; + const double BONUS_RECHARGE_TIME = 30; + const std::string PLAYER_NAME = "Player"; const std::string PROJECT_NAME = "Shooter"; const std::string ABILITY_OBJ = "obj/ability.obj";