diff --git a/AimGL/resources/Sounds/footsteps.wav b/AimGL/resources/Sounds/footsteps.wav new file mode 100644 index 0000000..d00009f Binary files /dev/null and b/AimGL/resources/Sounds/footsteps.wav differ diff --git a/AimGL/resources/Sounds/gunshot.wav b/AimGL/resources/Sounds/gunshot.wav new file mode 100644 index 0000000..f63d068 Binary files /dev/null and b/AimGL/resources/Sounds/gunshot.wav differ diff --git a/AimGL/src/CMakeLists_Sources.txt b/AimGL/src/CMakeLists_Sources.txt index cd66deb..beea8d9 100644 --- a/AimGL/src/CMakeLists_Sources.txt +++ b/AimGL/src/CMakeLists_Sources.txt @@ -26,5 +26,6 @@ set(PROJECT_SOURCES Player/Player.cpp World/Camera.cpp World/InfiniteGridFloor.cpp + World/GameObjects/Rifle.cpp Utils/Mouse.cpp ) \ No newline at end of file diff --git a/AimGL/src/Player/Player.cpp b/AimGL/src/Player/Player.cpp index 2b1cd02..14fab89 100644 --- a/AimGL/src/Player/Player.cpp +++ b/AimGL/src/Player/Player.cpp @@ -4,51 +4,34 @@ Player::Player(WindowToRender& window) : mCamera(window) - , mGun("resources/Models/ak47/ak47.obj", - {{"resources/Models/ak47/ak47-alternative.png", Texture::Type::Diffuse}, - {"resources/Models/ak47/ak47-alternative-specular.png", Texture::Type::Specular}}) , mCrosshairTexture("resources/Textures/crosshair.png") , mCrosshair(mCrosshairTexture) + , mRifle(mCamera) { mCrosshair.setPosition({window.getSize().x / 2.f, window.getSize().y / 2.f}, Sprite2D::Origin::Center); mCrosshair.setOpacity(0.8f); mCamera.cameraPosition({mPosition.x, mPosition.y + PLAYER_HEGIHT, mPosition.z}); - mGun.setPosition(mCamera.cameraPosition(), Model::Origin::Center); + mSoundBuffer.loadFromFile("resources/Sounds/footsteps.wav"); + mWalkingSound.setBuffer(mSoundBuffer); + mWalkingSound.setVolume(50); + mRifle.update(1); } void Player::draw(const Renderer& target) const { glDepthRange(0.0, 0.01); - mGun.draw(target, mCamera); + mRifle.draw(target); glDepthRange(0.0, 1.0); mCrosshair.draw(target); } -void Player::updateGunPosition(const float& deltaTime) -{ - const glm::vec3 rotationOrigin = {0.3f, -0.2f, -0.35f}; - const glm::vec3 targetPosition = {mPosition.x + rotationOrigin.x, - mPosition.y + PLAYER_HEGIHT * 5 / 8, - mPosition.z + rotationOrigin.z}; - - const auto gunPosition = lerp(mGun.position(), targetPosition, deltaTime * 30.f); - mGun.setPosition(gunPosition, Model::Origin::Center); - mGun.setRotationOrigin(rotationOrigin); - - const auto gunTargetPitch = - lerp(mGun.rotation().pitch, mCamera.rotation().pitch, deltaTime * 20.f); - const auto gunTargetYaw = - lerp(mGun.rotation().yaw, -(mCamera.rotation().yaw + 90), deltaTime * 20.f); - mGun.setRotation({gunTargetYaw, gunTargetPitch, 0}); -} - void Player::update(const float& deltaTime) { mCamera.cameraPosition({mPosition.x, mPosition.y + PLAYER_HEGIHT, mPosition.z}); mCamera.update(deltaTime); - updateGunPosition(deltaTime); + mRifle.update(deltaTime); } void Player::updatePhysics(float deltaTime) @@ -108,6 +91,27 @@ void Player::fixedUpdate(const float& deltaTime) updatePhysics(deltaTime); } +void Player::manageWalkingSounds(const glm::vec3& playerWalkingVector) +{ + constexpr auto noDirection = glm::vec3(0.0f, 0.0f, 0.0f); + switch (mWalkingSound.getStatus()) + { + case sf::Sound::Status::Playing: + if (playerWalkingVector == noDirection or not isOnGround()) + { + mWalkingSound.stop(); + } + break; + case sf::Sound::Status::Paused: + case sf::Sound::Status::Stopped: + if (playerWalkingVector != noDirection and isOnGround()) + { + mWalkingSound.play(); + } + break; + } +} + void Player::handleMovementKeyboardInputs(const float& deltaTime) { auto ACCELERATION_RATIO = 0.1f; @@ -129,6 +133,7 @@ void Player::handleMovementKeyboardInputs(const float& deltaTime) { direction -= mCamera.rightDirectionWithoutPitch(); } + manageWalkingSounds(direction); if (glm::length(direction) > 0.0f) { @@ -152,6 +157,7 @@ void Player::handleEvent(const sf::Event& event) { case sf::Keyboard::Space: tryJump(); break; } + mRifle.handleEvent(event); } Camera& Player::camera() diff --git a/AimGL/src/Player/Player.h b/AimGL/src/Player/Player.h index 3abd424..b2d34ff 100644 --- a/AimGL/src/Player/Player.h +++ b/AimGL/src/Player/Player.h @@ -1,7 +1,7 @@ #pragma once #include -#include #include +#include class Renderer; class Camera; @@ -114,16 +114,19 @@ class Player bool isOnGround() const; /** - * \brief Updates the position of the player's weapon - * \param deltaTime the time that has passed since the game was last updated. + * \brief Manages walking sound effects based on the player's movement. + * \param playerWalkingVector glm::vec3 indicating the direction of player movement. + * A zero vector suggests no movement, while a non-zero vector indicates movement. */ - void updateGunPosition(const float& deltaTime); + void manageWalkingSounds(const glm::vec3& playerWalkingVector); private: Camera mCamera; glm::vec3 mPosition{0, 0, 0}; glm::vec3 mVelocity{0, 0, 0}; - Model mGun; + Rifle mRifle; Texture mCrosshairTexture; Sprite2D mCrosshair; + sf::SoundBuffer mSoundBuffer; + sf::Sound mWalkingSound; }; \ No newline at end of file diff --git a/AimGL/src/Renderer/Graphics/3D/Utils/Rotation3D.cpp b/AimGL/src/Renderer/Graphics/3D/Utils/Rotation3D.cpp index 89107bc..3a5061d 100644 --- a/AimGL/src/Renderer/Graphics/3D/Utils/Rotation3D.cpp +++ b/AimGL/src/Renderer/Graphics/3D/Utils/Rotation3D.cpp @@ -1,6 +1,27 @@ #include "Rotation3D.h" #include "pch.h" +Rotation3D::Rotation3D() + : mRotation(0, 0, 0) +{ +} + +Rotation3D::Rotation3D(float yaw, float pitch, float roll) + : mRotation(yaw, pitch, roll) +{ +} + +Rotation3D::Rotation3D(const Rotation3D& rotation) + : mRotation(rotation.mRotation) +{ +} + +Rotation3D& Rotation3D::operator=(const Rotation3D& rotation) +{ + mRotation = rotation.mRotation; + return *this; +} + glm::mat4 Rotation3D::rotate(glm::mat4 model, std::initializer_list ordering) const { for (const auto axisRotation: ordering) @@ -27,3 +48,51 @@ void Rotation3D::imGuiRotationSlider() ImGui::SliderFloat("Pitch", &pitch, -360, 360.0f); ImGui::SliderFloat("Yaw", &yaw, -360, 360.0f); } + +bool Rotation3D::operator==(const Rotation3D& rhs) const +{ + return mRotation == rhs.mRotation; +} + +Rotation3D Rotation3D::operator+(const Rotation3D& rhs) const +{ + return Rotation3D(mRotation + rhs.mRotation); +} + +Rotation3D Rotation3D::operator-(const Rotation3D& rhs) const +{ + return Rotation3D(mRotation - rhs.mRotation); +} + +Rotation3D Rotation3D::operator*(const Rotation3D& rhs) const +{ + return Rotation3D(mRotation * rhs.mRotation); +} + +Rotation3D& Rotation3D::operator+=(const Rotation3D& rhs) +{ + mRotation += rhs.mRotation; + return *this; +} + +Rotation3D& Rotation3D::operator-=(const Rotation3D& rhs) +{ + mRotation -= rhs.mRotation; + return *this; +} + +Rotation3D& Rotation3D::operator*=(const Rotation3D& rhs) +{ + mRotation *= rhs.mRotation; + return *this; +} + +Rotation3D::operator glm::vec<3, float>() +{ + return mRotation; +} + +Rotation3D::Rotation3D(const glm::vec3& rotation) + : mRotation(rotation) +{ +} diff --git a/AimGL/src/Renderer/Graphics/3D/Utils/Rotation3D.h b/AimGL/src/Renderer/Graphics/3D/Utils/Rotation3D.h index 06955bf..d30a77f 100644 --- a/AimGL/src/Renderer/Graphics/3D/Utils/Rotation3D.h +++ b/AimGL/src/Renderer/Graphics/3D/Utils/Rotation3D.h @@ -3,8 +3,25 @@ /** * \brief Represents a 3D rotation using Euler angles. */ -struct Rotation3D +class Rotation3D { + glm::vec3 mRotation{0, 0, 0}; + +public: + Rotation3D(); + Rotation3D(float yaw, float pitch, float roll); + Rotation3D(const Rotation3D& rotation); + Rotation3D& operator=(const Rotation3D& rotation); + bool operator==(const Rotation3D&) const; + Rotation3D operator+(const Rotation3D&) const; + Rotation3D operator-(const Rotation3D&) const; + Rotation3D operator*(const Rotation3D&) const; + Rotation3D& operator+=(const Rotation3D&); + Rotation3D& operator-=(const Rotation3D&); + Rotation3D& operator*=(const Rotation3D&); + friend Rotation3D operator*(const Rotation3D& lhs, float rhs); + explicit operator glm::vec3(); + /** * \brief Angles of Euler rotation. */ @@ -15,9 +32,9 @@ struct Rotation3D YAW }; - float yaw{0}; - float pitch{0}; - float roll{0}; + float& yaw = mRotation.x; + float& pitch = mRotation.y; + float& roll = mRotation.z; /** * \brief Applies rotation to a 3D model matrix in a specified order. @@ -33,4 +50,18 @@ struct Rotation3D * \brief Renders an ImGui slider interface for adjusting the rotation. */ void imGuiRotationSlider(); + +private: + explicit Rotation3D(const glm::vec3& rotation); }; + + +inline Rotation3D operator*(const Rotation3D& lhs, float rhs) +{ + return Rotation3D(lhs.mRotation * rhs); +} + +inline Rotation3D operator*(float lhs, const Rotation3D& rhs) +{ + return rhs * lhs; +} \ No newline at end of file diff --git a/AimGL/src/States/CustomStates/GameState.cpp b/AimGL/src/States/CustomStates/GameState.cpp index af59a9d..780a9b3 100644 --- a/AimGL/src/States/CustomStates/GameState.cpp +++ b/AimGL/src/States/CustomStates/GameState.cpp @@ -57,7 +57,6 @@ bool GameState::update(const float& deltaTime) { mPhaseInLogoColor.setOpacity(mPhaseInLogoColor.opacity() - deltaTime / 4.f); } - mTree.showDebugImGui("Tree"); return true; } @@ -82,5 +81,6 @@ bool GameState::updateImGui(const float& deltaTime) MTR_SCOPE("GameState", "GameState::updateImGui"); mInfiniteGridFloor.showDebugImGui(); mLogo.showDebugImGui("Logo"); + mTree.showDebugImGui("Tree"); return true; } diff --git a/AimGL/src/World/Camera.cpp b/AimGL/src/World/Camera.cpp index b26b63f..c96528f 100644 --- a/AimGL/src/World/Camera.cpp +++ b/AimGL/src/World/Camera.cpp @@ -3,6 +3,7 @@ #include "Utils/Mouse.h" #include +#include Camera::Camera(const WindowToRender& target) : mRenderTarget(target) @@ -14,8 +15,20 @@ Camera::Camera(const WindowToRender& target) glm::radians(0.0f), static_cast(targetSize.x / targetSize.y), 1.f, 100.f); } +void Camera::updateShakeValues(const float& deltaTime) +{ + constexpr auto tolerance = 2.f; + mCurrentShakeValues = lerp(mCurrentShakeValues, mTargetShakeValues, deltaTime * 6.f); + auto difference = glm::abs(static_cast(mCurrentShakeValues - mTargetShakeValues)); + if (difference.x <= tolerance && difference.y <= tolerance && difference.z <= tolerance) + { + mTargetShakeValues = {0, 0, 0}; + } +} + void Camera::update(const float& deltaTime) { + updateShakeValues(deltaTime); handleMouseInputs(deltaTime); auto width = static_cast(mRenderTarget.getSize().x); @@ -41,15 +54,16 @@ void Camera::handleMouseInputs(const float& deltaTime) void Camera::calculateCameraDirectionVector() { + auto rotation = mRotation + mCurrentShakeValues; glm::vec3 direction; - direction.x = cos(glm::radians(mRotation.yaw)) * cos(glm::radians(mRotation.pitch)); - direction.y = sin(glm::radians(mRotation.pitch)); - direction.z = sin(glm::radians(mRotation.yaw)) * cos(glm::radians(mRotation.pitch)); + direction.x = cos(glm::radians(rotation.yaw)) * cos(glm::radians(rotation.pitch)); + direction.y = sin(glm::radians(rotation.pitch)); + direction.z = sin(glm::radians(rotation.yaw)) * cos(glm::radians(rotation.pitch)); mCameraFront = glm::normalize(direction); - direction.x = cos(glm::radians(mRotation.yaw)); + direction.x = cos(glm::radians(rotation.yaw)); direction.y = 0; - direction.z = sin(glm::radians(mRotation.yaw)); + direction.z = sin(glm::radians(rotation.yaw)); mCameraFrontWithoutPitch = glm::normalize(direction); } @@ -157,6 +171,11 @@ Rotation3D Camera::rotation() const return mRotation; } +void Camera::shake() +{ + mTargetShakeValues = {0.f, 4.f, 0.f}; +} + glm::vec3 Camera::direction() const { return mCameraFront; diff --git a/AimGL/src/World/Camera.h b/AimGL/src/World/Camera.h index bab2f8b..6409268 100644 --- a/AimGL/src/World/Camera.h +++ b/AimGL/src/World/Camera.h @@ -106,6 +106,11 @@ class Camera */ Rotation3D rotation() const; + /** + * \brief Shakes the camera + */ + void shake(); + private: /** * Handle keyboard behavior such as moving the camera inside the game @@ -149,19 +154,28 @@ class Camera void calculateCameraAngles(const float& deltaTime); /** - * Calculates the camera's directional vector, which is the final\ + * Calculates the camera's directional vector, which is the final * vector responsible for the camera's rotation. */ void calculateCameraDirectionVector(); - const WindowToRender& mRenderTarget; + /** + * \brief Updates the values responsible for shaking the camera + * \param deltaTime the time that has passed since the game was last updated. + */ + void updateShakeValues(const float& deltaTime); +private: + const WindowToRender& mRenderTarget; glm::vec3 mCameraPosition = glm::vec3(0, 0, 0); glm::vec3 mCameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 mCameraUp = glm::vec3(0.0f, 1.0f, 0.0f); glm::vec3 mCameraFrontWithoutPitch = glm::vec3(0.0f, 0.0f, -1.0f); Rotation3D mRotation{-90, 0, 0.f}; + Rotation3D mTargetShakeValues{0, 0, 0}; + Rotation3D mCurrentShakeValues{0, 0, 0}; + float mCameraSpeed = 5.f; float mCameraSensitivity = 4.f; float mFovCamera = 90.0f; diff --git a/AimGL/src/World/GameObjects/Rifle.cpp b/AimGL/src/World/GameObjects/Rifle.cpp new file mode 100644 index 0000000..fc93405 --- /dev/null +++ b/AimGL/src/World/GameObjects/Rifle.cpp @@ -0,0 +1,62 @@ +#include "Rifle.h" +#include "pch.h" + +#include +#include + +Rifle::Rifle(Camera& camera) + : mCamera(camera) + , mGun("resources/Models/ak47/ak47.obj", + {{"resources/Models/ak47/ak47-alternative.png", Texture::Type::Diffuse}, + {"resources/Models/ak47/ak47-alternative-specular.png", Texture::Type::Specular}}) +{ + mSoundBuffer.loadFromFile("resources/Sounds/gunshot.wav"); + mGunShotSound.setBuffer(mSoundBuffer); +} + +void Rifle::draw(const Renderer& target) const +{ + mGun.draw(target, mCamera); +} + +void Rifle::update(const float& deltaTime) +{ + updateAttachToCamera(deltaTime); +} + +void Rifle::updateAttachToCamera(const float& deltaTime) +{ + auto backward = -mCamera.direction(); + auto recoilOffset = backward * mCurrentRecoil; + + const glm::vec3 rotationOrigin = {0.3f, -0.2f, -0.35f}; + const auto cameraPosition = mCamera.cameraPosition(); + glm::vec3 targetPosition = {cameraPosition.x + rotationOrigin.x, cameraPosition.y - 0.3f, + cameraPosition.z + rotationOrigin.z}; + + targetPosition += recoilOffset; + + const auto gunPosition = lerp(mGun.position(), targetPosition, deltaTime * 30.f); + mGun.setPosition(gunPosition, Model::Origin::Center); + mGun.setRotationOrigin(rotationOrigin); + + const auto gunTargetPitch = + lerp(mGun.rotation().pitch, mCamera.rotation().pitch, deltaTime * 20.f); + const auto gunTargetYaw = + lerp(mGun.rotation().yaw, -(mCamera.rotation().yaw + 90), deltaTime * 20.f); + mGun.setRotation({gunTargetYaw, gunTargetPitch, 0}); + + mCurrentRecoil -= deltaTime; + mCurrentRecoil = std::max(mCurrentRecoil, 0.0f); +} + +void Rifle::handleEvent(const sf::Event& event) +{ + if (event.type == sf::Event::MouseButtonPressed && event.key.code == sf::Mouse::Left) + { + mCurrentRecoil += RECOIL_OFFSET_INCREMENT; + mCurrentRecoil = std::min(mCurrentRecoil, RECOIL_OFFSET_MAX); + mCamera.shake(); + mGunShotSound.play(); + } +} diff --git a/AimGL/src/World/GameObjects/Rifle.h b/AimGL/src/World/GameObjects/Rifle.h new file mode 100644 index 0000000..f8a29f2 --- /dev/null +++ b/AimGL/src/World/GameObjects/Rifle.h @@ -0,0 +1,54 @@ +#pragma once +#include +#include +#include + +class Renderer; +class Camera; + +/** + * \brief TODO: THIS + */ +class Rifle +{ +public: + /** + * \brief TODO: THIS + * \param camera TODO: THIS + */ + explicit Rifle(Camera& camera); + + /** + * \brief Draws a Rifle to a given target + * \param target The target to which the sprite is drawn + */ + void draw(const Renderer& target) const; + + /** + * Updates the Player logic dependent, or independent of time, every rendered frame. + * \param deltaTime the time that has passed since the game was last updated. + */ + void update(const float& deltaTime); + + /** + * \brief It takes input (event) from the user and interprets it + * \param event user input + */ + void handleEvent(const sf::Event& event); + +private: + /** + * \brief TODO: THIS + * \param deltaTime TODO: THIS + */ + void updateAttachToCamera(const float& deltaTime); + +private: + Model mGun; + Camera& mCamera; + static constexpr auto RECOIL_OFFSET_INCREMENT = 0.2f; + static constexpr auto RECOIL_OFFSET_MAX = 0.3f; + float mCurrentRecoil{0}; + sf::SoundBuffer mSoundBuffer; + sf::Sound mGunShotSound; +}; \ No newline at end of file