diff --git a/Player.cpp b/Player.cpp index 9c76211..c9debae 100644 --- a/Player.cpp +++ b/Player.cpp @@ -60,7 +60,7 @@ void Player::collisionWithObject(const ObjectNameTag &tag, std::shared_ptr weapon) { - SoundController::playSound(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND); + SoundController::loadAndPlay(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND); for (auto &w : _weapons) { if (w->name() == weapon->name()) { @@ -125,7 +125,7 @@ void Player::selectNextWeapon() { _addWeaponCallBack(_weapons[_selectedWeapon]); } Log::log("selectedWeapon " + std::to_string(_selectedWeapon)); - SoundController::playSound(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND); + SoundController::loadAndPlay(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND); } } @@ -144,7 +144,7 @@ void Player::selectPreviousWeapon() { _addWeaponCallBack(_weapons[_selectedWeapon]); } Log::log("selectedWeapon " + std::to_string(_selectedWeapon)); - SoundController::playSound(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND); + SoundController::loadAndPlay(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND); } } @@ -169,10 +169,10 @@ void Player::reload() { void Player::setFullHealth() { _health = ShooterConsts::HEALTH_MAX; - SoundController::playSound(SoundTag("addHealth"), ShooterConsts::RESTORE_HEALTH_SOUND); + SoundController::loadAndPlay(SoundTag("addHealth"), ShooterConsts::RESTORE_HEALTH_SOUND); } void Player::setFullAbility() { _ability = ShooterConsts::ABILITY_MAX; - SoundController::playSound(SoundTag("addAbility"), ShooterConsts::RESTORE_ABILITY_SOUND); + SoundController::loadAndPlay(SoundTag("addAbility"), ShooterConsts::RESTORE_ABILITY_SOUND); } diff --git a/PlayerController.cpp b/PlayerController.cpp index 42b21ac..145e181 100644 --- a/PlayerController.cpp +++ b/PlayerController.cpp @@ -28,7 +28,7 @@ void PlayerController::update() { _player->setAcceleration( _player->acceleration() * ShooterConsts::SLOW_MO_COEFFICIENT * ShooterConsts::SLOW_MO_COEFFICIENT); SoundController::stopSound(SoundTag("slowMo")); - SoundController::playSound(SoundTag("unSlowMo"), ShooterConsts::UN_SLOW_MO_SOUND); + SoundController::loadAndPlay(SoundTag("unSlowMo"), ShooterConsts::UN_SLOW_MO_SOUND); } } @@ -128,13 +128,13 @@ void PlayerController::update() { (ShooterConsts::SLOW_MO_COEFFICIENT * ShooterConsts::SLOW_MO_COEFFICIENT), 0)); SoundController::stopSound(SoundTag("unSlowMo")); - SoundController::playSound(SoundTag("slowMo"), ShooterConsts::SLOW_MO_SOUND); + SoundController::loadAndPlay(SoundTag("slowMo"), ShooterConsts::SLOW_MO_SOUND); } else if (_isInSlowMo && !Keyboard::isKeyPressed(sf::Keyboard::LShift)) { _isInSlowMo = false; _player->setVelocity(_player->velocity() * ShooterConsts::SLOW_MO_COEFFICIENT); _player->setAcceleration(Vec3D(0, -ShooterConsts::GRAVITY, 0)); SoundController::stopSound(SoundTag("slowMo")); - SoundController::playSound(SoundTag("unSlowMo"), ShooterConsts::UN_SLOW_MO_SOUND); + SoundController::loadAndPlay(SoundTag("unSlowMo"), ShooterConsts::UN_SLOW_MO_SOUND); } if (Mouse::isButtonPressed(sf::Mouse::Button::Left)) { @@ -209,7 +209,7 @@ void PlayerController::update() { } if ((_inRunning || _player->velocity().sqrAbs() > 3) && _player->inCollision() && !walkSoundPlayed) { int soundNum = (int) ((double) rand() / RAND_MAX * 6) + 1; - SoundController::playSound(SoundTag("walkSound_" + std::to_string(soundNum)), + SoundController::loadAndPlay(SoundTag("walkSound_" + std::to_string(soundNum)), "sound/stonestep" + std::to_string(soundNum) + ".ogg"); } } diff --git a/README.md b/README.md index ca94a3c..f2af94c 100644 --- a/README.md +++ b/README.md @@ -29,19 +29,20 @@ Source code of simple shooter on [3Dzavr game engine](https://github.com/vectoza

Control:

-SHIFT - slow motion (this ability is not infinite: its bar is next to hp) +Mouse, Space, A, S, W, D – player control. -E & Q or keys <- -> - change weapon +SHIFT – slow motion (this ability is not infinite: its bar is next to hp) -R - recharge +E & Q or keys <- -> – change weapon -Player control is standard. +R – recharge + +O – turn OpenGL on/off + +Tab – turn debug mode on/off

Playing with a source code:

-Structure: -![Project demonstration](img/structure.png) - 1) [Download and install OpenAL library](https://openal.org/downloads/) for SFML sound support (in current version you can't setup this engine without OpenAL) 2) Clone this repository @@ -56,7 +57,8 @@ Structure: P/S: SFML for 32-bit OS Windows is already included into this repository. So, you don't need to manually install it to your computer. If you have any problems with SFML, you can try to [download another version or build SFML by yourself.](https://www.sfml-dev.org/download.php) -Demos: +Structure: +![Project demonstration](img/structure.png) Online: ![Project demonstration](img/gamePlay4.png) diff --git a/Shooter.cpp b/Shooter.cpp index ab28fa6..8dbef0a 100644 --- a/Shooter.cpp +++ b/Shooter.cpp @@ -113,14 +113,14 @@ void Shooter::start() { mainMenu.addButton(screen->width() / 2, 200, 200, 20, [this]() { this->play(); - SoundController::playSound(SoundTag("click"), ShooterConsts::CLICK_SOUND); + SoundController::loadAndPlay(SoundTag("click"), ShooterConsts::CLICK_SOUND); }, "Server: " + client->serverIp().toString(), 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255}); 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); + SoundController::loadAndPlay(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]() { @@ -173,7 +173,7 @@ void Shooter::update() { // background sounds and music control if (SoundController::getStatus(SoundTag("background")) != sf::Sound::Status::Playing) { - SoundController::playSound(SoundTag("background"), ShooterConsts::BACK_NOISE); + SoundController::loadAndPlay(SoundTag("background"), ShooterConsts::BACK_NOISE); } } @@ -280,9 +280,9 @@ void Shooter::spawnPlayer(sf::Uint16 id) { int colorBodyNum = static_cast (static_cast((rand() - 1)) / RAND_MAX * 5.0); int colorFootNum = static_cast (static_cast((rand() - 1)) / RAND_MAX * 5.0); - newPlayer->setColor(ShooterConsts::WHITE_COLORS[colorBodyNum]); - world->body(ObjectNameTag(name + "_foot_1"))->setColor(ShooterConsts::DARK_COLORS[colorFootNum]); - world->body(ObjectNameTag(name + "_foot_2"))->setColor(ShooterConsts::DARK_COLORS[colorFootNum]); + newPlayer->setColor(Consts::WHITE_COLORS[colorBodyNum]); + world->body(ObjectNameTag(name + "_foot_1"))->setColor(Consts::DARK_COLORS[colorFootNum]); + world->body(ObjectNameTag(name + "_foot_2"))->setColor(Consts::DARK_COLORS[colorFootNum]); changeEnemyWeapon("gun", id); } diff --git a/ShooterClient.cpp b/ShooterClient.cpp index becdafd..536830f 100644 --- a/ShooterClient.cpp +++ b/ShooterClient.cpp @@ -19,17 +19,17 @@ void ShooterClient::updatePacket() { void ShooterClient::processInit(sf::Packet &packet) { sf::Uint16 targetId; - double buf[4]; + double x, y, z, health; int kills, deaths; - while (packet >> targetId >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> kills >> deaths) { + while (packet >> targetId >> x >> y >> z >> health >> kills >> deaths) { if (targetId != _socket.ownId()) { if (_spawnPlayerCallBack != nullptr) { _spawnPlayerCallBack(targetId); } - _players[targetId]->translateToPoint(Vec3D{buf[0], buf[1], buf[2]}); - _players[targetId]->setHealth(buf[3]); + _players[targetId]->translateToPoint(Vec3D{x, y, z}); + _players[targetId]->setHealth(health); _players[targetId]->setKills(kills); _players[targetId]->setDeaths(deaths); } @@ -38,21 +38,21 @@ void ShooterClient::processInit(sf::Packet &packet) { void ShooterClient::processUpdate(sf::Packet &packet) { sf::Uint16 targetId; - double buf[6]; + double x, y, z, health, bodyAngle, headAngle; std::string playerName; - while (packet >> targetId >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> buf[4] >> buf[5] >> playerName) { + while (packet >> targetId >> x >> y >> z >> health >> bodyAngle >> headAngle >> playerName) { if (_players.count(targetId)) { std::string name = "Enemy_" + std::to_string(targetId); - Vec3D newPosition = Vec3D{buf[0], buf[1], buf[2]}; + Vec3D newPosition = Vec3D{x, y, z}; bool isAnimate = (_players[targetId]->position() - newPosition).sqrAbs() > 0.2; _players[targetId]->translateToPoint(newPosition); - _players[targetId]->setHealth(buf[3]); - _players[targetId]->rotateToAngle(Vec3D{0, buf[4], 0}); + _players[targetId]->setHealth(health); + _players[targetId]->rotateToAngle(Vec3D{0, bodyAngle, 0}); _players[targetId]->setPlayerNickName(playerName); auto head = _players[targetId]->attached(ObjectNameTag(name + "_head")); @@ -62,10 +62,10 @@ void ShooterClient::processUpdate(sf::Packet &packet) { auto foot2 = _players[targetId]->attached(ObjectNameTag(name + "_foot_2")); if (head != nullptr) { - head->rotateLeft(buf[5] - _players[targetId]->headAngle()); + head->rotateLeft(headAngle - _players[targetId]->headAngle()); } if (weapon != nullptr) { - weapon->rotateLeft(buf[5] - _players[targetId]->headAngle()); + weapon->rotateLeft(headAngle - _players[targetId]->headAngle()); } if (isAnimate) { @@ -97,9 +97,9 @@ void ShooterClient::processUpdate(sf::Packet &packet) { } } - _players[targetId]->setHeadAngle(buf[5]); + _players[targetId]->setHeadAngle(headAngle); } else if (targetId == _socket.ownId()) { - _player->setHealth(buf[3]); + _player->setHealth(health); } } } @@ -136,7 +136,7 @@ void ShooterClient::processCustomPacket(sf::Packet &packet) { _lastEvent = ""; if (buffId[1] == _socket.ownId()) { _player->addKill(); - SoundController::playSound(SoundTag("kill"), ShooterConsts::KILL_SOUND); + SoundController::loadAndPlay(SoundTag("kill"), ShooterConsts::KILL_SOUND); _lastEvent += _player->playerNickName(); } else { _players[buffId[1]]->addKill(); @@ -182,7 +182,7 @@ void ShooterClient::processCustomPacket(sf::Packet &packet) { }, 1, 0.1); - SoundController::playSound(SoundTag("death"), ShooterConsts::DEATH_SOUND); + SoundController::loadAndPlay(SoundTag("death"), ShooterConsts::DEATH_SOUND); _lastEvent += _player->playerNickName(); } else { _players[buffId[0]]->addDeath(); diff --git a/ShooterConsts.h b/ShooterConsts.h index 24a4c92..31619d8 100644 --- a/ShooterConsts.h +++ b/ShooterConsts.h @@ -60,22 +60,6 @@ namespace ShooterConsts { const std::string SLOW_MO_SOUND = "sound/slow_mo.ogg"; const std::string UN_SLOW_MO_SOUND = "sound/unslow_mo.ogg"; const std::string NO_AMMO_SOUND = "sound/weapons/no_ammo.ogg"; - - const sf::Color WHITE_COLORS[] = { - sf::Color(137, 135, 222), // blue - sf::Color(195, 155, 209), // pink - sf::Color(201, 137, 137), // red - sf::Color(116, 204, 135), // green - sf::Color(201, 171, 137), // orange - }; - - const sf::Color DARK_COLORS[] = { - sf::Color(16, 18, 69), // blue - sf::Color(77, 0, 62), // pink - sf::Color(99, 20, 20), // red - sf::Color(12, 46, 9), // green - sf::Color(97, 70, 51), // orange - }; } #endif //SHOOTER_SHOOTERCONSTS_H diff --git a/ShooterServer.cpp b/ShooterServer.cpp index f66cae7..f72b56f 100644 --- a/ShooterServer.cpp +++ b/ShooterServer.cpp @@ -49,13 +49,15 @@ void ShooterServer::processConnect(sf::Uint16 targetId) { } void ShooterServer::processClientUpdate(sf::Uint16 senderId, sf::Packet &packet) { - double buf[5]; + double x, y, z, angleBody, headAngle; + std::string playerName; - 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]); + packet >> x >> y >> z >> angleBody >> headAngle >> playerName; + + _players.at(senderId)->translateToPoint(Vec3D{x, y, z}); + _players.at(senderId)->rotateToAngle(Vec3D{0, angleBody, 0}); + _players.at(senderId)->setHeadAngle(headAngle); _players.at(senderId)->setPlayerNickName(playerName); } diff --git a/engine/Consts.h b/engine/Consts.h index 6edb3cd..7282b0e 100644 --- a/engine/Consts.h +++ b/engine/Consts.h @@ -39,6 +39,22 @@ namespace Consts { const int NETWORK_WORLD_UPDATE_RATE = 30; const double NETWORK_RELIABLE_RETRY_TIME = 1.0 / 20; const uint16_t NETWORK_MAX_CLIENTS = 64; + + const sf::Color WHITE_COLORS[] = { + sf::Color(137, 135, 222), // blue + sf::Color(195, 155, 209), // pink + sf::Color(201, 137, 137), // red + sf::Color(116, 204, 135), // green + sf::Color(201, 171, 137), // orange + }; + + const sf::Color DARK_COLORS[] = { + sf::Color(16, 18, 69), // blue + sf::Color(77, 0, 62), // pink + sf::Color(99, 20, 20), // red + sf::Color(12, 46, 9), // green + sf::Color(97, 70, 51), // orange + }; } #endif //SHOOTER_CONSTS_H diff --git a/engine/Object.cpp b/engine/Object.cpp index 5f25df9..c107538 100644 --- a/engine/Object.cpp +++ b/engine/Object.cpp @@ -149,20 +149,24 @@ void Object::unattach(const ObjectNameTag &tag) { GLfloat *Object::glInvModel() const { auto *v = new GLfloat[4 * 4]; - v[0] = -static_cast(left().x()); - v[4] = -static_cast(left().y()); - v[8] = -static_cast(left().z()); - v[12] = static_cast(position().dot(left())); + Vec3D _left = _transformMatrix.x(); + Vec3D _up = _transformMatrix.y(); + Vec3D _lookAt = _transformMatrix.z(); - v[1] = static_cast(up().x()); - v[5] = static_cast(up().y()); - v[9] = static_cast(up().z()); - v[13] = -static_cast(position().dot(up())); + v[0] = -static_cast(_left.x()); + v[4] = -static_cast(_left.y()); + v[8] = -static_cast(_left.z()); + v[12] = static_cast(position().dot(_left)); - v[2] = -static_cast(lookAt().x()); - v[6] = -static_cast(lookAt().y()); - v[10] = -static_cast(lookAt().z()); - v[14] = static_cast(position().dot(lookAt())); + v[1] = static_cast(_up.x()); + v[5] = static_cast(_up.y()); + v[9] = static_cast(_up.z()); + v[13] = -static_cast(position().dot(_up)); + + v[2] = -static_cast(_lookAt.x()); + v[6] = -static_cast(_lookAt.y()); + v[10] = -static_cast(_lookAt.z()); + v[14] = static_cast(position().dot(_lookAt)); v[3] = static_cast(0.0f); v[7] = static_cast(0.0f); @@ -175,19 +179,23 @@ GLfloat *Object::glInvModel() const { GLfloat *Object::glModel() const { auto *m = new GLfloat[4 * 4]; - m[0] = static_cast(left().x()); - m[4] = static_cast(up().x()); - m[8] = static_cast(lookAt().x()); + Vec3D _left = _transformMatrix.x(); + Vec3D _up = _transformMatrix.y(); + Vec3D _lookAt = _transformMatrix.z(); + + m[0] = static_cast(_left.x()); + m[4] = static_cast(_up.x()); + m[8] = static_cast(_lookAt.x()); m[12] = static_cast(position().x()); - m[1] = static_cast(left().y()); - m[5] = static_cast(up().y()); - m[9] = static_cast(lookAt().y()); + m[1] = static_cast(_left.y()); + m[5] = static_cast(_up.y()); + m[9] = static_cast(_lookAt.y()); m[13] = static_cast(position().y()); - m[2] = static_cast(left().z()); - m[6] = static_cast(up().z()); - m[10] = static_cast(lookAt().z()); + m[2] = static_cast(_left.z()); + m[6] = static_cast(_up.z()); + m[10] = static_cast(_lookAt.z()); m[14] = static_cast(position().z()); m[3] = static_cast(0.0f); diff --git a/engine/Object.h b/engine/Object.h index abadd6f..7c802f1 100644 --- a/engine/Object.h +++ b/engine/Object.h @@ -73,9 +73,9 @@ public: void rotateUp(double ru); void rotateLookAt(double rlAt); - [[nodiscard]] Vec3D left() const { return _transformMatrix.x(); } - [[nodiscard]] Vec3D up() const { return _transformMatrix.y(); } - [[nodiscard]] Vec3D lookAt() const { return _transformMatrix.z(); } + [[nodiscard]] Vec3D left() const { return _transformMatrix.x().normalized(); } + [[nodiscard]] Vec3D up() const { return _transformMatrix.y().normalized(); } + [[nodiscard]] Vec3D lookAt() const { return _transformMatrix.z().normalized(); } [[nodiscard]] Vec3D position() const { return _position; } [[nodiscard]] Vec3D angle() const { return _angle; } [[nodiscard]] Vec3D angleLeftUpLookAt() const { return _angleLeftUpLookAt; } diff --git a/engine/SoundController.cpp b/engine/SoundController.cpp index 16bc162..28f08ca 100644 --- a/engine/SoundController.cpp +++ b/engine/SoundController.cpp @@ -16,15 +16,27 @@ void SoundController::init() { Log::log("SoundController::init(): sound controller was initialized"); } -void SoundController::playSound(const SoundTag &soundTag, const std::string &filename) { +void SoundController::loadAndPlay(const SoundTag &soundTag, const std::string& filename) { + if (_instance == nullptr) { + return; + } + if (_instance->_sounds.count(soundTag) != 0) { + _instance->_sounds[soundTag] = sf::Sound(*ResourceManager::loadSoundBuffer(filename)); + } else { + _instance->_sounds.emplace(soundTag, sf::Sound(*ResourceManager::loadSoundBuffer(filename))); + } + + _instance->_sounds[soundTag].play(); +} + +void SoundController::playSound(const SoundTag &soundTag) { if (_instance == nullptr) { return; } - if (_instance->_sounds.count(soundTag) == 0) { - _instance->_sounds.emplace(soundTag, sf::Sound(*ResourceManager::loadSoundBuffer(filename))); + if (_instance->_sounds.count(soundTag) != 0) { + _instance->_sounds[soundTag].play(); } - _instance->_sounds[soundTag].play(); } void SoundController::pauseSound(const SoundTag &soundTag) { diff --git a/engine/SoundController.h b/engine/SoundController.h index db3cce9..45fca4a 100644 --- a/engine/SoundController.h +++ b/engine/SoundController.h @@ -38,10 +38,10 @@ public: SoundController &operator=(SoundController &) = delete; - static void playSound(const SoundTag &soundTag, const std::string &filename); + static void loadAndPlay(const SoundTag &soundTag, const std::string& filename); + static void playSound(const SoundTag &soundTag); static void pauseSound(const SoundTag &soundTag); - static void stopSound(const SoundTag &soundTag); static sf::Sound::Status getStatus(const SoundTag &soundTag); diff --git a/engine/Triangle.h b/engine/Triangle.h index d474c08..7a32d64 100644 --- a/engine/Triangle.h +++ b/engine/Triangle.h @@ -29,6 +29,8 @@ public: [[nodiscard]] const Vec4D& operator[](int i) const; + [[nodiscard]] Vec3D position() const { return Vec3D(_points[0] + _points[1] + _points[2])/3; } + [[nodiscard]] Vec3D norm() const; // Operations with Matrix4x4 diff --git a/engine/physics/RigidBody.cpp b/engine/physics/RigidBody.cpp index 1c9cbae..0d1db28 100644 --- a/engine/physics/RigidBody.cpp +++ b/engine/physics/RigidBody.cpp @@ -18,6 +18,10 @@ RigidBody::RigidBody(ObjectNameTag nameTag, const std::string &filename, const V RigidBody::RigidBody(const Mesh &mesh, bool useSimpleBox) : Mesh(mesh), _hitBox(mesh, useSimpleBox) { } +void RigidBody::regenerateHitBox(bool useSimpleBox) { + _hitBox = HitBox(*this, useSimpleBox); +} + Vec3D RigidBody::_findFurthestPoint(const Vec3D &direction) { Vec3D maxPoint{0, 0, 0}; diff --git a/engine/physics/RigidBody.h b/engine/physics/RigidBody.h index b53fc11..98d02a3 100644 --- a/engine/physics/RigidBody.h +++ b/engine/physics/RigidBody.h @@ -70,6 +70,8 @@ public: [[nodiscard]] CollisionPoint EPA(const Simplex &simplex, std::shared_ptr obj); void solveCollision(const CollisionPoint &collision); + void regenerateHitBox(bool useSimpleBox = true); + [[nodiscard]] Vec3D collisionNormal() const { return _collisionNormal; } [[nodiscard]] bool hasCollision() const { return _hasCollision; } [[nodiscard]] bool inCollision() const { return _inCollision; } diff --git a/weapon/Weapon.cpp b/weapon/Weapon.cpp index a72dd52..649849e 100644 --- a/weapon/Weapon.cpp +++ b/weapon/Weapon.cpp @@ -31,7 +31,7 @@ FireInformation Weapon::fire(std::function