diff --git a/CMakeLists.txt b/CMakeLists.txt index 391c569..f422a17 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ add_executable(shooter engine/network/UDPSocket.h engine/network/config.h engine/animation/AFunction.h - ) + PlayerController.cpp PlayerController.h engine/Keyboard.cpp engine/Keyboard.h engine/Mouse.cpp engine/Mouse.h) if(APPLE OR UNIX) include_directories(/usr/local/include) diff --git a/Client.cpp b/Client.cpp index fb50a9a..6b495c0 100755 --- a/Client.cpp +++ b/Client.cpp @@ -128,7 +128,7 @@ void Client::processCustomPacket(MsgType type, sf::Packet& packet) { p2 = Point4D(dbuff[3], dbuff[4], dbuff[5]); tmp = "Client_fireTraces_" + std::to_string(fireTraces++); - _world->addBody(std::make_shared(RigidBody(Mesh::LineTo(p1, p2, 0.05))), tmp); + _world->addBody(std::make_shared(Mesh::LineTo(p1, p2, 0.05)), tmp); _world->body(tmp)->setCollider(false); _world->body(tmp)->a_color(tmp + "_fadeOut", {255, 255, 255, 0}, 1, Animation::None, Animation::linear); diff --git a/Player.cpp b/Player.cpp index 8427d90..cc1188d 100755 --- a/Player.cpp +++ b/Player.cpp @@ -9,161 +9,6 @@ void Player::update() { - // friction - if(inCollision()) - _velocity = _velocity - _velocity * Time::deltaTime() * 2; - - if(_isInSlowMo) { - if(_ability > 0) - _ability -= Time::deltaTime(); - else { - _ability = 0; - _isInSlowMo = false; - setVelocity(velocity() * _slowMoCoefficient); - setAcceleration(_acceleration * _slowMoCoefficient * _slowMoCoefficient); - _slowMoSound.stop(); - _unSlowMoSound.play(); - } - } - - double coeff = _isInSlowMo ? 1.0 / _slowMoCoefficient : 1.0; - - bool inRunning_old = _inRunning; - _inRunning = _screen != nullptr && (Screen::isKeyPressed(sf::Keyboard::A) || Screen::isKeyPressed(sf::Keyboard::D) || Screen::isKeyPressed(sf::Keyboard::W) || Screen::isKeyPressed(sf::Keyboard::S)); - - // in case when the camera is attached we make some animation during running - if(_camera != nullptr && _inRunning && !_camera->isInAnim()) { - _camera->a_translate("hor_oscil", -_camera->left()/12, 0.3/coeff, Animation::LoopOut::None, Animation::cos); - _camera->a_wait("hor_oscil", 0); - _camera->a_translate("hor_oscil", _camera->left()/12, 0.3/coeff, Animation::LoopOut::None, Animation::cos); - - _camera->a_translate("vert_oscil", -Point4D{0, 1, 0}/24, 0.15/coeff, Animation::LoopOut::None, Animation::cos); - _camera->a_wait("vert_oscil", 0); - _camera->a_translate("vert_oscil", Point4D{0, 1, 0}/24, 0.15/coeff, Animation::LoopOut::None, Animation::cos); - _camera->a_wait("vert_oscil", 0); - _camera->a_translate("vert_oscil", -Point4D{0, 1, 0}/24, 0.15/coeff, Animation::LoopOut::None, Animation::cos); - _camera->a_wait("vert_oscil", 0); - _camera->a_translate("vert_oscil", Point4D{0, 1, 0}/24, 0.15/coeff, Animation::LoopOut::None, Animation::cos); - - _camera->a_translateToPoint("init", position() + Point4D{0, 1.8, 0}, 0.3/coeff, Animation::None, Animation::cos); - - } else if(_camera != nullptr && inRunning_old && !_inRunning) { - _camera->a_stopAllAnimations(); - - _camera->a_translateToPoint("init", position() + Point4D{0, 1.8, 0}, 0.15/coeff, Animation::None, Animation::cos); - } - - auto rayToFloor = (*_world).rayCast(position(), position() + Point4D{0, -5, 0}); - - if(_world != nullptr && _screen != nullptr && _camera != nullptr) { - // Left and right - if (Screen::isKeyPressed(sf::Keyboard::A)) { - translate(_camera->left() * Time::deltaTime() * _walkSpeed * coeff); - if(inCollision()) - setVelocity(Point4D{0,0,0}); - } - if (Screen::isKeyPressed(sf::Keyboard::D)) { - translate(-_camera->left() * Time::deltaTime() * _walkSpeed * coeff); - if(inCollision()) - setVelocity(Point4D{0,0,0}); - } - - // Forward and backward - if (Screen::isKeyPressed(sf::Keyboard::W)) { - translate(_camera->left().cross3D(Point4D{0, 1, 0}) * Time::deltaTime() * _walkSpeed * coeff); - if(inCollision()) - setVelocity(Point4D{0,0,0}); - } - - if (Screen::isKeyPressed(sf::Keyboard::S)) { - translate(-_camera->left().cross3D(Point4D{0, 1, 0}) * Time::deltaTime() * _walkSpeed * coeff); - - if(inCollision()) - setVelocity(Point4D{0,0,0}); - } - - if (_ability > 0 && !_isInSlowMo && Screen::isKeyPressed(sf::Keyboard::LShift)) { - // slow mo - _isInSlowMo = true; - setVelocity(velocity() / _slowMoCoefficient); - setAcceleration(_acceleration / (_slowMoCoefficient * _slowMoCoefficient)); - _unSlowMoSound.stop(); - _slowMoSound.play(); - } else if (_isInSlowMo && !Screen::isKeyPressed(sf::Keyboard::LShift)) { - _isInSlowMo = false; - setVelocity(velocity() * _slowMoCoefficient); - setAcceleration(_acceleration * _slowMoCoefficient * _slowMoCoefficient); - _slowMoSound.stop(); - _unSlowMoSound.play(); - } - - if (Screen::isKeyPressed(sf::Keyboard::Space) && inCollision()) { - addVelocity(Point4D{0, std::abs(_collisionNormal.y()) * sqrt(2 * _g * _jumpHeight) * coeff, 0}); - translate(Point4D{0, Time::deltaTime() * _walkSpeed * 2 * coeff, 0}); - } - - // Mouse movement - Point4D disp = _screen->getMouseDisplacement(); - - rotate(Point4D{0, -disp.x() / 1000.0, 0}); - _velocity = Matrix4x4::RotationY(-disp.x() / 1000.0) * _velocity; - - double rotationLeft = disp.y() / 1000.0; - - // You can only see in range [-90 : 90] grad - if (_camera->angleLeftUpLookAt().x() + rotationLeft > M_PI / 2) - rotationLeft = M_PI / 2 - _camera->angleLeftUpLookAt().x(); - if (_camera->angleLeftUpLookAt().x() + rotationLeft < -M_PI / 2) - rotationLeft = -M_PI / 2 - _camera->angleLeftUpLookAt().x(); - - _camera->rotateLeft(rotationLeft); - rotateWeaponsRelativePoint(position() + Point4D{0, 1.8, 0}, _camera->left(), rotationLeft); - - if (_screen->isKeyTapped(sf::Keyboard::Right) || _screen->isKeyTapped(sf::Keyboard::E)) { - if(_weapons.size() > 1) { - // change '_selectedWeapon' - _weapons[_selectedWeapon]->removeFromWorld(_world); - _selectedWeapon = (_selectedWeapon + 1) % _weapons.size(); - _weapons[_selectedWeapon]->addToWorld(_world); - Log::log("selected _selectedWeapon " + std::to_string(_selectedWeapon)); - _changeWeaponSound.play(); - } - } - - if (_screen->isKeyTapped(sf::Keyboard::Left) || _screen->isKeyTapped(sf::Keyboard::Q)) { - if(_weapons.size() > 1) { - // change '_selectedWeapon' - _weapons[_selectedWeapon]->removeFromWorld(_world); - if (_selectedWeapon > 0) - _selectedWeapon = (_selectedWeapon - 1) % _weapons.size(); - else - _selectedWeapon = _weapons.size() - 1; - _weapons[_selectedWeapon]->addToWorld(_world); - Log::log("selected _selectedWeapon " + std::to_string(_selectedWeapon)); - _changeWeaponSound.play(); - } - } - - if (_screen->isButtonPressed(sf::Mouse::Button::Left)) { - auto damagedPlayers = _weapons[_selectedWeapon]->fire(_world, _camera); - for(auto& damagedPlayer : damagedPlayers) { - sf::Uint16 targetId = std::stoi(damagedPlayer.first.substr(7)); - _damagePlayerCallBack(targetId, damagedPlayer.second); - } - } - - if(Screen::isKeyPressed(sf::Keyboard::R)) { - _weapons[_selectedWeapon]->reload(); - } - - if (_inRunning && inCollision() && _walkSound.getStatus() != sf::Sound::Status::Playing) { - if ((position() - rayToFloor.first).abs() < 2) { - int soundNum = round((double) rand() / RAND_MAX * 5) + 1; - _walkSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/stonestep" + std::to_string(soundNum) + ".ogg")); - _walkSound.play(); - } - } - } } void Player::rotateWeaponsRelativePoint(const Point4D& point4D, const Point4D& v, double val) { @@ -172,98 +17,35 @@ void Player::rotateWeaponsRelativePoint(const Point4D& point4D, const Point4D& v } void Player::drawStats() { - if(_screen == nullptr) return; // health bar - int xPos = 10; - int yPos = _screen->height() - 10 - 10; + double xPos = 10; + double yPos = _screen->height() - 10 - 10; - int width = _screen->width()/2 - 20; - int height = 10; + double width = _screen->width()/2 - 20; + double height = 10; - sf::ConvexShape polygon1; - polygon1.setPointCount(4); - sf::ConvexShape polygon2; - polygon2.setPointCount(4); + _screen->drawTetragon(Point4D{xPos, yPos}, + Point4D{xPos + width, yPos}, + Point4D{xPos + width, yPos + height}, + Point4D{xPos, yPos + height}, + { static_cast((_healthMax - _health)/_healthMax * 255), static_cast(_health * 255 / _healthMax), 0, 100 }); - polygon1.setPoint(0, sf::Vector2f((float)xPos, (float)yPos)); - polygon1.setPoint(1, sf::Vector2f((float)(xPos + width), (float)yPos)); - polygon1.setPoint(2, sf::Vector2f((float)(xPos + width), (float)(yPos + height))); - polygon1.setPoint(3, sf::Vector2f((float)xPos, (float)(yPos + height))); - - polygon2.setPoint(0, sf::Vector2f((float)xPos, (float)yPos)); - polygon2.setPoint(1, sf::Vector2f((float)xPos + width * _health / _healthMax, (float)yPos)); - polygon2.setPoint(2, sf::Vector2f((float)xPos + width * _health / _healthMax, (float)(yPos + height))); - polygon2.setPoint(3, sf::Vector2f((float)xPos, (float)(yPos + height))); - - polygon1.setFillColor({ 255, 174, 174, 100 }); - polygon2.setFillColor({ static_cast((_healthMax - _health)/_healthMax * 255), static_cast(_health * 255 / _healthMax), 0, 100 }); - - polygon1.setOutlineThickness(3); - _screen->window.draw(polygon2); - - // ability bar - sf::ConvexShape polygon3; - polygon3.setPointCount(4); - polygon3.setPoint(0, sf::Vector2f((float)xPos, (float)yPos - 15)); - polygon3.setPoint(1, sf::Vector2f((float)xPos + width * _ability / _abilityMax, (float)yPos - 15)); - polygon3.setPoint(2, sf::Vector2f((float)xPos + width * _ability / _abilityMax, (float)(yPos - 15 + height))); - polygon3.setPoint(3, sf::Vector2f((float)xPos, (float)(yPos - 15 + height))); - polygon3.setFillColor({ 255, 168, 168, 100 }); - _screen->window.draw(polygon3); - - // ammo - sf::Text text_health; - - text_health.setFont(*ResourceManager::loadFont("../engine/fonts/Roboto-Medium.ttf")); - - // text health - text_health.setCharacterSize(20); - text_health.setFillColor(sf::Color::White); - text_health.setStyle(sf::Text::Italic); - text_health.setPosition(0, 0); - - text_health.setString(std::to_string((int)_health)); - - // text ammo - sf::Text text_ammo1(text_health); - sf::Text text_ammo2(text_health); - - int ammo1Size = 100; - int ammo2Size = 50; + _screen->drawTetragon(Point4D{xPos, yPos - 15}, + Point4D{xPos + width * _ability / _abilityMax, yPos - 15}, + Point4D{xPos + width * _ability / _abilityMax, yPos - 15 + height}, + Point4D{xPos, yPos - 15 + height}, + { 255, 168, 168, 100 }); auto balance = _weapons[_selectedWeapon]->balance(); - text_ammo1.setCharacterSize(ammo1Size); - text_ammo1.setString(std::to_string((int)balance.first)); - text_ammo1.setPosition(150, _screen->height() - 50 - ammo1Size); - text_ammo1.setFillColor(sf::Color(0, 0, 0, 100)); - _screen->window.draw(text_ammo1); + _screen->drawText(std::to_string((int)balance.first),Point4D{150, static_cast(_screen->height() - 50 - 100)},100, sf::Color(0, 0, 0, 100)); + _screen->drawText(std::to_string((int)balance.second),Point4D{50, static_cast(_screen->height() - 50 - 50)},50, sf::Color(0, 0, 0, 70)); - text_ammo2.setCharacterSize(ammo2Size); - text_ammo2.setString(std::to_string((int)balance.second)); - text_ammo2.setPosition(50, _screen->height() - 50 - ammo2Size); - text_ammo2.setFillColor(sf::Color(0, 0, 0, 70)); - _screen->window.draw(text_ammo2); - - // text _killSound/_deathSound stats - sf::Text text_kills(text_health); - text_kills.setStyle(sf::Text::Bold); - text_kills.setString("KILLS: " + std::to_string((int)_kills) + " | " + "DEATHS: " + std::to_string((int)_deaths)); - text_kills.setFillColor(sf::Color(0, 0, 0, 100)); - text_kills.setCharacterSize(ammo2Size/2); - text_kills.setPosition(10, 10); - - _screen->window.draw(text_kills); - - sf::Text text_deaths(text_health); - - text_deaths.setString(std::to_string((int)_deaths)); - text_deaths.setFillColor(sf::Color(100, 0, 0, 100)); - text_deaths.setCharacterSize(ammo2Size); - text_deaths.setPosition(10, ammo2Size + 10); + _screen->drawText("KILLS: " + std::to_string((int)_kills) + " | " + "DEATHS: " + std::to_string((int)_deaths), + Point4D{10, 10},25, sf::Color(0, 0, 0, 100)); } void Player::playDeath() { @@ -339,3 +121,40 @@ void Player::initWeapons() { _weapons[_selectedWeapon]->addToWorld(_world); } + +void Player::nextWeapon() { + if(_weapons.size() > 1) { + // change '_selectedWeapon' + _weapons[_selectedWeapon]->removeFromWorld(_world); + _selectedWeapon = (_selectedWeapon + 1) % _weapons.size(); + _weapons[_selectedWeapon]->addToWorld(_world); + Log::log("selected _selectedWeapon " + std::to_string(_selectedWeapon)); + _changeWeaponSound.play(); + } +} + +void Player::previousWeapon() { + if(_weapons.size() > 1) { + // change '_selectedWeapon' + _weapons[_selectedWeapon]->removeFromWorld(_world); + if (_selectedWeapon > 0) + _selectedWeapon = (_selectedWeapon - 1) % _weapons.size(); + else + _selectedWeapon = _weapons.size() - 1; + _weapons[_selectedWeapon]->addToWorld(_world); + Log::log("selected _selectedWeapon " + std::to_string(_selectedWeapon)); + _changeWeaponSound.play(); + } +} + +void Player::fire() { + auto damagedPlayers = _weapons[_selectedWeapon]->fire(_world, _camera); + for(auto& damagedPlayer : damagedPlayers) { + sf::Uint16 targetId = std::stoi(damagedPlayer.first.substr(7)); + _damagePlayerCallBack(targetId, damagedPlayer.second); + } +} + +void Player::reload() { + _weapons[_selectedWeapon]->reload(); +} diff --git a/Player.h b/Player.h index d2e7bab..0501573 100755 --- a/Player.h +++ b/Player.h @@ -33,23 +33,15 @@ private: double _g = 35; - double _slowMoCoefficient = 5; - bool _isInSlowMo = false; - std::shared_ptr _camera; std::shared_ptr _screen; std::shared_ptr _world; - bool _inRunning = false; - // sounds sf::Sound _killSound; sf::Sound _deathSound; - sf::Sound _walkSound; sf::Sound _changeWeaponSound; - sf::Sound _slowMoSound; - sf::Sound _unSlowMoSound; sf::Sound _fullHealthSound; sf::Sound _fullAbilitySound; @@ -62,7 +54,6 @@ private: std::function _addTraceCallBack; std::function _takeBonusCallBack; - public: Player() { loadObj("../obj/cube.obj", "", Point4D{0.5, 1.9, 0.5}); @@ -73,9 +64,6 @@ public: _changeWeaponSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/weapons/change_weapon.ogg")); - _slowMoSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/slow_mo.ogg")); - _unSlowMoSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/unslow_mo.ogg")); - _fullHealthSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/fullHealth.ogg")); _fullAbilitySound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/fullAbility.ogg")); @@ -107,6 +95,13 @@ public: _ability = a; } + void nextWeapon(); + void previousWeapon(); + void fire(); + void reload(); + + [[nodiscard]] double ability() const { return _ability; } + void setFullHealth() { _health = _healthMax; _fullHealthSound.play(); @@ -141,7 +136,6 @@ public: void rotateWeaponsRelativePoint(const Point4D& point4D, const Point4D& v, double val); - void drawStats(); void addKill() { _kills++; } diff --git a/PlayerController.cpp b/PlayerController.cpp new file mode 100644 index 0000000..7b463c8 --- /dev/null +++ b/PlayerController.cpp @@ -0,0 +1,152 @@ +// +// Created by Иван Ильин on 19.09.2021. +// + +#include "PlayerController.h" + +PlayerController::PlayerController(std::shared_ptr player, + std::shared_ptr world, + std::shared_ptr keyboard, + std::shared_ptr mouse) : _player(player), _world(world), _keyboard(keyboard), _mouse(mouse) { + _slowMoSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/slow_mo.ogg")); + _unSlowMoSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/unslow_mo.ogg")); + _changeWeaponSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/weapons/change_weapon.ogg")); +} + +void PlayerController::update() { + // friction + if(_player->inCollision()) + _player->setVelocity(_player->velocity()*(1.0 - Time::deltaTime() * 2)); + + if(_isInSlowMo) { + if(_player->ability() > 0) + _player->setAbility(_player->ability() - Time::deltaTime()); + else { + _player->setAbility(0); + _isInSlowMo = false; + _player->setVelocity(_player->velocity() * _slowMoCoefficient); + _player->setAcceleration(_player->acceleration() * _slowMoCoefficient * _slowMoCoefficient); + _slowMoSound.stop(); + _unSlowMoSound.play(); + } + } + + double coeff = _isInSlowMo ? 1.0 / _slowMoCoefficient : 1.0; + + bool inRunning_old = _inRunning; + _inRunning = ( Keyboard::isKeyPressed(sf::Keyboard::A) || + Keyboard::isKeyPressed(sf::Keyboard::D) || + Keyboard::isKeyPressed(sf::Keyboard::W) || + Keyboard::isKeyPressed(sf::Keyboard::S)); + + // in case when the camera is attached we make some animation during running + if(_inRunning && !_player->camera()->isInAnim()) { + _player->camera()->a_translate("hor_oscil", -_player->camera()->left()/12, 0.3/coeff, Animation::LoopOut::None, Animation::cos); + _player->camera()->a_wait("hor_oscil", 0); + _player->camera()->a_translate("hor_oscil", _player->camera()->left()/12, 0.3/coeff, Animation::LoopOut::None, Animation::cos); + + _player->camera()->a_translate("vert_oscil", -Point4D{0, 1, 0}/24, 0.15/coeff, Animation::LoopOut::None, Animation::cos); + _player->camera()->a_wait("vert_oscil", 0); + _player->camera()->a_translate("vert_oscil", Point4D{0, 1, 0}/24, 0.15/coeff, Animation::LoopOut::None, Animation::cos); + _player->camera()->a_wait("vert_oscil", 0); + _player->camera()->a_translate("vert_oscil", -Point4D{0, 1, 0}/24, 0.15/coeff, Animation::LoopOut::None, Animation::cos); + _player->camera()->a_wait("vert_oscil", 0); + _player->camera()->a_translate("vert_oscil", Point4D{0, 1, 0}/24, 0.15/coeff, Animation::LoopOut::None, Animation::cos); + + _player->camera()->a_translateToPoint("init", _player->position() + Point4D{0, 1.8, 0}, 0.3/coeff, Animation::None, Animation::cos); + + } else if(inRunning_old && !_inRunning) { + _player->camera()->a_stopAllAnimations(); + + _player->camera()->a_translateToPoint("init", _player->position() + Point4D{0, 1.8, 0}, 0.15/coeff, Animation::None, Animation::cos); + } + + auto rayToFloor = (*_world).rayCast(_player->position(), _player->position() + Point4D{0, -5, 0}); + + // Left and right + if (Keyboard::isKeyPressed(sf::Keyboard::A)) { + _player->translate(_player->camera()->left() * Time::deltaTime() * _walkSpeed * coeff); + if(_player->inCollision()) + _player->setVelocity(Point4D{0,0,0}); + } + if (Keyboard::isKeyPressed(sf::Keyboard::D)) { + _player->translate(-_player->camera()->left() * Time::deltaTime() * _walkSpeed * coeff); + if(_player->inCollision()) + _player->setVelocity(Point4D{0,0,0}); + } + + // Forward and backward + if (Keyboard::isKeyPressed(sf::Keyboard::W)) { + _player->translate(_player->camera()->left().cross3D(Point4D{0, 1, 0}) * Time::deltaTime() * _walkSpeed * coeff); + if(_player->inCollision()) + _player->setVelocity(Point4D{0,0,0}); + } + + if (Keyboard::isKeyPressed(sf::Keyboard::S)) { + _player->translate(-_player->camera()->left().cross3D(Point4D{0, 1, 0}) * Time::deltaTime() * _walkSpeed * coeff); + + if(_player->inCollision()) + _player->setVelocity(Point4D{0,0,0}); + } + + if (_player->ability() > 0 && !_isInSlowMo && Keyboard::isKeyPressed(sf::Keyboard::LShift)) { + // slow mo + _isInSlowMo = true; + _player->setVelocity(_player->velocity() / _slowMoCoefficient); + _player->setAcceleration(_player->acceleration() / (_slowMoCoefficient * _slowMoCoefficient)); + _unSlowMoSound.stop(); + _slowMoSound.play(); + } else if (_isInSlowMo && !Keyboard::isKeyPressed(sf::Keyboard::LShift)) { + _isInSlowMo = false; + _player->setVelocity(_player->velocity() * _slowMoCoefficient); + _player->setAcceleration(_player->acceleration() * _slowMoCoefficient * _slowMoCoefficient); + _slowMoSound.stop(); + _unSlowMoSound.play(); + } + + if (Keyboard::isKeyPressed(sf::Keyboard::Space) && _player->inCollision()) { + _player->addVelocity(Point4D{0, std::abs(_player->collisionNormal().y()) * sqrt(2 * _g * _jumpHeight) * coeff, 0}); + _player->translate(Point4D{0, Time::deltaTime() * _walkSpeed * 2 * coeff, 0}); + } + + // Mouse movement + Point4D disp = _mouse->getMouseDisplacement(); + + _player->rotate(Point4D{0, -disp.x() / 1000.0, 0}); + _player->setVelocity(Matrix4x4::RotationY(-disp.x() / 1000.0) * _player->velocity()); + + double rotationLeft = disp.y() / 1000.0; + + // You can only see in range [-90 : 90] grad + if (_player->camera()->angleLeftUpLookAt().x() + rotationLeft > M_PI / 2) + rotationLeft = M_PI / 2 - _player->camera()->angleLeftUpLookAt().x(); + if (_player->camera()->angleLeftUpLookAt().x() + rotationLeft < -M_PI / 2) + rotationLeft = -M_PI / 2 - _player->camera()->angleLeftUpLookAt().x(); + + _player->camera()->rotateLeft(rotationLeft); + _player->rotateWeaponsRelativePoint(_player->position() + Point4D{0, 1.8, 0}, _player->camera()->left(), rotationLeft); + + if (_keyboard->isKeyTapped(sf::Keyboard::Right) || _keyboard->isKeyTapped(sf::Keyboard::E)) { + _player->nextWeapon(); + } + + if (_keyboard->isKeyTapped(sf::Keyboard::Left) || _keyboard->isKeyTapped(sf::Keyboard::Q)) { + _player->previousWeapon(); + } + + if (Mouse::isButtonPressed(sf::Mouse::Button::Left)) { + _player->fire(); + } + + if(Keyboard::isKeyPressed(sf::Keyboard::R)) { + _player->reload(); + } + + if (_inRunning && _player->inCollision() && _walkSound.getStatus() != sf::Sound::Status::Playing) { + if ((_player->position() - rayToFloor.first).abs() < 2) { + int soundNum = round((double) rand() / RAND_MAX * 5) + 1; + _walkSound.setBuffer(*ResourceManager::loadSoundBuffer("../sound/stonestep" + std::to_string(soundNum) + ".ogg")); + _walkSound.play(); + } + } +} diff --git a/PlayerController.h b/PlayerController.h new file mode 100644 index 0000000..5fe8952 --- /dev/null +++ b/PlayerController.h @@ -0,0 +1,39 @@ +// +// Created by Иван Ильин on 19.09.2021. +// + +#ifndef SHOOTER_PLAYERCONTROLLER_H +#define SHOOTER_PLAYERCONTROLLER_H + +#include "Player.h" +#include "Keyboard.h" +#include "Mouse.h" + +class PlayerController { +private: + std::shared_ptr _player; + std::shared_ptr _world; + + std::shared_ptr _keyboard; + std::shared_ptr _mouse; + + bool _inRunning = false; + double _slowMoCoefficient = 5; + bool _isInSlowMo = false; + + double _g = 35; + + sf::Sound _slowMoSound; + sf::Sound _unSlowMoSound; + sf::Sound _changeWeaponSound; + sf::Sound _walkSound; + + double _jumpHeight = 3; + double _walkSpeed = 10; +public: + PlayerController(std::shared_ptr player, std::shared_ptr world, std::shared_ptr keyboard, std::shared_ptr mouse); + void update(); +}; + + +#endif //SHOOTER_PLAYERCONTROLLER_H diff --git a/engine/Engine.cpp b/engine/Engine.cpp index 6ab3048..18bac95 100755 --- a/engine/Engine.cpp +++ b/engine/Engine.cpp @@ -10,6 +10,9 @@ Engine::Engine() { screen = std::make_shared(); + keyboard = std::make_shared(); + mouse = std::make_shared(); + world = std::make_shared(); camera = std::make_shared(); } @@ -18,13 +21,14 @@ void Engine::create(int screenWidth, int screenHeight, const std::string &name, _name = name; screen->open(screenWidth, screenHeight, name, verticalSync, background, style); + screen->attachMouse(mouse); - Log::log("Engine::create(): started engine (" + std::to_string(screenWidth) + " x " + std::to_string(screenHeight) + ") with name '" + name + "'."); + Log::log("Engine::create(): started engine (" + std::to_string(screenWidth) + " x " + std::to_string(screenHeight) + ") with title '" + name + "'."); Time::update(); start(); camera->init(screenWidth, screenHeight); - screen->getMouseDisplacement(); // We do it to set mouse position in the center (see how getMouseDisplacement() works) + mouse->setMouseInCenter(); while (screen->isOpen()) { screen->clear(); @@ -69,7 +73,8 @@ void Engine::exit() { screen->close(); } ResourceManager::unloadAllResources(); - Log::log("Engine::exit(): exit engine (" + std::to_string(screen->width()) + " x " + std::to_string(screen->height()) + ") with name '" + screen->name() + "'."); + Log::log("Engine::exit(): exit engine (" + std::to_string(screen->width()) + " x " + std::to_string(screen->height()) + ") with title '" + + screen->title() + "'."); } void Engine::printDebugText() const { diff --git a/engine/Engine.h b/engine/Engine.h index 8d14a26..9aa11a0 100755 --- a/engine/Engine.h +++ b/engine/Engine.h @@ -6,6 +6,9 @@ #define ENGINE_ENGINE_H #include "Screen.h" +#include "Keyboard.h" +#include "Mouse.h" + #include "World.h" #include "Camera.h" #include "utils/Log.h" @@ -21,6 +24,9 @@ private: protected: std::shared_ptr screen; + std::shared_ptr keyboard; + std::shared_ptr mouse; + std::shared_ptr world; std::shared_ptr camera; diff --git a/engine/Keyboard.cpp b/engine/Keyboard.cpp new file mode 100644 index 0000000..51175e2 --- /dev/null +++ b/engine/Keyboard.cpp @@ -0,0 +1,24 @@ +// +// Created by Иван Ильин on 19.09.2021. +// + +#include "Keyboard.h" +#include "utils/Time.h" + +bool Keyboard::isKeyPressed(sf::Keyboard::Key key) { + return sf::Keyboard::isKeyPressed(key); +} + +bool Keyboard::isKeyTapped(sf::Keyboard::Key key) { + if (!Keyboard::isKeyPressed(key)) + return false; + + if(_tappedKeys.count(key) == 0) { + _tappedKeys.emplace(key, Time::time()); + return true; + } else if((Time::time() - _tappedKeys[key]) > 0.2) { + _tappedKeys[key] = Time::time(); + return true; + } + return false; +} \ No newline at end of file diff --git a/engine/Keyboard.h b/engine/Keyboard.h new file mode 100644 index 0000000..897b4ab --- /dev/null +++ b/engine/Keyboard.h @@ -0,0 +1,21 @@ +// +// Created by Иван Ильин on 19.09.2021. +// + +#ifndef SHOOTER_KEYBOARD_H +#define SHOOTER_KEYBOARD_H + +#include + +class Keyboard { +private: + std::map _tappedKeys; +public: + Keyboard() = default; + + static bool isKeyPressed(sf::Keyboard::Key key); // returns true if this key is pressed + bool isKeyTapped(sf::Keyboard::Key key); // returns true if this key is tapped and 1/5 sec passed (button bouncing problem solved) +}; + + +#endif //SHOOTER_KEYBOARD_H diff --git a/engine/Mouse.cpp b/engine/Mouse.cpp new file mode 100644 index 0000000..dbf1fb6 --- /dev/null +++ b/engine/Mouse.cpp @@ -0,0 +1,50 @@ +// +// Created by Иван Ильин on 19.09.2021. +// + +#include "Mouse.h" +#include "utils/Time.h" + +Point4D Mouse::getMousePosition() const { + sf::Vector2 pos = sf::Mouse::getPosition(*_window); + return Point4D(pos.x, pos.y, 0, 0); +} + +Point4D Mouse::getMouseDisplacement() const { + sf::Vector2 mousePos = sf::Mouse::getPosition(*_window); + sf::Vector2 center = sf::Vector2(_window->getSize().x/2, _window->getSize().y/2); + + sf::Vector2 disp = mousePos - center; + //setMouseInCenter(); + return Point4D(disp.x, disp.y, 0, 0); +} + +void Mouse::setMouseInCenter() const { + sf::Mouse::setPosition({ static_cast(_window->getSize().x / 2), static_cast(_window->getSize().y / 2) }, *_window); +} + +bool Mouse::isButtonPressed(sf::Mouse::Button button) { + return sf::Mouse::isButtonPressed(button); +} + +bool Mouse::isButtonTapped(sf::Mouse::Button button) { + if (!Mouse::isButtonPressed(button)) + return false; + + if(_tappedButtons.count(button) == 0) { + _tappedButtons.emplace(button, Time::time()); + return true; + } else if((Time::time() - _tappedButtons[button]) > 0.2) { + _tappedButtons[button] = Time::time(); + return true; + } + return false; +} + +void Mouse::setWindow(std::shared_ptr window) { + _window = window; +} + +void Mouse::setMouseCursorVisible(bool visible) { + _window->setMouseCursorVisible(visible); +} diff --git a/engine/Mouse.h b/engine/Mouse.h new file mode 100644 index 0000000..2b43053 --- /dev/null +++ b/engine/Mouse.h @@ -0,0 +1,31 @@ +// +// Created by Иван Ильин on 19.09.2021. +// + +#ifndef SHOOTER_MOUSE_H +#define SHOOTER_MOUSE_H + +#include +#include "utils/Point4D.h" + +class Mouse { +private: + std::shared_ptr _window; + + std::map _tappedButtons; +public: + Mouse() = default; + + void setWindow(std::shared_ptr window); + + static bool isButtonPressed(sf::Mouse::Button button); // returns true if this button is pressed + bool isButtonTapped(sf::Mouse::Button button); // returns true if this button is tapped and 1/5 sec passed (button bouncing problem solved) + + [[nodiscard]] Point4D getMousePosition() const; + [[nodiscard]] Point4D getMouseDisplacement() const; + void setMouseInCenter() const; + void setMouseCursorVisible(bool visible); +}; + + +#endif //SHOOTER_MOUSE_H diff --git a/engine/Screen.cpp b/engine/Screen.cpp index 7831701..af3ba6f 100755 --- a/engine/Screen.cpp +++ b/engine/Screen.cpp @@ -11,7 +11,7 @@ void Screen::open(int screenWidth, int screenHeight, const std::string &name, bool verticalSync, sf::Color background, sf::Uint32 style) { - _name = name; + _title = name; _w = screenWidth; _h = screenHeight; _background = background; @@ -19,26 +19,27 @@ void Screen::open(int screenWidth, int screenHeight, const std::string &name, bo sf::ContextSettings settings; settings.antialiasingLevel = 8; - window.create(sf::VideoMode(_w, _h), name, style, settings); - window.setVerticalSyncEnabled(verticalSync); + _window = std::make_shared(); + _window->create(sf::VideoMode(_w, _h), name, style, settings); + _window->setVerticalSyncEnabled(verticalSync); } void Screen::display() { sf::Event event{}; - while (window.pollEvent(event)) { + while (_window->pollEvent(event)) { if (event.type == sf::Event::Closed) { - window.close(); + _window->close(); } } - std::string title = _name + " (" + std::to_string(Time::fps()) + " fps)"; - window.setTitle(title); + std::string title = _title + " (" + std::to_string(Time::fps()) + " fps)"; + _window->setTitle(title); - window.display(); + _window->display(); } void Screen::clear() { - window.clear(_background); + _window->clear(_background); } void Screen::drawTriangle(const Triangle& triangle) @@ -49,74 +50,19 @@ void Screen::drawTriangle(const Triangle& triangle) sf::Vertex(sf::Vector2f(triangle[1].x(), triangle[1].y()), triangle.color()), sf::Vertex(sf::Vector2f(triangle[2].x(), triangle[2].y()), triangle.color()) }; - window.draw(tris, 3, sf::Triangles); + _window->draw(tris, 3, sf::Triangles); } -void Screen::setName(const std::string& title) { - _name = title; +void Screen::setTitle(const std::string& title) { + _title = title; } bool Screen::isOpen() { - return window.isOpen(); + return _window->isOpen(); } void Screen::close() { - window.close(); -} - -bool Screen::isKeyPressed(sf::Keyboard::Key key) { - return sf::Keyboard::isKeyPressed(key); -} - -Point4D Screen::getMousePosition() const { - sf::Vector2 pos = sf::Mouse::getPosition(window); - return Point4D(pos.x, pos.y, 0, 0); -} - -Point4D Screen::getMouseDisplacement() const { - sf::Vector2 disp = sf::Mouse::getPosition(window) - sf::Vector2(_w/2, _h/2); - setMouseInCenter(); - return Point4D(disp.x, disp.y, 0, 0); -} - -void Screen::setMouseInCenter() const { - sf::Mouse::setPosition({ _w / 2, _h / 2 }, window); -} - -void Screen::setMouseCursorVisible(bool visible) { - window.setMouseCursorVisible(visible); -} - -bool Screen::isKeyTapped(sf::Keyboard::Key key) { - if (!Screen::isKeyPressed(key)) - return false; - - if(_tappedKeys.count(key) == 0) { - _tappedKeys.emplace(key, Time::time()); - return true; - } else if((Time::time() - _tappedKeys[key]) > 0.2) { - _tappedKeys[key] = Time::time(); - return true; - } - return false; -} - -bool Screen::isButtonPressed(sf::Mouse::Button button) { - return sf::Mouse::isButtonPressed(button); -} - -bool Screen::isButtonTapped(sf::Mouse::Button button) { - if (!Screen::isButtonPressed(button)) - return false; - - if(_tappedButtons.count(button) == 0) { - _tappedButtons.emplace(button, Time::time()); - return true; - } else if((Time::time() - _tappedButtons[button]) > 0.2) { - _tappedButtons[button] = Time::time(); - return true; - } - return false; + _window->close(); } @@ -129,5 +75,42 @@ void Screen::debugText(const std::string& text) { t.setFillColor(sf::Color::Black); t.setPosition(10, 10); - window.draw(t); + _window->draw(t); +} + +void Screen::drawTetragon(const Point4D &p1, const Point4D &p2, const Point4D &p3, const Point4D &p4, sf::Color color) { + sf::ConvexShape polygon; + polygon.setPointCount(4); + polygon.setPoint(0, sf::Vector2f((float)p1.x(), (float)p1.y())); + polygon.setPoint(1, sf::Vector2f((float)p2.x(), (float)p2.y())); + polygon.setPoint(2, sf::Vector2f((float)p3.x(), (float)p3.y())); + polygon.setPoint(3, sf::Vector2f((float)p4.x(), (float)p4.y())); + polygon.setFillColor(color); + _window->draw(polygon); +} + +void Screen::drawText(const std::string& string, const Point4D &position, int size, sf::Color color) { + sf::Text text; + + text.setFont(*ResourceManager::loadFont("../engine/fonts/Roboto-Medium.ttf")); + + text.setCharacterSize(size); + text.setFillColor(color); + text.setStyle(sf::Text::Italic); + text.setPosition((float)position.x(), (float)position.y()); + + text.setString(string); + _window->draw(text); +} + +void Screen::drawSprite(const sf::Sprite &sprite) { + _window->draw(sprite); +} + +void Screen::drawText(const sf::Text &text) { + _window->draw(text); +} + +void Screen::attachMouse(std::shared_ptr mouse) { + mouse->setWindow(_window); } diff --git a/engine/Screen.h b/engine/Screen.h index e47c8ef..dd5476e 100755 --- a/engine/Screen.h +++ b/engine/Screen.h @@ -11,53 +11,46 @@ #include #include #include "utils/Time.h" +#include "Mouse.h" class Screen { private: int _w = 1920; int _h = 1080; - std::string _name; + std::string _title; sf::Color _background; - std::map _tappedKeys; - std::map _tappedButtons; - std::string _font = "../engine/fonts/Roboto-Thin.ttf"; + std::shared_ptr _window; public: - sf::RenderWindow window; - void open(int screenWidth = 1920, int screenHeight = 1080, const std::string& name = "engine", bool verticalSync = true, sf::Color background = sf::Color(255, 255, 255), sf::Uint32 style = sf::Style::Default); void display(); void clear(); + bool hasFocus() const { return _window->hasFocus(); } void drawTriangle(const Triangle& triangle); + void drawTetragon(const Point4D& p1, const Point4D& p2, const Point4D& p3, const Point4D& p4, sf::Color color); + void drawText(const std::string& string, const Point4D& position, int size, sf::Color color); + void drawText(const sf::Text& text); + void drawSprite(const sf::Sprite& sprite); - void setName(const std::string& title); - std::string name() const { return _name; }; + void setTitle(const std::string& title); + [[nodiscard]] std::string title() const { return _title; }; bool isOpen(); - int width() const {return window.getSize().x;} - int height() const {return window.getSize().y;} + [[nodiscard]] int width() const {return _window->getSize().x;} + [[nodiscard]] int height() const {return _window->getSize().y;} void close(); - static bool isKeyPressed(sf::Keyboard::Key key); // returns true if this key is pressed - bool isKeyTapped(sf::Keyboard::Key key); // returns true if this key is tapped and 1/5 sec passed (button bouncing problem solved) - - static bool isButtonPressed(sf::Mouse::Button button); // returns true if this button is pressed - bool isButtonTapped(sf::Mouse::Button button); // returns true if this button is tapped and 1/5 sec passed (button bouncing problem solved) - - Point4D getMousePosition() const; - Point4D getMouseDisplacement() const; - void setMouseInCenter() const; - void setMouseCursorVisible(bool visible); - void debugText(const std::string& text); + + void attachMouse(std::shared_ptr mouse); }; diff --git a/engine/World.cpp b/engine/World.cpp index 20f7baa..f5a5f33 100755 --- a/engine/World.cpp +++ b/engine/World.cpp @@ -16,7 +16,7 @@ void World::addBody(std::shared_ptr body, const string &name) { void World::loadBody(const string &name, const string &filename, const std::string &materials, const Point4D& scale) { _objects.emplace(name, std::make_shared(Mesh(filename, materials, scale))); - Log::log("World::loadBody(): inserted body from " + filename + " with name '" + name + "' with " + std::to_string(_objects[name]->triangles().size()) + " _tris."); + Log::log("World::loadBody(): inserted body from " + filename + " with title '" + name + "' with " + std::to_string(_objects[name]->triangles().size()) + " _tris."); } void World::removeBody(const string &name) { diff --git a/engine/World.h b/engine/World.h index 93855a3..9ab24c4 100755 --- a/engine/World.h +++ b/engine/World.h @@ -29,7 +29,7 @@ public: // rayCast returns pair of Point4D and std::string: // 1) Point4D is point of collision (the last coordinate is -1 if there are no collisions) - // 2) std::string - name of the object + // 2) std::string - title of the object std::pair rayCast(const Point4D& from, const Point4D& to); void loadMap(const std::string& filename, const std::string& name = "", const Point4D& scale = Point4D{1, 1, 1}, const std::string &materials = "../maps/materials.txt"); diff --git a/engine/gui/Window.cpp b/engine/gui/Window.cpp index ac31507..d20168b 100755 --- a/engine/gui/Window.cpp +++ b/engine/gui/Window.cpp @@ -14,15 +14,15 @@ void Window::addButton(int x, int y, int w, int h, std::function click, buttons.back().init(); } -void Window::update(std::shared_ptr screen) { +void Window::update() { - screen->setName(s_name); - screen->window.draw(back); + _screen->setTitle(s_name); + _screen->drawSprite(back); - Point4D mousePos = screen->getMousePosition(); + Point4D mousePos = _mouse->getMousePosition(); Point4D dMousePos = mousePos - prevMousePosition; back.setPosition(back.getPosition() - sf::Vector2f(dMousePos.x()/30, dMousePos.y()/30)); - bool isPressed = screen->isButtonTapped(sf::Mouse::Left); + bool isPressed = _mouse->isButtonTapped(sf::Mouse::Left); for(auto& button : buttons) { if( mousePos.x() > button.x - button.w*button.sx/2 && mousePos.y() > button.y - button.h*button.sy/2 && @@ -34,9 +34,9 @@ void Window::update(std::shared_ptr screen) { button.unSelect(); } - if(screen->isOpen()) { - screen->window.draw(button.button); - screen->window.draw(button.text); + if(_screen->isOpen()) { + _screen->drawSprite(button.button); + _screen->drawText(button.text); } } diff --git a/engine/gui/Window.h b/engine/gui/Window.h index 975851e..316a149 100755 --- a/engine/gui/Window.h +++ b/engine/gui/Window.h @@ -10,6 +10,7 @@ #include "Button.h" #include "Screen.h" +#include "Mouse.h" class Window { private: @@ -20,8 +21,11 @@ private: sf::Sprite back; Point4D prevMousePosition; + + std::shared_ptr _screen; + std::shared_ptr _mouse; public: - explicit Window(std::string name = "Menu", std::string backTexture = "") : s_name(std::move(name)), s_backTexture(std::move(backTexture)){} + explicit Window(std::shared_ptr screen, std::shared_ptr mouse, std::string name = "Menu", std::string backTexture = "") : _screen(screen), _mouse(mouse), s_name(std::move(name)), s_backTexture(std::move(backTexture)){} void addButton(int x, int y, int w, int h, std::function click, @@ -34,7 +38,7 @@ public: void setBackgroundTexture(const std::string& texture, double sx = 1, double sy = 1, int w = 1920, int h = 1080); - void update(std::shared_ptr screen); + void update(); }; diff --git a/engine/physics/RigidBody.h b/engine/physics/RigidBody.h index 52c8379..2fd5692 100755 --- a/engine/physics/RigidBody.h +++ b/engine/physics/RigidBody.h @@ -52,6 +52,8 @@ public: std::pair checkGJKCollision(std::shared_ptr obj); CollisionPoint EPA(const Simplex& simplex, std::shared_ptr obj); + [[nodiscard]] Point4D collisionNormal() const { return _collisionNormal; } + [[nodiscard]] bool isCollision() const { return _collision; } [[nodiscard]] bool inCollision() const {return _inCollision; } [[nodiscard]] bool isCollider() const {return _isCollider; } @@ -67,6 +69,7 @@ public: void setAcceleration(const Point4D& acceleration); [[nodiscard]] Point4D velocity() const { return _velocity; } + [[nodiscard]] Point4D acceleration() const { return _acceleration; } [[nodiscard]] const std::function)>& collisionCallBack() const { return _collisionCallBack; } void setCollisionCallBack(const std::function)>& f) { _collisionCallBack = f; } diff --git a/main.cpp b/main.cpp index 8c9cc2a..aabbc88 100755 --- a/main.cpp +++ b/main.cpp @@ -7,6 +7,7 @@ #include "Player.h" #include "ResourceManager.h" #include "gui/Window.h" +#include "PlayerController.h" #include "Client.h" #include "Server.h" @@ -61,6 +62,7 @@ void InitNetwork(shared_ptr server, shared_ptr client) class Shooter : public Engine { private: shared_ptr player; + shared_ptr playerController; sf::Sound backgroundNoise; @@ -72,7 +74,7 @@ private: bool inGame = false; public: - Shooter() = default; + Shooter() : mainMenu(screen, mouse) {}; void start() override; void update() override; @@ -86,11 +88,13 @@ void Shooter::start() { // This code executed once in the beginning: setDebugText(false); - screen->setMouseCursorVisible(true); + mouse->setMouseCursorVisible(true); world->loadMap("../maps/map1.obj", "map", Point4D{5, 5, 5}); player = std::make_shared(); + playerController = std::make_shared(player, world, keyboard, mouse); + client = std::make_shared(player, world); server = std::make_shared(); @@ -139,22 +143,23 @@ void Shooter::update() { client->update(); // Check all input after this condition please - if (!screen->window.hasFocus()) + if (!screen->hasFocus()) return; - if(screen->isKeyTapped(sf::Keyboard::Escape)) { + if(keyboard->isKeyTapped(sf::Keyboard::Escape)) { inGame = !inGame; - screen->setMouseCursorVisible(!inGame); + mouse->setMouseCursorVisible(!inGame); } if(inGame) { - screen->setName("Shooter"); + screen->setTitle("Shooter"); player->update(); + playerController->update(); + mouse->setMouseInCenter(); } else { - mainMenu.update(screen); + mainMenu.update(); } - setUpdateWorld(inGame); // background sounds and music control @@ -172,7 +177,7 @@ void Shooter::gui() { sprite.scale(3, 3); sprite.setPosition(screen->width() / 2.0 - 27.0/2.0, screen->height() / 2 - 27.0/2.0); sprite.setColor(sf::Color(0,0,0, 200)); - screen->window.draw(sprite); + screen->drawSprite(sprite); // health player stats player->drawStats(); @@ -181,10 +186,10 @@ void Shooter::gui() { void Shooter::play() { inGame = true; - screen->setMouseCursorVisible(!inGame); + mouse->setMouseCursorVisible(!inGame); } -int main(int argc, char* argv[]) { +int main() { Shooter game; //game.create(1280, 720, "Shooter");