diff --git a/CMakeLists.txt b/CMakeLists.txt index 634f26d..6a3aec4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,7 @@ add_executable(${CMAKE_PROJECT_NAME} engine/animation/Animations.h engine/animation/AShowCreation.h engine/animation/AShowUncreation.h + engine/animation/ARotateLeftUpLookAt.h engine/physics/RigidBody.cpp engine/physics/RigidBody.h engine/physics/Simplex.h diff --git a/Player.cpp b/Player.cpp index c9debae..f0a0274 100644 --- a/Player.cpp +++ b/Player.cpp @@ -80,12 +80,29 @@ void Player::addWeapon(std::shared_ptr weapon) { _weapons.back()->setReloadCallBack([this]() { Timeline::addAnimation(AnimationListTag("reload_weapon"), _weapons[_selectedWeapon], - -4 * Consts::PI, + -2 * Consts::PI, _weapons[_selectedWeapon]->reloadTime() / 2, Animation::LoopOut::None, Animation::InterpolationType::Cos); }); + // adding fire animation + _weapons.back()->setFireCallBack([this]() { + Timeline::addAnimation(AnimationListTag("fire_weapon"), + _weapons[_selectedWeapon], + -_weapons[_selectedWeapon]->fireDelay(), + _weapons[_selectedWeapon]->fireDelay()/3, + Animation::LoopOut::None, + Animation::InterpolationType::Cos); + Timeline::addAnimation(AnimationListTag("fire_weapon"), 0); + Timeline::addAnimation(AnimationListTag("fire_weapon"), + _weapons[_selectedWeapon], + _weapons[_selectedWeapon]->fireDelay(), + _weapons[_selectedWeapon]->fireDelay()/3, + Animation::LoopOut::None, + Animation::InterpolationType::Cos); + }); + // add call back function to create fire traces if (_addTraceCallBack != nullptr) { _weapons.back()->setAddTraceCallBack(_addTraceCallBack); @@ -126,7 +143,9 @@ void Player::selectNextWeapon() { } Log::log("selectedWeapon " + std::to_string(_selectedWeapon)); SoundController::loadAndPlay(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND); + rotateWeapon(); } + } void Player::selectPreviousWeapon() { @@ -145,6 +164,7 @@ void Player::selectPreviousWeapon() { } Log::log("selectedWeapon " + std::to_string(_selectedWeapon)); SoundController::loadAndPlay(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND); + rotateWeapon(); } } @@ -176,3 +196,12 @@ void Player::setFullAbility() { _ability = ShooterConsts::ABILITY_MAX; SoundController::loadAndPlay(SoundTag("addAbility"), ShooterConsts::RESTORE_ABILITY_SOUND); } + +void Player::rotateWeapon() { + Timeline::addAnimation(AnimationListTag("select_weapon"), + _weapons[_selectedWeapon], + -2 * Consts::PI, + 0.3, + Animation::LoopOut::None, + Animation::InterpolationType::Cos); +} diff --git a/Player.h b/Player.h index d0375ca..b0af663 100644 --- a/Player.h +++ b/Player.h @@ -42,6 +42,7 @@ private: std::function _rayCastFunction; void collisionWithObject(const ObjectNameTag &tag, std::shared_ptr obj); + void rotateWeapon(); public: explicit Player(ObjectNameTag name, const std::string &filename = ShooterConsts::CUBE_OBJ, const Vec3D &scale = Vec3D{1, 1, 1}); diff --git a/PlayerController.cpp b/PlayerController.cpp index 145e181..1cd7209 100644 --- a/PlayerController.cpp +++ b/PlayerController.cpp @@ -41,6 +41,28 @@ void PlayerController::update() { Keyboard::isKeyPressed(sf::Keyboard::S)); std::shared_ptr camera = _player->attached(ObjectNameTag("Camera")); + + if(camera != nullptr) { + // random motion during high speed + if (!Timeline::isInAnimList(AnimationListTag("high_speed_motion"))) { + double d_alpha = _player->velocity().abs()/3000*rand()/RAND_MAX; + double dt = 0.07; + + Timeline::addAnimation(AnimationListTag("high_speed_motion"), + camera, Vec3D(0, 0, d_alpha), dt, + Animation::LoopOut::None, + Animation::InterpolationType::Cos); + Timeline::addAnimation(AnimationListTag("high_speed_motion"), 0); + Timeline::addAnimation(AnimationListTag("high_speed_motion"), + camera, Vec3D(0, 0, -d_alpha), dt, + Animation::LoopOut::None, + Animation::InterpolationType::Cos); + Timeline::addAnimation(AnimationListTag("high_speed_motion"), 0); + + } + } + + if (camera != nullptr && _inRunning && _player->inCollision()) { if (!Timeline::isInAnimList(AnimationListTag("camera_hor_oscil"))) { Timeline::addAnimation(AnimationListTag("camera_hor_oscil"), @@ -149,6 +171,7 @@ void PlayerController::update() { if (Keyboard::isKeyPressed(sf::Keyboard::Space) && _player->inCollision()) { // if we just want to jump, we have to add particular speed + if (!_isSliding) { _player->addVelocity(Vec3D{0, std::abs(_player->collisionNormal().y()) * sqrt(2 * -_player->acceleration().y() * ShooterConsts::JUMP_HEIGHT) * coeff, @@ -160,6 +183,8 @@ void PlayerController::update() { Time::deltaTime() * 60, 0}); } _player->translate(Vec3D{0, Time::deltaTime() * ShooterConsts::WALK_SPEED * 2 * coeff, 0}); + + //_player->setVelocity(Vec3D{_player->velocity().x(), sqrt(2 * -_player->acceleration().y() * ShooterConsts::JUMP_HEIGHT) * coeff,_player->velocity().z()}); _isSliding = true; } else { _isSliding = false; @@ -169,8 +194,7 @@ void PlayerController::update() { Vec2D displacement = _mouse->getMouseDisplacement(); _player->rotate(Vec3D{0, -displacement.x() * ShooterConsts::MOUSE_SENSITIVITY, 0}); - _player->setVelocity( - Matrix4x4::RotationY(-displacement.x() * ShooterConsts::MOUSE_SENSITIVITY) * _player->velocity()); + _player->setVelocity(Matrix4x4::RotationY(-displacement.x() * ShooterConsts::MOUSE_SENSITIVITY) * _player->velocity()); double rotationLeft = displacement.y() * ShooterConsts::MOUSE_SENSITIVITY; @@ -186,7 +210,10 @@ void PlayerController::update() { _player->rotateWeaponsRelativePoint(_player->position() + Vec3D{0, 1.8, 0}, _player->left(), rotationLeft); if (camera != nullptr) { + double lookAtAngle = camera->angleLeftUpLookAt().z(); + camera->rotateLookAt(-lookAtAngle); camera->rotateLeft(_player->headAngle() - camera->angleLeftUpLookAt().x()); + camera->rotateLookAt(lookAtAngle); } if (_keyboard->isKeyTapped(sf::Keyboard::Right) || _keyboard->isKeyTapped(sf::Keyboard::E)) { diff --git a/Shooter.cpp b/Shooter.cpp index 8dbef0a..9af7805 100644 --- a/Shooter.cpp +++ b/Shooter.cpp @@ -82,7 +82,7 @@ void Shooter::start() { player->setDamagePlayerCallBack( [this](sf::Uint16 targetId, double damage) { client->damagePlayer(targetId, damage); }); player->setRayCastFunction( - [this](const Vec3D &from, const Vec3D &to) { return world->rayCast(from, to, "Player Weapon"); }); + [this](const Vec3D &from, const Vec3D &to) { return world->rayCast(from, to, "Player Weapon fireTrace bulletHole"); }); player->setTakeBonusCallBack([this](const string &bonusName) { client->takeBonus(bonusName); }); player->setAddWeaponCallBack([this](std::shared_ptr weapon) { addWeapon(std::move(weapon)); }); player->setRemoveWeaponCallBack([this](std::shared_ptr weapon) { removeWeapon(std::move(weapon)); }); @@ -303,7 +303,7 @@ void Shooter::removePlayer(sf::Uint16 id) { } void Shooter::addFireTrace(const Vec3D &from, const Vec3D &to) { - std::string traceName = "Client_fireTraces_" + std::to_string(fireTraces++); + std::string traceName = "Client_fireTrace_" + std::to_string(fireTraces++); world->addBody(std::make_shared(Mesh::LineTo(ObjectNameTag(traceName), from, to, 0.05))); world->body(ObjectNameTag(traceName))->setCollider(false); @@ -312,6 +312,17 @@ void Shooter::addFireTrace(const Vec3D &from, const Vec3D &to) { Timeline::addAnimation(AnimationListTag(traceName + "_delete"), [this, traceName]() { removeFireTrace(ObjectNameTag(traceName)); }, 1, 1); + + + std::string bulletHoleName = "Client_bulletHole_" + std::to_string(fireTraces++); + auto bulletHole = Mesh::Cube(ObjectNameTag(bulletHoleName), 0.2, sf::Color(70, 70, 70)); + bulletHole.translate(to); + world->addBody(std::make_shared(bulletHole)); + world->body(ObjectNameTag(bulletHoleName))->setCollider(false); + + Timeline::addAnimation(AnimationListTag(bulletHoleName + "_delete"), + [this, bulletHoleName]() { removeFireTrace(ObjectNameTag(bulletHoleName)); }, 1, + 7); } void Shooter::removeFireTrace(const ObjectNameTag &traceName) { @@ -367,12 +378,18 @@ void Shooter::changeEnemyWeapon(const std::string &weaponName, sf::Uint16 enemyI world->body(weaponTag)->setCollider(false); world->body(weaponTag)->scale(Vec3D(3, 3, 3)); - world->body(weaponTag)->translateToPoint( - head->position() - enemy->left() * 2.5 - enemy->up() * 2.5 + enemy->lookAt()); + world->body(weaponTag)->translateToPoint(head->position() - enemy->left() * 1.0 - enemy->up() * 1.0 + enemy->lookAt()); world->body(weaponTag)->rotate(Vec3D(0, enemy->angle().y(), 0)); world->body(weaponTag)->rotateLeft(head->angleLeftUpLookAt().x()); enemy->attach(world->body(weaponTag)); + + Timeline::addAnimation(AnimationListTag("select_weapon_" + std::to_string(enemyId)), + world->body(weaponTag), + -2 * Consts::PI, + 0.3, + Animation::LoopOut::None, + Animation::InterpolationType::Cos); } void Shooter::removeWeapon(std::shared_ptr weapon) { diff --git a/Source.cpp b/Source.cpp index b5fe3bc..7ee15e2 100644 --- a/Source.cpp +++ b/Source.cpp @@ -15,8 +15,8 @@ int main() { //game.create(1920, 1080, ShooterConsts::PROJECT_NAME, true, Consts::BACKGROUND_COLOR, sf::Style::Fullscreen); // Optimal for MacBook Pro 16 display: - game.create(2048, 1152, ShooterConsts::PROJECT_NAME, false, Consts::BACKGROUND_COLOR); - //game.create(3072, 1920, ShooterConsts::PROJECT_NAME, true, Consts::BACKGROUND_COLOR); + game.create(2048, 1152, ShooterConsts::PROJECT_NAME, true, Consts::BACKGROUND_COLOR); + //game.create(3072, 1920, ShooterConsts::PROJECT_NAME, true, Consts::BACKGROUND_COLOR, sf::Style::Fullscreen); return 0; } \ No newline at end of file diff --git a/engine/Camera.cpp b/engine/Camera.cpp index bccc753..7372b68 100644 --- a/engine/Camera.cpp +++ b/engine/Camera.cpp @@ -21,7 +21,7 @@ std::vector> Camera::project(std::shared_ptr mes // Model transform matrix: translate _tris in the origin of body. Matrix4x4 M = mesh->model(); - Matrix4x4 V = Matrix4x4::View(left(), up(), lookAt(), position()); + Matrix4x4 V = invModel(); // We don't want to waste time re-allocating memory every time std::vector clippedTriangles, tempBuffer; diff --git a/engine/Matrix4x4.cpp b/engine/Matrix4x4.cpp index 541a668..cd3807a 100644 --- a/engine/Matrix4x4.cpp +++ b/engine/Matrix4x4.cpp @@ -191,23 +191,32 @@ Matrix4x4 Matrix4x4::ScreenSpace(int width, int height) { return s; } -Matrix4x4 Matrix4x4::View(const Vec3D &left, const Vec3D &up, const Vec3D &lookAt, const Vec3D &eye) { +Matrix4x4 Matrix4x4::View(const Matrix4x4 &transformMatrix) { Matrix4x4 V = Zero(); - V._arr[0][0] = left.x(); - V._arr[0][1] = left.y(); - V._arr[0][2] = left.z(); - V._arr[0][3] = -eye.dot(left); + Vec3D left = transformMatrix.x(); + Vec3D up = transformMatrix.y(); + Vec3D lookAt = transformMatrix.z(); + Vec3D eye = transformMatrix.w(); - V._arr[1][0] = up.x(); - V._arr[1][1] = up.y(); - V._arr[1][2] = up.z(); - V._arr[1][3] = -eye.dot(up); + double left_sqrAbs = left.sqrAbs(); + double up_sqrAbs = up.sqrAbs(); + double lookAt_sqrAbs = lookAt.sqrAbs(); - V._arr[2][0] = lookAt.x(); - V._arr[2][1] = lookAt.y(); - V._arr[2][2] = lookAt.z(); - V._arr[2][3] = -eye.dot(lookAt); + V._arr[0][0] = left.x()/left_sqrAbs; + V._arr[0][1] = left.y()/left_sqrAbs; + V._arr[0][2] = left.z()/left_sqrAbs; + V._arr[0][3] = -eye.dot(left)/left_sqrAbs; + + V._arr[1][0] = up.x()/up_sqrAbs; + V._arr[1][1] = up.y()/up_sqrAbs; + V._arr[1][2] = up.z()/up_sqrAbs; + V._arr[1][3] = -eye.dot(up)/up_sqrAbs; + + V._arr[2][0] = lookAt.x()/lookAt_sqrAbs; + V._arr[2][1] = lookAt.y()/lookAt_sqrAbs; + V._arr[2][2] = lookAt.z()/lookAt_sqrAbs; + V._arr[2][3] = -eye.dot(lookAt)/lookAt_sqrAbs; V._arr[3][3] = 1.0; diff --git a/engine/Matrix4x4.h b/engine/Matrix4x4.h index c9980db..c4d8bcf 100644 --- a/engine/Matrix4x4.h +++ b/engine/Matrix4x4.h @@ -55,7 +55,7 @@ public: Matrix4x4 static Rotation(const Vec3D &v, double rv); - Matrix4x4 static View(const Vec3D &left, const Vec3D &up, const Vec3D &lookAt, const Vec3D &eye); + Matrix4x4 static View(const Matrix4x4 &transformMatrix); Matrix4x4 static Projection(double fov = 90.0, double aspect = 1.0, double ZNear = 1.0, double ZFar = 10.0); diff --git a/engine/Mesh.cpp b/engine/Mesh.cpp index 51c6b67..b129551 100644 --- a/engine/Mesh.cpp +++ b/engine/Mesh.cpp @@ -36,8 +36,7 @@ Mesh::Mesh(ObjectNameTag nameTag, const std::string &filename, const Vec3D &scal loadObj(filename, scale); } -Mesh::Mesh(ObjectNameTag nameTag, const vector &tries) : Object(std::move(nameTag)), _tris(tries) { -} +Mesh::Mesh(ObjectNameTag nameTag, const vector &tries) : Object(std::move(nameTag)), _tris(tries) {} void Mesh::setColor(const sf::Color &c) { _color = c; @@ -200,3 +199,25 @@ GLfloat *Mesh::glFloatArray() const { return _geometry; } + +Mesh Mesh::Cube(ObjectNameTag tag, double size, sf::Color color) { + Mesh cube(std::move(tag)); + + cube._tris = { + { Vec4D{0.0, 0.0, 0.0, 1.0}, Vec4D{0.0, 1.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 0.0, 1.0} }, + { Vec4D{0.0, 0.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 0.0, 1.0}, Vec4D{1.0, 0.0, 0.0, 1.0} }, + { Vec4D{1.0, 0.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 1.0, 1.0} }, + { Vec4D{1.0, 0.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 1.0, 1.0}, Vec4D{1.0, 0.0, 1.0, 1.0} }, + { Vec4D{1.0, 0.0, 1.0, 1.0}, Vec4D{1.0, 1.0, 1.0, 1.0}, Vec4D{0.0, 1.0, 1.0, 1.0} }, + { Vec4D{1.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 1.0, 1.0, 1.0}, Vec4D{0.0, 0.0, 1.0, 1.0} }, + { Vec4D{0.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 1.0, 1.0, 1.0}, Vec4D{0.0, 1.0, 0.0, 1.0} }, + { Vec4D{0.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 1.0, 0.0, 1.0}, Vec4D{0.0, 0.0, 0.0, 1.0} }, + { Vec4D{0.0, 1.0, 0.0, 1.0}, Vec4D{0.0, 1.0, 1.0, 1.0}, Vec4D{1.0, 1.0, 1.0, 1.0} }, + { Vec4D{0.0, 1.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 1.0, 1.0}, Vec4D{1.0, 1.0, 0.0, 1.0} }, + { Vec4D{1.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 0.0, 0.0, 1.0} }, + { Vec4D{1.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 0.0, 0.0, 1.0}, Vec4D{1.0, 0.0, 0.0, 1.0} }, + }; + cube.setColor(color); + + return cube *= Matrix4x4::Scale(Vec3D(size, size, size))*Matrix4x4::Translation(Vec3D(-0.5, -0.5, -0.5)); +} diff --git a/engine/Mesh.h b/engine/Mesh.h index 3023df6..9a00b9a 100644 --- a/engine/Mesh.h +++ b/engine/Mesh.h @@ -54,6 +54,8 @@ public: ~Mesh() override; + Mesh static Cube(ObjectNameTag tag, double size = 1.0, sf::Color color = sf::Color(0,0,0)); + Mesh static LineTo(ObjectNameTag nameTag, const Vec3D &from, const Vec3D &to, double line_width = 0.1, const sf::Color &color = {150, 150, 150, 100}); diff --git a/engine/Object.h b/engine/Object.h index 7c802f1..a2f528e 100644 --- a/engine/Object.h +++ b/engine/Object.h @@ -87,7 +87,7 @@ public: [[nodiscard]] ObjectNameTag name() const { return _nameTag; } [[nodiscard]] Matrix4x4 model() const { return Matrix4x4::Translation(_position) * _transformMatrix; } - [[nodiscard]] Matrix4x4 invModel() const { return Matrix4x4::View(left(), up(), lookAt(), position()); } + [[nodiscard]] Matrix4x4 invModel() const { return Matrix4x4::View(model()); } // OpenGL function [[nodiscard]] GLfloat *glModel() const; diff --git a/engine/ResourceManager.cpp b/engine/ResourceManager.cpp index 6dcb044..a66494d 100644 --- a/engine/ResourceManager.cpp +++ b/engine/ResourceManager.cpp @@ -135,8 +135,7 @@ std::vector> ResourceManager::loadObjects(const std::strin if (line[0] == 'o') { if (!tris.empty()) objects.push_back( - std::make_shared(ObjectNameTag(filename + "_temp_obj_" + std::to_string(objects.size())), - tris)); + std::make_shared(ObjectNameTag(filename + "_temp_obj_" + std::to_string(objects.size())), tris)); tris.clear(); } if (line[0] == 'v') { diff --git a/engine/World.cpp b/engine/World.cpp index 6879d59..df8e6be 100644 --- a/engine/World.cpp +++ b/engine/World.cpp @@ -56,25 +56,38 @@ IntersectionInformation World::rayCast(const Vec3D &from, const Vec3D &to, const continue; } - for (auto &tri : body->triangles()) { - Matrix4x4 model = body->model(); - Triangle tri_translated(model * tri[0], model * tri[1], model * tri[2], tri.color()); + Matrix4x4 model = body->model(); + Matrix4x4 invModel = body->invModel(); - Plane plane(tri_translated); - auto intersection = plane.intersection(from, to); - double distance = (intersection.first - from).sqrAbs(); - if (intersection.second > 0 && distance < minDistance && tri_translated.isPointInside(intersection.first)) { + Vec3D v = (to - from).normalized(); + Vec3D v_model = invModel*v; + Vec3D from_model = invModel*(from - body->position()); + Vec3D to_model = invModel*(to - body->position()); + + for (auto &tri : body->triangles()) { + + if(tri.norm().dot(v_model) > 0) { + continue; + } + + Plane plane(tri); + auto intersection = plane.intersection(from_model, to_model); + double distance = (intersection.first - from_model).sqrAbs(); + + if (intersection.second > 0 && distance < minDistance && tri.isPointInside(intersection.first)) { minDistance = distance; - point = intersection.first; - triangle = tri_translated; + point = model*intersection.first + body->position(); + triangle = Triangle(model * tri[0], model * tri[1], model * tri[2], tri.color()); bodyName = name.str(); intersected = true; intersectedBody = body; + //Triangle triangleRED = Triangle(model * tri[0], model * tri[1], model * tri[2], sf::Color(255, 0, 0)); + //addBody(std::make_shared(Mesh(ObjectNameTag("Test" + std::to_string(rand())), std::vector({triangleRED})))); } } } - return IntersectionInformation{point, sqrt(minDistance), triangle, ObjectNameTag(bodyName), intersectedBody, - intersected}; + + return IntersectionInformation{point, sqrt(minDistance), triangle, ObjectNameTag(bodyName), intersectedBody, intersected}; } void World::loadMap(const std::string &filename, const Vec3D &scale) { diff --git a/engine/animation/ARotateLeftUpLookAt.h b/engine/animation/ARotateLeftUpLookAt.h new file mode 100644 index 0000000..f9ae78f --- /dev/null +++ b/engine/animation/ARotateLeftUpLookAt.h @@ -0,0 +1,36 @@ +// +// Created by Иван Ильин on 01.11.2021. +// + +#ifndef SHOOTER_AROTATELEFTUPLOOKAT_H +#define SHOOTER_AROTATELEFTUPLOOKAT_H + +#include "Animation.h" +#include "../Object.h" + + +class ARotateLeftUpLookAt final : public Animation { +private: + const std::weak_ptr _object; + const Vec3D _rotationValue; + + void update() override { + auto obj = _object.lock(); + + if (obj == nullptr) { + stop(); + return; + } + + obj->rotateLeft(_rotationValue.x()*dprogress()); + obj->rotateUp(_rotationValue.y()*dprogress()); + obj->rotateLookAt(_rotationValue.z()*dprogress()); + } + +public: + ARotateLeftUpLookAt(std::weak_ptr object, const Vec3D &r, double duration = 1, LoopOut looped = LoopOut::None, + InterpolationType interpolationType = InterpolationType::Bezier) + : Animation(duration, looped, interpolationType), _object(object), _rotationValue(r) {} +}; + +#endif //SHOOTER_AROTATELEFT_H diff --git a/engine/animation/Animations.h b/engine/animation/Animations.h index 5e1bd16..66fbabb 100644 --- a/engine/animation/Animations.h +++ b/engine/animation/Animations.h @@ -19,6 +19,7 @@ #include "AWait.h" #include "AShowCreation.h" #include "AShowUncreation.h" +#include "ARotateLeftUpLookAt.h" #endif //SHOOTER_ANIMATIONS_H diff --git a/engine/physics/RigidBody.cpp b/engine/physics/RigidBody.cpp index 1c9cbae..f16213c 100644 --- a/engine/physics/RigidBody.cpp +++ b/engine/physics/RigidBody.cpp @@ -321,12 +321,10 @@ RigidBody::_addIfUniqueEdge(const std::vector> &edges, void RigidBody::solveCollision(const CollisionPoint &collision) { - Vec3D velocity_parallel = collision.normal * velocity().dot(collision.normal); - Vec3D velocity_perpendicular = velocity() - velocity_parallel; + Vec3D velocity_perpendicular = collision.normal * velocity().dot(collision.normal); + Vec3D velocity_parallel = velocity() - velocity_perpendicular; - if (velocity().dot(collision.normal) > 0) { - setVelocity(velocity_perpendicular); - } + setVelocity(velocity_parallel); translate(-collision.normal * collision.depth); } diff --git a/weapon/Weapon.cpp b/weapon/Weapon.cpp index 649849e..c0bc9b5 100644 --- a/weapon/Weapon.cpp +++ b/weapon/Weapon.cpp @@ -43,18 +43,18 @@ FireInformation Weapon::fire(std::function _addTraceCallBack; std::function _reloadCallBack; + std::function _fireCallBack; protected: std::map @@ -60,11 +61,13 @@ public: void reload(); [[nodiscard]] double reloadTime() const { return _reloadTime; } + [[nodiscard]] double fireDelay() const { return _fireDelay; } [[nodiscard]] std::pair balance() const { return std::make_pair(_clipAmmo, _stockAmmo); } void setAddTraceCallBack(std::function add) { _addTraceCallBack = std::move(add); } void setReloadCallBack(std::function reload) { _reloadCallBack = std::move(reload); } + void setFireCallBack(std::function fire) { _fireCallBack = std::move(fire); } void addAPack() { _stockAmmo += initialPack(); }