6 Commits

Author SHA1 Message Date
cd4fb0a7ec Merge branch 'main' into gestionnaireajoutkick
All checks were successful
Linux arm64 / Build (push) Successful in 5m3s
2024-04-11 17:20:56 +02:00
582a66d4eb Merge branch 'main' into gestionnaireajoutkick
Some checks are pending
Linux arm64 / Build (push) Waiting to run
2024-04-11 17:18:39 +02:00
9a6642b1ad Update BlitzConfig.h and LeaderBoardGui.cpp, and fix kick button size in ServerGui.cpp
All checks were successful
Linux arm64 / Build (push) Successful in 22m42s
2024-04-11 11:56:11 +02:00
d823dfa9d7 Squashed commit of the following:
Some checks are pending
Linux arm64 / Build (push) Waiting to run
commit 98fcb30f68
Author: Morph01 <thibaut6969delastreet@gmail.com>
Date:   Tue Apr 9 19:19:51 2024 +0200

    update color interface
2024-04-11 11:41:33 +02:00
028715d3b5 interface fonctionnelle
All checks were successful
Linux arm64 / Build (push) Successful in 23m29s
2024-04-11 09:20:00 +02:00
d4902214ae Gestionnaire d'ajout de joueurs et de kick
All checks were successful
Linux arm64 / Build (push) Successful in 23m16s
2024-04-10 10:03:25 +02:00
64 changed files with 378 additions and 1085 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -253,7 +253,7 @@ class DataBuffer {
* \brief Write a file into the buffer
* \param fileName The name of the file to write to
*/
bool WriteFile(const std::string& fileName) const;
bool WriteFile(const std::string& fileName);
/**
* \brief Allocate the buffer on the heap

View File

@@ -3,7 +3,7 @@
/**
* \file Defines.h
* \brief File containing constants and typedefs
*/
*/
#include <cstdint>
@@ -13,20 +13,8 @@ namespace game {
/**
* \typedef PlayerID
* \brief Represents the identifier of a Player
*/
*/
typedef std::uint8_t PlayerID;
/**
* \enum GameState
* \brief The states of the game
*/
enum GameState : std::uint8_t {
gsNone = 0, /**< Default state */
gsWaiting, /**< Waiting state if the number of players is less than 2 */
gsPreparing, /**< Preparing state until the game start */
gsGame, /**< Game state during the players can shoot and kill ... */
gsEnd, /**< End state of the game : show the winner of the game and the leaderboard*/
};
} // namespace game
} // namespace blitz

View File

@@ -2,38 +2,17 @@
namespace blitz {
/**
* \struct An exponential moving average smoother, or one pole lowpass filter
* smoothes incoming data by attenutating sharp/sudden changes
*/
class EMASmoother {
private:
float Alpha;
float GetAlpha();
void SetAlpha(float alpha);
public:
/**
* \brief the current output value of the smoother
*/
float Current;
EMASmoother();
/**
* \brief behaves like `Tick(target, 1.0f)` but optimised
*/
void TickUnitT(float target);
/**
* \brief feed in the next value to the filter, and update `Current` accordingly
* \param target the value in question
* \param delta the time that has passed sinced the last value has been provided
*/
void Tick(float target, float delta);
/**
* \brief set the amount of time it should take to reacha certain value, the higher this is
* the "smoother the output signal"
*/
float GetAlpha();
void SetAlpha(float alpha);
void SetSmoothingTime(float t);
};

View File

@@ -6,12 +6,8 @@
*/
#include "Player.h"
#include "blitz/game/Listeners.h"
#include "blitz/game/World.h"
#include "blitz/misc/ObjectNotifier.h"
#include "blitz/misc/Time.h"
#include <map>
#include <memory>
namespace blitz {
namespace game {
@@ -22,6 +18,18 @@ namespace game {
*/
typedef std::map<PlayerID, Player> PlayerMap;
/**
* \enum GameState
* \brief The states of the game
*/
enum GameState : std::uint8_t {
gsNone = 0, /**< Default state */
gsWaiting, /**< Waiting state if the number of players is less than 2 */
gsPreparing, /**< Preparing state until the game start */
gsGame, /**< Game state during the players can shoot and kill ... */
gsEnd, /**< End state of the game : show the winner of the game and the leaderboard*/
};
/**
* \brief The game configuration
* \struct GameConfig
@@ -41,13 +49,12 @@ struct GameConfig {
* \class Game
* \brief Class representing a game
*/
class Game : public utils::ObjectNotifier<GameListener> {
class Game {
protected:
PlayerMap m_Players;
GameState m_GameState;
utils::Timer m_GameTimer;
GameConfig m_Config;
std::unique_ptr<World> m_World;
public:
/** \brief Default constructor */
@@ -97,12 +104,6 @@ class Game : public utils::ObjectNotifier<GameListener> {
return m_GameState;
}
/**
* \brief Set the game state
* \return The game state
*/
virtual void UpdateGameState(GameState newGameState, std::uint64_t timeRemaining);
/**
* \brief Load the game configuration
* \param config The game configuration to load
@@ -138,13 +139,6 @@ class Game : public utils::ObjectNotifier<GameListener> {
std::uint64_t GetGameStateRemainingTime() const {
return m_GameTimer.GetTimeRemaining();
}
/**
* \return The world associated with this game
*/
const World* GetWorld() const {
return m_World.get();
}
};

View File

@@ -21,19 +21,11 @@ class PlayerInputListener {
virtual void OnLocalPlayerShoot(const Vec3f& position, float yaw, float pitch) {}
};
class GameListener {
public:
virtual void OnPlayerJoin(game::PlayerID player) {}
virtual void OnPlayerLeave(game::PlayerID player) {}
virtual void OnGameStateUpdate(game::GameState newState) {}
};
class ClientListener {
public:
virtual void OnTextChatReceived(const protocol::ColoredText& text) {}
virtual void OnSpectatorChange(game::PlayerID player) {}
virtual void OnPlayerShoot(PlayerID player, const Vec3f& position, float yaw, float pitch) {}
virtual void OnClientPlayerJoin() {}
virtual void OnGameConfigUpdate() {}
virtual void OnGameJoin() {}
virtual void OnGameLeave() {}

View File

@@ -7,7 +7,6 @@
#include "blitz/common/Defines.h"
#include "blitz/maths/Vector.h"
#include "blitz/maths/Physics.h"
#include <cstdint>
#include <string>
@@ -43,7 +42,6 @@ struct PlayerStats {
*/
class Player {
private:
maths::AABB m_Hitbox;
PlayerID m_ID;
std::string m_Name;
Vec3f m_Position;
@@ -85,20 +83,6 @@ class Player {
m_Name = name;
}
/**
* \brief Get the player's hitbox
*/
maths::AABB GetHitBox() const {
return m_Hitbox + m_Position;
}
/**
* \brief Sets the player's hitbox
*/
void SetHitBoxSize(const maths::AABB& aabb) {
m_Hitbox = aabb;
}
/**
* \brief Get the position of the player
* \return The position of the player

View File

@@ -1,27 +0,0 @@
#pragma once
#include "blitz/game/Listeners.h"
#include "blitz/maths/Physics.h"
#include <vector>
namespace blitz {
namespace game {
class Game;
class World {
protected:
Game* m_Game;
std::vector<maths::AABB> m_AABBs;
public:
World(Game* game);
virtual ~World();
const std::vector<maths::AABB>& GetAABBs() const {
return m_AABBs;
}
};
} // namespace game
} // namespace blitz

View File

@@ -128,32 +128,18 @@ T ReduceMax(const Vec3<T>& vect) {
* \param v a vector
* \return the (signed) minimal coordinate of the vector
*/
inline float ReduceFMinF(const Vec3f& v) {
template <>
inline float ReduceMin<float>(const Vec3f& v) {
return std::fminf(std::fminf(v.x, v.y), v.z);
}
inline Vec3f FmaF(const Vec3f& v, const Vec3f& a, const Vec3f& b) {
return {
std::fmaf(v.x, a.x, b.x),
std::fmaf(v.y, a.y, b.y),
std::fmaf(v.z, a.z, b.z),
};
}
inline Vec3d Fma(const Vec3d& v, const Vec3d& a, const Vec3d& b) {
return {
std::fma(v.x, a.x, b.x),
std::fma(v.y, a.y, b.y),
std::fma(v.z, a.z, b.z),
};
}
/**
* \brief Returns the (signed) maximal coordinate of the vector
* \param v a vector
* \return the (signed) maximal coordinate of the vector
*/
inline float ReduceFMaxF(const Vec3f& v) {
template <>
inline float ReduceMax<float>(const Vec3f& v) {
return std::fmaxf(std::fmaxf(v.x, v.y), v.z);
}
@@ -162,7 +148,8 @@ inline float ReduceFMaxF(const Vec3f& v) {
* \param v a vector
* \return the (signed) minimal coordinate of the vector
*/
inline double ReduceFMin(const Vec3d& v) {
template <>
inline double ReduceMin<double>(const Vec3d& v) {
return std::fmin(std::fmin(v.x, v.y), v.z);
}
@@ -171,7 +158,8 @@ inline double ReduceFMin(const Vec3d& v) {
* \param v a vector
* \return the (signed) maximal coordinate of the vector
*/
inline double ReduceFMax(const Vec3d& v) {
template <>
inline double ReduceMax<double>(const Vec3d& v) {
return std::fmax(std::fmax(v.x, v.y), v.z);
}
@@ -194,30 +182,13 @@ constexpr Vec3<T> Min(const Vec3<T>& self, const Vec3<T>& other) {
}
/**
* @brief returns the coordinate-wise minimum of the given vectors,
* where a coordinate in the returned vector is NAN iff both of the two compared ones are NAN
*
* @tparam T
* @param self
* @param other
* @return constexpr Vec3f
*/
constexpr Vec3f FMinF(const Vec3f& self, const Vec3f& other) {
return {
std::fminf(self.x, other.x),
std::fminf(self.y, other.y),
std::fminf(self.z, other.z),
};
}
/**
* @brief returns the coordinate-wise maximum of the given vectors,
* \brief returns the coordinate-wise maximum of the given vectors,
* where a coordinate in the returned vector is NAN iff any of the two compared ones are NAN
* \tparam T
* \param self a vector
* \param other an other vector
* \return returns the coordinate-wise maximum of the given vectors,
* where a coordinate in the returned vector is NAN iff any of the two compared ones are NAN
*
* @tparam T
* @param self
* @param other
* @return constexpr Vec3
*/
template <typename T>
constexpr Vec3<T> Max(const Vec3<T>& self, const Vec3<T>& other) {
@@ -228,47 +199,8 @@ constexpr Vec3<T> Max(const Vec3<T>& self, const Vec3<T>& other) {
};
}
/**
* @brief returns the coordinate-wise maximum of the given vectors,
* where a coordinate in the returned vector is NAN iff both of the two compared ones are NAN
*
* @tparam T
* @param self
* @param other
* @return constexpr Vec3
*/
constexpr Vec3f FMaxF(const Vec3f& self, const Vec3f& other) {
return {
std::fmaxf(self.x, other.x),
std::fmaxf(self.y, other.y),
std::fmaxf(self.z, other.z),
};
}
/**
* @brief lane-wise copysign
*/
constexpr Vec3f CopysignF(const Vec3f& v, const Vec3f& signs) {
return {
std::copysignf(v.x, signs.x),
std::copysignf(v.y, signs.y),
std::copysignf(v.z, signs.z),
};
}
/**
* @brief lane-wise copysign
*/
constexpr Vec3d Copysign(const Vec3d& v, const Vec3d& signs) {
return {
std::copysign(v.x, signs.x),
std::copysign(v.y, signs.y),
std::copysign(v.z, signs.z),
};
}
//////////////////////////////////////////////////////////////////
// Matrices //
// Matricies //
//////////////////////////////////////////////////////////////////
/**
@@ -418,16 +350,5 @@ Mat4f Rotate(const Vec3f& angles);
*/
Mat4f Rotate(float angle, Vec3f axis);
/**
* \brief Returns the unit vector correspond to the yaw and pitch
* \param yaw Angle in radians
* \param pitch Angle in radians
*/
Vec3f GetDirectionVectorFromRotation(float yaw, float pitch);
} // namespace maths
} // namespace blitz

View File

@@ -1,149 +1,30 @@
#pragma once
/**
* \file Physics.h
* \brief Physics logic
*/
#include "blitz/maths/Maths.h"
#include <optional>
#include "blitz/maths/Vector.h"
namespace blitz {
namespace maths {
/**
* \enum Axis
* \brief represents an axis in 3-dimensional space
*/
enum Axis : std::size_t { aX = 0, aY, aZ };
/**
* \brief encodes the movement an entity must perform, in an environment containing other
* entitis it may collide with
*/
struct CollisionData {
/**
* \brief the effective movement the entity can/should perform, immediately
*/
Vec3f delta;
/**
* \brief the direction of "slide" along a side of a bounding
* box, this is 0 if no collisions occured
*/
Vec3f slide;
struct Ray {
Vec3f origin;
Vec3f direction;
};
/**
* \struct IntersectionData
* \brief Intermediate data encoding an intersection between a Ray/AABB and an AABB
*/
struct IntersectionData {
/**
* \brief by how much to translate before intersecting with the AABB
*/
float distance;
/**
* \brief the axis along which the collision happens, used to solve sliding requirements
*/
Axis axis;
/**
* \brief Returns the movements that the entity must perform. It is advised to make sure
* `0.0f <= distance <= 1.0f` as this would return incoherent data
* \pre `0.0f <= distance <= 1.0f`
* \param dir
* \return
*/
CollisionData ToCollision(const Vec3f& dir) const;
};
/**
* \struct AABB
* \brief an Axis Aligned Bounding Box, see wikipedia for more
*/
struct AABB {
Vec3f from;
Vec3f to;
/**
* \return A vector representing the center of mass of the box
*/
inline Vec3f Center() const;
/**
* \return The same box but all the coordinates in `from` are less than their
* counterparts in `to`.
*/
AABB Direct() const;
/**
* \brief Enlarges this box along each axis by the length of the box along said axis
* \param with
* \return The new, big, box
*
*/
AABB Enlarge(const AABB& with) const;
AABB operator+(const Vec3f& offset) const;
AABB operator+=(const Vec3f& offset);
/**
* \brief checks if this box overlaps with another one
* \param aabb
* \return whether this box overlaps with another one
*/
bool OverlapsWith(const AABB& aabb) const;
/**
* \brief Given this box is to be offset by some vector colinear to dir,
* this function behave exactly like Ray::Intersection
* \param aabb
* \param dir
* \return
*/
std::optional<IntersectionData> Intersection(const AABB& aabb, const Vec3f& dir) const;
};
/**
* \struct Ray
* \brief represents a (half-)line
*/
struct Ray {
/**
* \brief the origin/start/initial point of the line
*/
Vec3f origin;
/**
* \brief the direction of the line
*/
Vec3f direction;
inline AABB operator+(const AABB& aabb, const Vec3f& offset) {
AABB result = aabb;
result.from += offset;
result.to += offset;
return result;
}
/**
* \brief Note that t isn't necessarily positive
* \param t
* \return `origin` + `direction` * `t`
*/
Vec3f operator()(float t) const;
float Distance(const Ray& ray, const AABB& aabb);
/**
* \brief Is essentially Intersection(aabb).distance >= 0.0f
* \returns `true` if the half-line `ray` _strictly_ intersects with `aabb`,
* and `false` if it _strictly_ doesn't intersect.
* Note that if it only intersects with corners, edges, or sides of the box,
* or if any coordinate in `ray` is `NAN` or `inf` or if any coordinate in
* `aabb` is `NAN` the result is unspecified.
*/
bool Intersects(const AABB& aabb) const;
/**
* \brief The `distance` field of the returned value is smallest number t
* (in absolute value), if it exists, such that `ray(t)` is in `aabb`. otherwise
* a quiet `NaN` is returned. The `axis` field is the axis to along
* which `ray` intersects/collides with `aabb`
*/
std::optional<IntersectionData> Intersection(const AABB& aabb) const;
};
bool Intersects(const Ray& ray, const AABB& aabb);
} // namespace maths
} // namespace blitz

View File

@@ -6,6 +6,7 @@
*/
#include <algorithm>
#include <cmath>
#include <cstddef>
namespace blitz {
@@ -47,34 +48,6 @@ struct Vec3 {
};
constexpr Vec3(T X = 0, T Y = 0, T Z = 0) : x(X), y(Y), z(Z) {}
static Vec3 splat(T val) {
return Vec3(val, val, val);
}
const T* data() const {
return reinterpret_cast<const T*>(this);
}
T* data() {
return reinterpret_cast<T*>(this);
}
const T& at(std::size_t index) const {
return data()[index];
}
T& at(std::size_t index) {
return data()[index];
}
const T& operator[](std::size_t index) const {
return at(index);
}
T& operator[](std::size_t index) {
return at(index);
}
};
template <typename T>
@@ -123,6 +96,10 @@ using Vec4d = Vec4<double>;
using Color = Vec3uc;
// Vec2
template <typename T>
@@ -167,6 +144,10 @@ constexpr Vec2<T> operator*(T mult, const Vec2<T>& vect) {
return vect * mult;
}
// Vec3
template <typename T>
@@ -245,6 +226,11 @@ Vec3<T>& operator/=(Vec3<T>& vect, const Vec3<T>& other) {
return vect;
}
template <typename T>
constexpr bool operator<(const Vec3<T>& vec3, const Vec3<T>& other) {
return vec3.x < other.x && vec3.y < other.y && vec3.z < other.z;
}
// Vec4
template <typename T>

View File

@@ -45,7 +45,7 @@ class ObjectNotifier {
* \brief Notify listeners that were bound
*/
template <typename Func, typename... Args>
void NotifyListeners(Func function, Args... args) const {
void NotifyListeners(Func function, Args... args) {
for (Listener* listener : m_Listeners)
std::bind(function, listener, args...)();
}

View File

@@ -3,31 +3,19 @@
#include "blitz/game/Listeners.h"
#include "client/audio/AudioListener.h"
#include "client/audio/AudioSource.h"
#include <map>
namespace blitz {
class Client;
namespace game {
class Player;
} // namespace game
namespace audio {
struct PlayerSound {
AudioSourcePtr m_Laser;
};
class AudioManager : public game::ClientListener, public game::GameListener {
class AudioManager : public game::ClientListener {
private:
Client* m_Client;
game::Player* m_Player;
AudioListener m_Listener;
AudioSourcePtr m_MenuMusic;
AudioBufferPtr m_LaserSound;
std::map<game::PlayerID, PlayerSound> m_PlayerSources;
std::vector<AudioSourcePtr> m_Sources;
public:
AudioManager(Client* client);
@@ -35,20 +23,9 @@ class AudioManager : public game::ClientListener, public game::GameListener {
virtual void OnGameJoin() override;
virtual void OnGameLeave() override;
virtual void OnClientPlayerJoin() override;
virtual void OnPlayerShoot(game::PlayerID player, const Vec3f& position, float yaw, float pitch) override;
virtual void OnPlayerJoin(game::PlayerID player) override;
virtual void OnPlayerLeave(game::PlayerID player) override;
void SetGlobalVolume(float volume);
void Update();
private:
void InitSounds();
AudioSourcePtr InitSourceFromFile(const std::string& fileName);
AudioSourcePtr InitSourceFromBuffer(const AudioBufferPtr& buffer);
AudioBufferPtr InitBufferFromFile(const std::string& fileName);
void InitMainMenuMusic();
};
} // namespace audio

View File

@@ -8,7 +8,7 @@
namespace blitz {
namespace audio {
typedef std::shared_ptr<AudioBuffer> AudioBufferPtr;
typedef std::unique_ptr<AudioBuffer> AudioBufferPtr;
class AudioSource : NonCopyable {
private:
@@ -27,8 +27,7 @@ class AudioSource : NonCopyable {
void SetDirection(const Vec3f& a_Direction);
void SetVelocity(const Vec3f& a_Velocity);
void SetLooping(bool a_Looping);
void SetRelative(bool a_Relative);
void SetBuffer(const AudioBufferPtr& a_Buffer);
void SetBuffer(AudioBufferPtr&& a_Buffer);
SourceState GetSourceState() const;

View File

@@ -5,8 +5,6 @@
* \brief File containing the blitz::Display class
*/
#include "client/display/InputManager.h"
#include "client/display/PlayerController.h"
#include <memory>
#include <string>
@@ -38,9 +36,7 @@ class Display {
bool m_FullScreen;
Client* m_Client;
input::InputManager& m_InputManager;
std::unique_ptr<gui::BlitzGui> m_BlitzGui;
input::PlayerController m_PlayerController;
public:
/**
@@ -49,33 +45,28 @@ class Display {
* \param height The height of the window
* \param windowName The name of the window
* \param client The client
* \param inputManager The InputManager
*/
Display(int width, int height, const std::string& windowName, Client* client, input::InputManager& inputManager);
Display(int width, int height, const std::string& windowName, Client* client);
~Display();
/**
* \brief Return whether the display has been created
*/
bool Create();
/**
* \brief Poll the events
* \note This function should be called at the beginning of the main loop
*/
void PollEvents();
/**
* \brief Update the display
* \note Swap the buffers
*/
void Update();
/**
* \brief Render the display (ImGui)
*/
void Render();
/**
* \brief Destroy the display (Not your mother's display)
*/
@@ -90,24 +81,15 @@ class Display {
* \brief Return widht/height ratio
*/
float GetAspectRatio();
/**
* \brief Return the window width
*/
int GetWindowWidth();
/**
* \brief Return the window height
*/
int GetWindowHeight();
/**
* \brief Return the player controller
*/
input::PlayerController& GetPlayerController() {
return m_PlayerController;
}
private:
void InitImGui();
};

View File

@@ -1,30 +1,19 @@
#pragma once
#include "blitz/misc/ObjectNotifier.h"
#include <SDL2/SDL_events.h>
#include <functional>
namespace blitz {
namespace input {
namespace InputManager {
class InputListener {
public:
virtual void OnKeyDown(int imguiKey) {}
virtual void OnMouseMove(int deltaX, int deltaY) {}
};
typedef std::function<void(int)> KeyDownCallback;
typedef std::function<void(int, int)> MouseMoveCallback;
class InputManager : public utils::ObjectNotifier<InputListener> {
private:
bool m_MouseInputGrabbed;
void BindKeyDownCallback(const KeyDownCallback&);
void BindMouseMoveCallback(const MouseMoveCallback&);
void ProcessEvent(SDL_Event& event);
void GrabMouse(bool grabInput);
bool MouseGrabbed();
public:
InputManager() : m_MouseInputGrabbed(false) {}
virtual ~InputManager() {}
void ProcessEvent(SDL_Event& event) const;
void GrabMouse(bool grabInput);
bool MouseGrabbed() const;
};
} // namespace input
} // namespace InputManager
} // namespace blitz

View File

@@ -9,7 +9,6 @@
#include "blitz/game/Listeners.h"
#include "blitz/misc/ObjectNotifier.h"
#include "blitz/misc/Time.h"
#include "client/display/InputManager.h"
namespace blitz {
@@ -28,11 +27,10 @@ namespace input {
* \details This class is responsible for handling player input and sending it to the server.
* It also handles the player's velocity and position.
*/
class PlayerController : public utils::ObjectNotifier<game::PlayerInputListener>, game::ClientListener, InputListener {
class PlayerController : public utils::ObjectNotifier<game::PlayerInputListener>, game::ClientListener {
private:
game::Player* m_Player;
Client* m_Client;
input::InputManager& m_InputManager;
utils::CooldownTimer<float> m_ShootTimer{1.0f};
EMASmoother m_DxSmoother;
EMASmoother m_DySmoother;
@@ -47,8 +45,7 @@ class PlayerController : public utils::ObjectNotifier<game::PlayerInputListener>
/**
* \brief Default constructor
*/
PlayerController(Client* client, input::InputManager& inputManager);
virtual ~PlayerController();
PlayerController(Client* client);
/**
* \brief Update things like player position and velocity.
@@ -56,16 +53,27 @@ class PlayerController : public utils::ObjectNotifier<game::PlayerInputListener>
void Update(float delta);
virtual void OnGameConfigUpdate() override;
virtual void OnClientPlayerJoin() override;
virtual void OnGameLeave() override;
virtual void OnMouseMove(int, int) override;
/**
* \brief Set the player that this controller is attached to.
* \param a_Player The player to attach to.
*/
void SetAttachedPlayer(game::Player* a_Player) {
m_Player = a_Player;
}
/**
* \brief Get the player that this controller is attached to.
* \return The player that this controller is attached to.
*/
game::Player* GetAttachedPlayer() {
return m_Player;
}
private:
void UpdateShootTimer(int bpm);
void MouseMotionEvent(int, int);
void UpdatePosition(float delta);
void ApplyForce(const Vec3f& f, float delta);
void ApplyGravity(float delta);
};
} // namespace input

View File

@@ -1,20 +0,0 @@
#pragma once
#include "blitz/game/World.h"
namespace blitz {
namespace client {
class ClientGame;
class ClientWorld : public game::World {
public:
ClientWorld(ClientGame* game);
virtual ~ClientWorld() {}
private:
void LoadAABBs();
};
} // namespace client
} // namespace blitz

View File

@@ -1,7 +1,6 @@
#pragma once
#include "GuiWidget.h"
#include "client/display/InputManager.h"
namespace blitz {
@@ -14,7 +13,7 @@ class BlitzGui : public GuiWidget {
enum SubMenu { Main = 0 };
public:
BlitzGui(Client* client, input::InputManager& inputManager);
BlitzGui(Client* client);
virtual void Render() override;

View File

@@ -1,7 +1,6 @@
#pragma once
#include "GuiWidget.h"
#include "client/display/InputManager.h"
namespace blitz {
@@ -10,11 +9,8 @@ class Client;
namespace gui {
class CreateGameMenu : public GuiWidget {
private:
input::InputManager& m_InputManager;
public:
CreateGameMenu(GuiWidget* parent, Client* client, input::InputManager& inputManager);
CreateGameMenu(GuiWidget* parent, Client* client) : GuiWidget(parent, client) {}
virtual void Render() override;
};

View File

@@ -2,7 +2,6 @@
#include "GuiWidget.h"
#include "client/Client.h"
#include "client/display/InputManager.h"
#include <string>
#include <vector>
@@ -20,15 +19,13 @@ class GameChatGui : public GuiWidget, game::ClientListener {
bool ScrollToBottom = false;
bool AutoScroll = true;
float m_ChatDisplay = 0;
input::InputManager& m_InputManager;
void Draw(const char* title, bool* p_open);
void DrawMini(const char* title, bool* p_open);
public:
GameChatGui(GuiWidget* parent, Client* client, input::InputManager& inputManager);
virtual ~GameChatGui();
GameChatGui(GuiWidget* parent, Client* client);
virtual void OnTextChatReceived(const protocol::ColoredText& text) override;

View File

@@ -1,7 +1,6 @@
#pragma once
#include "GuiWidget.h"
#include "client/display/InputManager.h"
namespace blitz {
@@ -10,11 +9,8 @@ class Client;
namespace gui {
class JoinGameMenu : public GuiWidget {
private:
input::InputManager& m_InputManager;
public:
JoinGameMenu(GuiWidget* parent, Client* client, input::InputManager& inputManager);
JoinGameMenu(GuiWidget* parent, Client* client) : GuiWidget(parent, client) {}
virtual void Render() override;
};

View File

@@ -1,29 +1,19 @@
#pragma once
#include "GuiWidget.h"
#include "blitz/game/Listeners.h"
namespace blitz {
class Client;
namespace input {
class InputManager;
} // namespace input
namespace gui {
class MainMenu : public GuiWidget, public game::ClientListener {
class MainMenu : public GuiWidget {
private:
enum SubMenu { CREATE_MENU = 0, JOIN_MENU, OPTION_MENU };
input::InputManager& m_InputManager;
public:
MainMenu(Client* client, input::InputManager& inputManager);
virtual ~MainMenu();
virtual void OnGameLeave() override;
MainMenu(Client* client);
virtual void Render() override;
};

View File

@@ -3,7 +3,6 @@
#include "GuiWidget.h"
#include "blitz/misc/Time.h"
#include "client/config/BlitzConfig.h"
#include "client/display/InputManager.h"
#include <array>
#include <string>
@@ -13,7 +12,7 @@ class Client;
namespace gui {
class OptionsMenu : public GuiWidget, public input::InputListener {
class OptionsMenu : public GuiWidget {
private:
bool m_ShowFPS;
bool m_VSync;
@@ -21,15 +20,13 @@ class OptionsMenu : public GuiWidget, public input::InputListener {
bool m_KeyPopupShouldClose;
utils::Timer m_Timer{100};
KeyAction m_CurrentAction;
input::InputManager& m_InputManager;
public:
OptionsMenu(GuiWidget* parent, Client* client, input::InputManager& inputManager);
virtual ~OptionsMenu();
OptionsMenu(GuiWidget* parent, Client* client);
virtual void Render() override;
virtual void OnKeyDown(int key) override;
void OnKeyEvent(int key);
private:
std::string GetKeyActionCodeName(KeyAction);

View File

@@ -1,17 +1,13 @@
#pragma once
#include "GuiWidget.h"
#include "client/display/InputManager.h"
namespace blitz {
namespace gui {
class ServerGui : public GuiWidget {
private:
input::InputManager& m_InputManager;
public:
ServerGui(GuiWidget* parent, Client* client, input::InputManager& inputManager);
ServerGui(GuiWidget* parent, Client* client);
virtual void Render() override;
};

View File

@@ -37,7 +37,6 @@ class BulletRenderer {
void AddBullet(const Vec3f& origin, float yaw, float pitch, bool firstPersson);
void Update(float delta);
void Render();
void Clear();
};
} // namespace render

View File

@@ -29,14 +29,14 @@ class MainRenderer : public game::ClientListener, public game::PlayerInputListen
std::unique_ptr<shader::EntityShader> m_EntityShader;
std::unique_ptr<shader::WorldShader> m_WorldShader;
std::unique_ptr<shader::GunShader> m_GunShader;
input::PlayerController m_PlayerController;
unsigned int m_Texture;
float m_ShootTime;
Camera m_Camera;
BulletRenderer m_BulletRenderer;
input::PlayerController& m_PlayerController;
public:
MainRenderer(Client* client, input::PlayerController& playerController);
MainRenderer(Client* client);
~MainRenderer();
virtual void OnSpectatorChange(game::PlayerID player) override;
@@ -44,7 +44,6 @@ class MainRenderer : public game::ClientListener, public game::PlayerInputListen
virtual void OnLocalPlayerShoot(const Vec3f& position, float yaw, float pitch) override;
virtual void OnGameConfigUpdate() override;
virtual void OnGameLeave() override;
void Update();
void Render();

View File

@@ -1,6 +1,5 @@
#pragma once
#include "blitz/maths/Physics.h"
#include "client/render/loader/GLLoader.h"
#include <memory>
#include <string>
@@ -17,7 +16,5 @@ struct Model {
Model LoadModel(const std::string& fileName);
std::vector<maths::AABB> LoadModelAABBs(const std::string& fileName);
} // namespace ModelLoader
} // namespace blitz

View File

@@ -44,8 +44,6 @@ class Server {
std::thread m_Thread;
bool m_ServerRunning;
game::PlayerID m_FreePlayerID;
public:
/**
* \brief Constructor
@@ -78,7 +76,7 @@ class Server {
/**
* \brief Forcefully remove a player from the game
* \param player the id of the player to remove
*/
*/
void KickPlayer(game::PlayerID player);
/**

View File

@@ -74,7 +74,7 @@ class ServerGame : public game::Game {
* \param gameState The game state
* \param duration The duration in milliseconds
*/
virtual void UpdateGameState(game::GameState gameState, std::uint64_t duration) override;
void SetGameState(game::GameState gameState, std::uint64_t duration);
/**
* \brief Get the server duration
@@ -97,7 +97,6 @@ class ServerGame : public game::Game {
void StartGame(); // when at least 2 players joined
void CancelGame(); // when not enough players are left
void ResetPlayerStats();
void InitGameConfig();
};
} // namespace server

View File

@@ -19,7 +19,7 @@
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
struct SDL_Window;
class SDL_Window;
struct SDL_Renderer;
typedef union SDL_Event SDL_Event;

View File

@@ -2,19 +2,17 @@
#include "client/Client.h"
#include "client/audio/AudioManager.h"
#include "client/display/Display.h"
#include "client/display/InputManager.h"
#include "client/render/MainRenderer.h"
int main(int argc, char** argv) {
blitz::Client client;
blitz::input::InputManager inputManager;
blitz::Display display(1920, 1080, "BlitzKrieg", &client, inputManager);
blitz::Display display(1920, 1080, "BlitzKrieg", &client);
if (!display.Create())
return EXIT_FAILURE;
blitz::render::MainRenderer renderer(&client, display.GetPlayerController());
blitz::render::MainRenderer renderer(&client);
blitz::audio::AudioManager audioManager(&client);
blitz::network::NetworkInitializer network;
@@ -22,7 +20,6 @@ int main(int argc, char** argv) {
client.Update();
display.PollEvents();
renderer.Update();
audioManager.Update();
renderer.Render();
display.Render();
display.Update();

View File

@@ -85,7 +85,7 @@ bool DataBuffer::ReadFile(const std::string& fileName) {
return m_Buffer.size() > 0;
}
bool DataBuffer::WriteFile(const std::string& fileName) const {
bool DataBuffer::WriteFile(const std::string& fileName) {
try {
std::ofstream file(fileName, std::ostream::binary);
file.write(reinterpret_cast<const char*>(m_Buffer.data()), static_cast<std::streamsize>(m_Buffer.size()));

View File

@@ -1,5 +1,4 @@
#include "blitz/game/Game.h"
#include <cmath>
namespace blitz {
namespace game {
@@ -26,19 +25,10 @@ void Game::AddPlayer(PlayerID player, const std::string& name) {
static float MAX_HP = 100;
game::Player newPlayer{player};
static const maths::AABB PLAYER_BASE_AABB = {Vec3f{-0.5f, -0.9f, -0.5f}, Vec3f{0.5f, 0.9f, 0.5f}};
newPlayer.SetHitBoxSize(PLAYER_BASE_AABB);
newPlayer.SetPosition({
0.0f,
std::fabs(PLAYER_BASE_AABB.to.y - PLAYER_BASE_AABB.from.y) * 10.0f,
0.0f
});
newPlayer.SetName(name);
newPlayer.SetHP(MAX_HP);
GetPlayers().insert({player, newPlayer});
NotifyListeners(&GameListener::OnPlayerJoin, player);
}
void Game::RemovePlayer(PlayerID player) {
@@ -47,17 +37,8 @@ void Game::RemovePlayer(PlayerID player) {
if (it == GetPlayers().end())
return;
NotifyListeners(&GameListener::OnPlayerLeave, player);
GetPlayers().erase(it);
}
void Game::UpdateGameState(GameState newGameState, std::uint64_t timeRemaining) {
m_GameState = newGameState;
m_GameTimer.SetInterval(timeRemaining);
m_GameTimer.Reset();
NotifyListeners(&GameListener::OnGameStateUpdate, newGameState);
}
} // namespace game
} // namespace blitz

View File

@@ -1,13 +0,0 @@
#include "blitz/game/World.h"
#include "blitz/game/Game.h"
namespace blitz {
namespace game {
World::World(Game* game) : m_Game(game) {}
World::~World() {}
} // namespace game
} // namespace blitz

View File

@@ -5,20 +5,15 @@
namespace blitz {
namespace maths {
Mat4f Perspective(float fovY, float invAspectRatio, float zNear, float zFar) {
static const float FRAC_PI_2 = 1.5707963267948966;
const float cotanHalfFovy = -std::tan(std::fmaf(fovY, 0.5f, FRAC_PI_2));
float neg_i_z_diff = -1.0f / (zFar - zNear);
Mat4f Perspective(float fovY, float aspectRatio, float zNear, float zFar) {
const float tanHalfFovy = std::tan(fovY / 2.0f);
Mat4f result{};
result.x0 = cotanHalfFovy * invAspectRatio;
result.y1 = cotanHalfFovy;
result.z2 = (zFar + zNear) * neg_i_z_diff;
result.x0 = 1.0f / (aspectRatio * tanHalfFovy);
result.y1 = 1.0f / (tanHalfFovy);
result.z2 = -(zFar + zNear) / (zFar - zNear);
result.z3 = -1.0f;
result.w2 = 2.0f * zFar * zNear * neg_i_z_diff;
result.w2 = -(2.0f * zFar * zNear) / (zFar - zNear);
return result;
}
@@ -176,13 +171,5 @@ Mat4f Rotate(float angle, Vec3f axis) {
return mat;
}
Vec3f GetDirectionVectorFromRotation(float yaw, float pitch) {
return {
std::cos(yaw) * std::cos(pitch),
std::sin(pitch),
std::sin(yaw) * std::cos(pitch),
};
}
} // namespace maths
} // namespace blitz

113
src/blitz/maths/Physics.cpp Normal file → Executable file
View File

@@ -1,112 +1,67 @@
#include "blitz/maths/Physics.h"
#include "blitz/maths/Maths.h"
#include <cmath>
namespace blitz {
namespace maths {
AABB AABB::Enlarge(const AABB& with) const {
const Vec3f dir = 0.5f * (with.to - with.from);
/**
* @brief Returns `true` if the half-line `ray` _strictly_ intersects with `aabb`,
* and `false` if it _strictly_ doesn't intersect.
* Note that if it only intersects with corners, edges, or sides of the box,
* or if any coordinate in `ray` is `NAN` or `inf` or if any coordinate in
* `aabb` is `NAN` the result is unspecified.
* */
float Distance(const Ray& ray, const AABB& aabb) {
return AABB{
from - dir,
to + dir,
};
}
AABB AABB::Direct() const {
return AABB{Min(from, to), Max(from, to)};
}
Vec3f AABB::Center() const {
return (from + to) * 0.5f;
}
AABB AABB::operator+(const Vec3f& offset) const {
return AABB{from + offset, to + offset};
}
AABB AABB::operator+=(const Vec3f& offset) {
*this = *this + offset;
return *this;
}
bool AABB::OverlapsWith(const AABB& aabb) const {
return RangesOverlapping(from.x, to.x, aabb.from.x, aabb.to.x) &&
RangesOverlapping(from.y, to.y, aabb.from.y, aabb.to.y) &&
RangesOverlapping(from.z, to.z, aabb.from.z, aabb.to.z);
}
std::optional<IntersectionData> AABB::Intersection(const AABB& aabb, const Vec3f& dir) const {
return Ray { Center(), dir }.Intersection(aabb.Enlarge(*this));
}
Vec3f Ray::operator()(float t) const {
return FmaF(Vec3f::splat(t), direction, origin);
}
std::optional<IntersectionData> Ray::Intersection(const AABB& aabb) const {
// This function calculates smallest interval I = ] tmin, tmax [,
// such that for all t in I ray(t) is in the AABB, now, if tmin > tmax
// there is no such t, i.e. the ray never intersects with the AABB
// This function calculates smallest interval I = ] a, b [, for strictly positive a and b
// such that for all t in I, for all l, r, o, d corresponding
// coordinates in aabb.from, aabb.to, ray.origin, ray.direction, respectively
//
// and returns true if it's non-empty i.e. a < b
// min(l, r) < o + t * d < max(l, r)
//
// and returns true if it's non-empty i.e. a < b
// m = min(l, r), M = max(l, r)
// m < o + t * d < M
AABB directed = aabb.Direct();
Vec3f& l = directed.from;
Vec3f& r = directed.to;
Vec3f l = Min(aabb.from, aabb.to);
Vec3f r = Max(aabb.to, aabb.from);
// m - o < t * d < M - o
l -= origin;
r -= origin;
l -= ray.origin;
r -= ray.origin;
// (m - o) / d < t < (M - o) / d
l /= direction;
r /= direction;
l /= ray.direction;
r /= ray.direction;
// but if d is negative the inequality is flipped
Vec3f u = Min(l, r);
r = Max(l, r);
l = u;
const float tmin = ReduceFMaxF(l);
const float tmax = ReduceFMinF(r);
float tmin = ReduceMax(l);
float tmax = ReduceMin(r);
// Since Min propagates NANs and ReduceFMinF doesn't, and since NAN != <any float>
// the inequality becomes ignored for coordinates where a NaN is involved
// Since Min propagates NANs and ReduceMin doesn't, and since NAN !< <any float>
// the inequality becomes ignored for coordinates where a NAN is involved
// (as a result of 0.0 / 0.0). If all coordinates are NAN, this means
// that the box is reduced to a point and the ray has direction 0,
// in which case this returns 0.0, which is technically the correct result
if (tmin <= tmax && tmax > 0.0f) {
Axis axis = Axis::aZ;
for (std::size_t i = 2; i >= 0; i--) {
Axis this_axis = Axis(i);
if (l[this_axis] == tmin) {
axis = this_axis;
break;
}
}
const float dist = std::fmaxf(0.0f, tmin);
return std::make_optional(IntersectionData { dist, axis });
// in which case this returns -1
if (tmax >= 0.0f && tmin <= tmax) {
return std::fmaxf(tmin, 0.0f);
}
return std::nullopt;
return -1.0f;
}
bool Ray::Intersects(const AABB& aabb) const {
auto data = Intersection(aabb);
return data.has_value() && data->distance >= 0.0f;
bool Intersects(const AABB& aabb1, const AABB& aabb2) {
return false;
}
CollisionData IntersectionData::ToCollision(const Vec3f& dir) const {
Vec3f new_dir = dir;
new_dir[axis] = 0.0f;
return CollisionData{dir * (distance - 0.07f), new_dir * (1.0f - distance)};
bool Intersects(const Ray& ray, const AABB& aabb) {
return Distance(ray, aabb) >= 0.0f;
}
} // namespace maths

View File

@@ -22,7 +22,7 @@ static DataBuffer Inflate(const std::uint8_t* source, std::size_t size, std::siz
static DataBuffer Deflate(const std::uint8_t* source, std::size_t size) {
DataBuffer result;
uLongf compressedSize = size;
uLongf compressedSize;
result.Resize(size); // Resize for the compressed data to fit into
compress(

View File

@@ -32,7 +32,7 @@ float EaseOutCubic(float x) {
}
float EaseInOutCubic(float x) {
return x < 0.5f ? 4.0f * EaseInCubic(x) : 1.0f - std::pow(-2.0f * x + 2.0f, 3.0f) / 2.0f;
return static_cast<float>(x < 0.5 ? 4 * EaseInCubic(x) : 1 - std::pow(-2 * x + 2, 3) / 2.0);
}
/* Quint functions */
@@ -60,8 +60,8 @@ float EaseOutCirc(float x) {
}
float EaseInOutCirc(float x) {
return x < 0.5f ? (1.0f - std::sqrt(1.0f - std::pow(2.0f * x, 2.0f))) / 2.0f
: (std::sqrt(1.0f - std::pow(-2.0f * x + 2.0f, 2.0f)) + 1.0f) / 2.0f;
return static_cast<float>(
x < 0.5 ? (1 - std::sqrt(1 - std::pow(2 * x, 2))) / 2.0 : (std::sqrt(1 - std::pow(-2 * x + 2, 2)) + 1) / 2.0);
}
/* Elastic functions */

View File

@@ -1,6 +1,5 @@
#include "blitz/protocol/packets/ChatPacket.h"
#include "blitz/common/VarInt.h"
#include "blitz/maths/Vector.h"
#include "blitz/misc/Log.h"
#include <map>
@@ -24,7 +23,7 @@ DataBuffer ChatPacket::Serialize(bool packetID) const {
WritePacketID(data, packetID);
data << VarInt{m_Message.size()};
data << static_cast<std::uint64_t>(m_Message.size());
for (const auto& part : m_Message) {
data << part.color << part.text;
}
@@ -32,12 +31,12 @@ DataBuffer ChatPacket::Serialize(bool packetID) const {
}
void ChatPacket::Deserialize(DataBuffer& data) {
VarInt partsNumber;
std::uint64_t partsNumber;
data >> partsNumber;
m_Message.resize(partsNumber.GetValue());
m_Message.resize(partsNumber);
for (std::size_t i = 0; i < partsNumber.GetValue(); ++i) {
for (std::size_t i = 0; i < partsNumber; ++i) {
data >> m_Message[i].color >> m_Message[i].text;
}
}

View File

@@ -74,14 +74,12 @@ void Client::Disconnect() {
m_Server->Stop();
}
m_Connexion->CloseConnection();
Reset();
NotifyListeners(&game::ClientListener::OnGameLeave);
Reset();
}
void Client::Reset() {
utils::LOGD("[Client] Reset !");
// Reset server
m_Server.reset(nullptr);
m_Server = std::make_unique<server::Server>();

View File

@@ -1,103 +1,38 @@
#include "client/audio/AudioManager.h"
#include "blitz/maths/Maths.h"
#include "blitz/misc/Log.h"
#include "client/Client.h"
#include "client/audio/AudioBuffer.h"
#include "client/game/ClientGame.h"
namespace blitz {
namespace audio {
AudioManager::AudioManager(Client* client) : m_Client(client), m_Player(nullptr) {
AudioManager::AudioManager(Client* client) : m_Client(client) {
m_Listener.SetPosition({});
m_Listener.SetVelocity({});
m_Listener.SetGain(1.0f);
InitSounds();
m_Listener.SetOrientation(blitz::Vec3f{0.0, 0.0, 0.0}, blitz::Vec3f{0.0, 1.0, 0.0});
InitMainMenuMusic();
m_MenuMusic->Play();
m_Client->BindListener(this);
}
void AudioManager::SetGlobalVolume(float volume) {
m_Listener.SetGain(volume);
}
void AudioManager::Update() {
if (!m_Player)
return;
m_Listener.SetPosition(m_Player->GetPosition());
m_Listener.SetOrientation(maths::GetDirectionVectorFromRotation(m_Player->GetYaw(), m_Player->GetPitch()), {0.0f, 1.0f, 0.0f});
m_Listener.SetVelocity(m_Player->GetVelocity());
}
AudioSourcePtr AudioManager::InitSourceFromFile(const std::string& fileName) {
AudioBufferPtr audioBuffer = InitBufferFromFile(fileName);
return InitSourceFromBuffer(audioBuffer);
}
AudioSourcePtr AudioManager::InitSourceFromBuffer(const AudioBufferPtr& buffer) {
AudioSourcePtr audioSource = std::make_unique<AudioSource>();
audioSource->SetBuffer(buffer);
audioSource->SetPosition({});
audioSource->SetVelocity({});
audioSource->SetPitch(1.0f);
audioSource->SetRelative(false);
return audioSource;
}
AudioBufferPtr AudioManager::InitBufferFromFile(const std::string& fileName) {
AudioData audioData = AudioLoader::LoadAudioFile(fileName);
return std::make_shared<AudioBuffer>(std::move(audioData));
}
void AudioManager::InitSounds() {
m_MenuMusic = InitSourceFromFile("sessionD.wav");
void AudioManager::InitMainMenuMusic() {
AudioData audioData = AudioLoader::LoadAudioFile("sessionD.wav");
AudioBufferPtr audioBuffer = std::make_unique<AudioBuffer>(std::move(audioData));
m_MenuMusic = std::make_unique<AudioSource>();
m_MenuMusic->SetBuffer(std::move(audioBuffer));
m_MenuMusic->SetPosition({});
m_MenuMusic->SetVelocity({});
m_MenuMusic->SetPitch(1.0f);
m_MenuMusic->SetLooping(true);
m_LaserSound = InitBufferFromFile("laser.wav");
}
void AudioManager::OnGameJoin() {
m_MenuMusic->Stop();
m_Client->GetGame()->BindListener(this);
}
void AudioManager::OnGameLeave() {
m_MenuMusic->Play();
m_PlayerSources.clear();
m_Player = nullptr;
m_Client->GetGame()->UnbindListener(this);
}
void AudioManager::OnClientPlayerJoin() {
m_Player = m_Client->GetGame()->GetPlayerById(m_Client->GetPlayerID());
}
void AudioManager::OnPlayerJoin(game::PlayerID player) {
m_PlayerSources.insert({player, PlayerSound{InitSourceFromBuffer(m_LaserSound)}});
}
void AudioManager::OnPlayerLeave(game::PlayerID player) {
m_PlayerSources.erase(player);
}
void AudioManager::OnPlayerShoot(game::PlayerID playerID, const Vec3f& position, float yaw, float pitch) {
auto it = m_PlayerSources.find(playerID);
if (it == m_PlayerSources.end()) {
utils::LOGD("[AudioManager] No sound found for player " + std::to_string(playerID) + " !");
return;
}
game::Player* player = m_Client->GetGame()->GetPlayerById(playerID);
assert(player);
Vec3f shootFront = maths::GetDirectionVectorFromRotation(player->GetYaw(), player->GetPitch());
PlayerSound& playerSounds = it->second;
playerSounds.m_Laser->SetPosition(player->GetPosition());
playerSounds.m_Laser->SetDirection(shootFront);
playerSounds.m_Laser->Play();
}
AudioManager::~AudioManager() {

View File

@@ -37,13 +37,9 @@ void AudioSource::SetLooping(bool a_Looping) {
alSourcei(m_ID, AL_LOOPING, a_Looping);
}
void AudioSource::SetRelative(bool a_Relative) {
alSourcei(m_ID, AL_SOURCE_RELATIVE, a_Relative);
}
void AudioSource::SetBuffer(const AudioBufferPtr& a_Buffer) {
void AudioSource::SetBuffer(AudioBufferPtr&& a_Buffer) {
alSourcei(m_ID, AL_BUFFER, a_Buffer->GetID());
m_Buffer = a_Buffer;
m_Buffer = std::move(a_Buffer);
}
AudioSource::SourceState AudioSource::GetSourceState() const {

View File

@@ -20,7 +20,7 @@
namespace blitz {
Display::Display(int width, int height, const std::string& windowName, Client* client, input::InputManager& inputManager) :
Display::Display(int width, int height, const std::string& windowName, Client* client) :
m_WindowWidth(width),
m_WindowHeight(height),
m_AspectRatio(m_WindowHeight / static_cast<float>(m_WindowWidth)),
@@ -28,9 +28,7 @@ Display::Display(int width, int height, const std::string& windowName, Client* c
m_ShouldClose(false),
m_FullScreen(false),
m_Client(client),
m_InputManager(inputManager),
m_BlitzGui(nullptr),
m_PlayerController(m_Client, m_InputManager) {}
m_BlitzGui(nullptr) {}
Display::~Display() {
Destroy();
@@ -147,7 +145,7 @@ void Display::PollEvents() {
}
}
ImGui_ImplSDL2_ProcessEvent(&event);
m_InputManager.ProcessEvent(event);
InputManager::ProcessEvent(event);
}
#ifdef __ANDROID__
@@ -158,8 +156,6 @@ void Display::PollEvents() {
}
#endif
m_PlayerController.Update(ImGui::GetIO().DeltaTime);
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
@@ -168,7 +164,7 @@ void Display::PollEvents() {
void Display::Update() {
// center mouse
#ifndef __ANDROID__
if (m_InputManager.MouseGrabbed()) {
if (InputManager::MouseGrabbed()) {
SDL_WarpMouseInWindow(m_Window, GetWindowWidth() / 2, GetWindowHeight() / 2);
}
#endif
@@ -233,7 +229,7 @@ void Display::InitImGui() {
#ifndef __ANDROID__
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
#endif
m_BlitzGui = std::make_unique<gui::BlitzGui>(m_Client, m_InputManager);
m_BlitzGui = std::make_unique<gui::BlitzGui>(m_Client);
}
} // namespace blitz

View File

@@ -4,7 +4,12 @@
#include <vector>
namespace blitz {
namespace input {
namespace InputManager {
std::vector<KeyDownCallback> KeyCallBacks;
std::vector<MouseMoveCallback> MouseCallBacks;
bool MouseInputGrabbed = false;
static int ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode) {
switch (keycode) {
@@ -222,15 +227,36 @@ static int ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode) {
return ImGuiKey_None;
}
void InputManager::ProcessEvent(SDL_Event& event) const {
void BindKeyDownCallback(const KeyDownCallback& callback) {
KeyCallBacks.push_back(callback);
}
void BindMouseMoveCallback(const MouseMoveCallback& callback) {
MouseCallBacks.push_back(callback);
}
static void CallKeyFunctions(SDL_Keycode key) {
int imguiKey = ImGui_ImplSDL2_KeycodeToImGuiKey(key);
for (auto callback : KeyCallBacks) {
callback(imguiKey);
}
}
static void CallMouseFunctions(int xrel, int yrel) {
for (auto callback : MouseCallBacks) {
callback(xrel, yrel);
}
}
void ProcessEvent(SDL_Event& event) {
switch (event.type) {
case SDL_KEYDOWN: {
NotifyListeners(&InputListener::OnKeyDown, ImGui_ImplSDL2_KeycodeToImGuiKey(event.key.keysym.sym));
CallKeyFunctions(event.key.keysym.sym);
break;
}
case SDL_MOUSEMOTION: {
NotifyListeners(&InputListener::OnMouseMove, event.motion.xrel, event.motion.yrel);
CallMouseFunctions(event.motion.xrel, event.motion.yrel);
break;
}
@@ -239,16 +265,16 @@ void InputManager::ProcessEvent(SDL_Event& event) const {
}
}
void InputManager::GrabMouse(bool grabInput) {
m_MouseInputGrabbed = grabInput;
void GrabMouse(bool grabInput) {
MouseInputGrabbed = grabInput;
#ifndef __ANDROID__
SDL_SetRelativeMouseMode(static_cast<SDL_bool>(grabInput));
#endif
}
bool InputManager::MouseGrabbed() const {
return m_MouseInputGrabbed;
bool MouseGrabbed() {
return MouseInputGrabbed;
}
} // namespace input
} // namespace InputManager
} // namespace blitz

View File

@@ -2,7 +2,6 @@
#include "blitz/game/Player.h"
#include "blitz/maths/Maths.h"
#include "blitz/maths/Physics.h"
#include "blitz/misc/Log.h"
#include "client/Client.h"
#include "client/config/BlitzConfig.h"
@@ -21,45 +20,32 @@ static constexpr float DEFAULT_MAX_FB_SPEED = 10.;
static constexpr float DEFAULT_LR_SPEED_SMOOTHING_TIME = 1.0;
static constexpr float DEFAULT_FB_SPEED_SMOOTHING_TIME = 1.0;
PlayerController::PlayerController(Client* client, input::InputManager& inputManager) :
PlayerController::PlayerController(Client* client) :
m_Player(nullptr),
m_Client(client),
m_InputManager(inputManager),
m_Velocity({}),
m_MaxVelocity(DEFAULT_MAX_LR_SPEED, DEFAULT_JUMP_VEL, DEFAULT_MAX_FB_SPEED),
m_MaxVelocity(DEFAULT_MAX_LR_SPEED, DEFAULT_MAX_FB_SPEED, DEFAULT_JUMP_VEL),
m_OnGround(true) {
m_DxSmoother.Current = 0.0f;
m_DySmoother.Current = 0.0f;
m_DxSmoother.SetSmoothingTime(DEFAULT_LR_SPEED_SMOOTHING_TIME);
m_DySmoother.SetSmoothingTime(DEFAULT_FB_SPEED_SMOOTHING_TIME);
m_InputManager.BindListener(this);
m_Client->BindListener(this);
}
PlayerController::~PlayerController() {
m_InputManager.UnbindListener(this);
m_Client->UnbindListener(this);
InputManager::BindMouseMoveCallback(
std::bind(&PlayerController::MouseMotionEvent, this, std::placeholders::_1, std::placeholders::_2));
client->BindListener(this);
}
void PlayerController::OnGameConfigUpdate() {
UpdateShootTimer(m_Client->GetGame()->GetGameConfig().FiringRate);
}
void PlayerController::OnClientPlayerJoin() {
m_Player = m_Client->GetGame()->GetPlayerById(m_Client->GetPlayerID());
}
void PlayerController::OnGameLeave() {
m_Player = nullptr;
}
void PlayerController::UpdateShootTimer(int bpm) {
m_ShootTimer.SetCooldown(60.0f / static_cast<float>(bpm));
m_ShootTimer.Reset();
}
void PlayerController::OnMouseMove(int deltaX, int deltaY) {
if (!m_Player || !m_InputManager.MouseGrabbed())
void PlayerController::MouseMotionEvent(int deltaX, int deltaY) {
if (!m_Player || !InputManager::MouseGrabbed())
return;
float MouseSpeed = m_Client->GetConfig()->GetMouseSpeed();
@@ -73,7 +59,7 @@ void PlayerController::Update(float delta) {
if (!m_Player)
return;
if (m_InputManager.MouseGrabbed()) {
if (InputManager::MouseGrabbed()) {
Keybinds keys = m_Client->GetConfig()->GetKeys();
float lr = static_cast<float>(ImGui::IsKeyDown((ImGuiKey(keys[kaAvancer])))) -
static_cast<float>(ImGui::IsKeyDown((ImGuiKey(keys[kaReculer]))));
@@ -81,19 +67,13 @@ void PlayerController::Update(float delta) {
static_cast<float>(ImGui::IsKeyDown((ImGuiKey(keys[kaDroite]))));
// scale values in such a way that clamps ||(lr, fb)|| to 1.0
float scale = 1.0f / std::fmaxf(sqrt(lr * lr + fb * fb), 1.0f);
static constexpr float AIR_MOVEMENT_DAMP = 3.0f;
float no = std::fmaf(static_cast<float>(!m_OnGround), AIR_MOVEMENT_DAMP, 1.0f);
m_DxSmoother.SetSmoothingTime(DEFAULT_LR_SPEED_SMOOTHING_TIME * no);
m_DySmoother.SetSmoothingTime(DEFAULT_FB_SPEED_SMOOTHING_TIME * no);
float scale = 1.0f / std::max(sqrt(lr * lr + fb * fb), 1.0f);
m_Velocity.x = lr * m_MaxVelocity.x * scale;
m_Velocity.z = fb * m_MaxVelocity.z * scale;
m_Velocity.y = fb * m_MaxVelocity.y * scale;
if (ImGui::IsKeyDown(ImGuiKey::ImGuiKey_Space) && m_OnGround) {
m_Velocity.y = m_MaxVelocity.y;
m_Velocity.z = m_MaxVelocity.z;
NotifyListeners(&game::PlayerInputListener::OnLocalPlayerJump);
}
@@ -104,22 +84,12 @@ void PlayerController::Update(float delta) {
m_ShootTimer.ApplyCooldown();
}
} else {
m_Velocity.x = m_Velocity.z = 0.0f;
m_Velocity.x = m_Velocity.y = 0.0f;
}
ApplyGravity(delta);
UpdatePosition(delta);
}
void PlayerController::ApplyForce(const Vec3f& f, float delta) {
m_Velocity += f * delta;
}
void PlayerController::ApplyGravity(float delta) {
ApplyForce(Vec3f { 0.0f, -m_Client->GetGame()->GetGameConfig().Gravity, 0.0f }, delta);
}
void PlayerController::UpdatePosition(const float delta) {
float yaw = m_Player->GetYaw();
@@ -127,54 +97,28 @@ void PlayerController::UpdatePosition(const float delta) {
float cosine = std::cos(yaw);
m_DxSmoother.Tick(m_Velocity.x, delta);
m_DySmoother.Tick(m_Velocity.z, delta);
m_DySmoother.Tick(m_Velocity.y, delta);
float dx_smooth = m_DxSmoother.Current;
float dy_smooth = m_DySmoother.Current;
Vec3f vel = Vec3f((dx_smooth * cosine + dy_smooth * sine), m_Velocity.y, (dx_smooth * sine - dy_smooth * cosine)) * delta;
maths::CollisionData collision { Vec3f::splat(0.0f), vel };
float dx = (dx_smooth * cosine + dy_smooth * sine) * delta;
float dy = (dx_smooth * sine - dy_smooth * cosine) * delta;
const auto& aabbs = m_Client->GetGame()->GetWorld()->GetAABBs();
maths::AABB hitbox = m_Player->GetHitBox();
float dz = m_Velocity.z * delta;
bool on_ground = false;
// the floor here is y-level zero, once downwards collision lands it will be dynmicallly calculated
// assumed to be a negative number
const float floor_dist = 0.0f - m_Player->GetPosition().y;
do {
if ((m_OnGround = (dz <= floor_dist))) {
dz = floor_dist;
m_Velocity.z = 0.0f;
} else {
m_Velocity.z -= m_Client->GetGame()->GetGameConfig().Gravity * 1.0f * delta;
}
maths::IntersectionData closest { 1.0f, maths::Axis::aY };
for (const maths::AABB& aabb : aabbs) {
auto intersection = hitbox.Intersection(aabb, collision.slide);
if (intersection.has_value()) {
float d = intersection->distance;
if (d < closest.distance) {
maths::Axis axis = intersection->axis;
on_ground |= (axis == maths::Axis::aY);
closest.distance = d;
closest.axis = axis;
}
}
}
if (closest.distance < 0.99f) {
m_Velocity[closest.axis] = 0.0f;
}
collision = closest.ToCollision(collision.slide);
Vec3f v = collision.delta;
m_Player->AddPosition(v);
m_Player->SetVelocity(v);
} while (maths::Length(collision.slide) > 1e-6);
m_OnGround = on_ground;
m_Player->AddPosition({dx, dz, dy});
}
} // namespace input

View File

@@ -13,14 +13,12 @@
#include "blitz/protocol/packets/UpdateGameStatePacket.h"
#include "blitz/protocol/packets/UpdateHealthPacket.h"
#include "client/Client.h"
#include "client/game/ClientWorld.h"
namespace blitz {
namespace client {
ClientGame::ClientGame(Client* client, protocol::PacketDispatcher* dispatcher) :
protocol::PacketHandler(dispatcher), m_Client(client) {
m_World = std::make_unique<ClientWorld>(this);
RegisterHandlers();
}
@@ -33,8 +31,8 @@ void ClientGame::AddPlayer(game::PlayerID player, const std::string& name) {
m_LeaderBoard.AddPlayer(GetPlayerById(player));
}
void ClientGame::RemovePlayer(game::PlayerID player) {
m_LeaderBoard.RemovePlayer(player);
Game::RemovePlayer(player);
m_LeaderBoard.RemovePlayer(player);
}
void ClientGame::RegisterHandlers() {
@@ -50,17 +48,12 @@ void ClientGame::RegisterHandlers() {
}
void ClientGame::HandlePacket(const protocol::PlayerJoinPacket* packet) {
if (packet->GetPlayerID() == m_Client->GetPlayerID()) {
m_Client->NotifyListeners(&game::ClientListener::OnGameJoin);
}
AddPlayer(packet->GetPlayerID(), packet->GetPlayerName());
// Initialize camera
if (packet->GetPlayerID() == m_Client->GetPlayerID()) {
m_Client->NotifyListeners(&game::ClientListener::OnSpectatorChange, packet->GetPlayerID());
m_Client->NotifyListeners(&game::ClientListener::OnClientPlayerJoin);
m_Client->NotifyListeners(&game::ClientListener::OnGameJoin);
}
}
@@ -94,7 +87,9 @@ void ClientGame::HandlePacket(const protocol::UpdateHealthPacket* packet) {
}
void ClientGame::HandlePacket(const protocol::UpdateGameStatePacket* packet) {
Game::UpdateGameState(packet->GetGameState(), packet->GetTimeRemaining());
m_GameState = packet->GetGameState();
m_GameTimer.SetInterval(packet->GetTimeRemaining());
m_GameTimer.Reset();
}
void ClientGame::HandlePacket(const protocol::ServerConfigPacket* packet) {

View File

@@ -1,18 +0,0 @@
#include "client/game/ClientWorld.h"
#include "client/game/ClientGame.h"
#include "client/render/loader/ModelLoader.h"
namespace blitz {
namespace client {
ClientWorld::ClientWorld(ClientGame* game) : game::World(game) {
LoadAABBs();
}
void ClientWorld::LoadAABBs() {
m_AABBs = ModelLoader::LoadModelAABBs("sol.glb");
}
} // namespace client
} // namespace blitz

View File

@@ -11,14 +11,14 @@
namespace blitz {
namespace gui {
BlitzGui::BlitzGui(Client* client, input::InputManager& inputManager) : GuiWidget(nullptr, client) {
BlitzGui::BlitzGui(Client* client) : GuiWidget(nullptr, client) {
Enable();
AddWidget(std::make_unique<GameChatGui>(this, client, inputManager));
AddWidget(std::make_unique<MainMenu>(client, inputManager));
AddWidget(std::make_unique<GameChatGui>(this, client));
AddWidget(std::make_unique<MainMenu>(client));
AddWidget(std::make_unique<CrossHair>(client));
AddWidget(std::make_unique<Hud>(this, client));
AddWidget(std::make_unique<LeaderBoardGui>(this, client));
AddWidget(std::make_unique<ServerGui>(this, client, inputManager));
AddWidget(std::make_unique<ServerGui>(this, client));
SetCustomTheme();
}

View File

@@ -3,6 +3,7 @@
#include "blitz/misc/Format.h"
#include "blitz/misc/Log.h"
#include "client/Client.h"
#include "client/display/InputManager.h"
#include <cmath>
#include <imgui.h>
#include <string>
@@ -10,9 +11,6 @@
namespace blitz {
namespace gui {
CreateGameMenu::CreateGameMenu(GuiWidget* parent, Client* client, input::InputManager& inputManager) :
GuiWidget(parent, client), m_InputManager(inputManager) {}
void CreateGameMenu::Render() {
if (!IsEnabled())
return;
@@ -40,7 +38,7 @@ void CreateGameMenu::Render() {
utils::LOGD(utils::Format("[CreateGameMenu] Port saisi : %i", InputPort));
if (m_Client->CreateGame(InputPort, m_Client->GetConfig()->GetPseudo().data())) {
m_InputManager.GrabMouse(true);
InputManager::GrabMouse(true);
Disable();
}
}

View File

@@ -15,16 +15,11 @@ namespace gui {
static const float ChatFadeTime = 2.0f;
GameChatGui::GameChatGui(GuiWidget* parent, Client* client, input::InputManager& inputManager) :
GuiWidget(parent, client), m_InputManager(inputManager) {
GameChatGui::GameChatGui(GuiWidget* parent, Client* client) : GuiWidget(parent, client) {
m_Client->BindListener(this);
InputBuf[0] = '\0';
}
GameChatGui::~GameChatGui() {
m_Client->UnbindListener(this);
}
void GameChatGui::Draw(const char* title, bool* p_open) {
HistoryPos = -1;
static float chat_width = 620.0f;
@@ -96,11 +91,11 @@ void GameChatGui::Render() {
if (ImGui::IsKeyPressed(ImGuiKey_Enter)) {
showCHAT = true;
m_FocusRequested = true;
m_InputManager.GrabMouse(false);
InputManager::GrabMouse(false);
} else if (ImGui::IsKeyPressed(ImGuiKey_Escape) && showCHAT) {
showCHAT = false;
ImGui::GetIO().ClearInputKeys();
m_InputManager.GrabMouse(true);
InputManager::GrabMouse(true);
}
if (showCHAT) {

View File

@@ -10,9 +10,6 @@
namespace blitz {
namespace gui {
JoinGameMenu::JoinGameMenu(GuiWidget* parent, Client* client, input::InputManager& inputManager) :
GuiWidget(parent, client), m_InputManager(inputManager) {}
void JoinGameMenu::Render() {
if (!IsEnabled())
return;
@@ -45,7 +42,7 @@ void JoinGameMenu::Render() {
utils::LOGD(utils::Format("[JoinGameMenu] Adresse saisie : %s, Port saisi : %i", InputAddress, InputPort));
if (m_Client->JoinGame(m_Client->GetConfig()->GetPseudo().data(), InputAddress, InputPort)) {
m_InputManager.GrabMouse(true);
InputManager::GrabMouse(true);
Disable();
}
}

View File

@@ -1,29 +1,18 @@
#include "client/gui/MainMenu.h"
#include "client/Client.h"
#include "client/gui/CreateGameMenu.h"
#include "client/gui/JoinGameMenu.h"
#include "client/gui/OptionsMenu.h"
#include <imgui.h>
namespace blitz {
namespace gui {
MainMenu::MainMenu(Client* client, input::InputManager& inputManager) : GuiWidget(nullptr, client), m_InputManager(inputManager) {
MainMenu::MainMenu(Client* client) : GuiWidget(nullptr, client) {
Enable();
AddWidget(std::make_unique<CreateGameMenu>(this, client, inputManager));
AddWidget(std::make_unique<JoinGameMenu>(this, client, inputManager));
AddWidget(std::make_unique<OptionsMenu>(this, client, inputManager));
m_Client->BindListener(this);
}
MainMenu::~MainMenu() {
m_Client->UnbindListener(this);
}
void MainMenu::OnGameLeave() {
Enable();
m_InputManager.GrabMouse(false);
AddWidget(std::make_unique<CreateGameMenu>(this, client));
AddWidget(std::make_unique<JoinGameMenu>(this, client));
AddWidget(std::make_unique<OptionsMenu>(this, client));
}
void MainMenu::Render() {

View File

@@ -42,31 +42,6 @@ static std::string GetImGuiKeyName(int key) {
OptionsMenu::OptionsMenu(GuiWidget* parent, Client* client, input::InputManager& inputManager) :
GuiWidget(parent, client), m_IsKeyPopupOpen(false), m_KeyPopupShouldClose(false), m_InputManager(inputManager) {
AddWidget(std::make_unique<FPSMenu>(this, client));
m_InputManager.BindListener(this);
m_ShowFPS = m_Client->GetConfig()->IsFPSDisplayEnabled();
m_SubWidgets[0]->SetState(m_ShowFPS);
m_VSync = m_Client->GetConfig()->IsVSyncEnabled();
SDL_GL_SetSwapInterval(m_VSync);
}
OptionsMenu::~OptionsMenu() {
m_InputManager.UnbindListener(this);
}
void OptionsMenu::HotkeyBindingButton() {
for (std::size_t i = 0; i < m_Client->GetConfig()->GetKeys().size(); i++) {
if (ImGui::Button(utils::Format("%s##%i", GetKeyActionCodeName(KeyAction(i)).c_str(), i).c_str())) {
@@ -115,7 +90,23 @@ void OptionsMenu::HotkeyBindingPopUp() {
void OptionsMenu::OnKeyDown(int key) {
OptionsMenu::OptionsMenu(GuiWidget* parent, Client* client) :
GuiWidget(parent, client), m_IsKeyPopupOpen(false), m_KeyPopupShouldClose(false) {
AddWidget(std::make_unique<FPSMenu>(this, client));
InputManager::BindKeyDownCallback(std::bind(&OptionsMenu::OnKeyEvent, this, std::placeholders::_1));
m_ShowFPS = m_Client->GetConfig()->IsFPSDisplayEnabled();
m_SubWidgets[0]->SetState(m_ShowFPS);
m_VSync = m_Client->GetConfig()->IsVSyncEnabled();
SDL_GL_SetSwapInterval(m_VSync);
}
void OptionsMenu::OnKeyEvent(int key) {
if (!m_IsKeyPopupOpen)
return;
@@ -149,7 +140,7 @@ void OptionsMenu::Render() {
if (ImGui::IsKeyPressed(ImGuiKey_Escape) && m_Client->IsConnected() && !IsEnabled()) {
Enable();
ImGui::GetIO().ClearInputKeys(); // releases the Escape key
m_InputManager.GrabMouse(false);
InputManager::GrabMouse(false);
}
if (!IsEnabled())
@@ -212,7 +203,7 @@ void OptionsMenu::Render() {
if (ImGui::Button("Retour", buttonSize) || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
Disable();
if (m_Client->IsConnected()) {
m_InputManager.GrabMouse(true);
InputManager::GrabMouse(true);
} else {
m_Parent->Enable();
}
@@ -221,6 +212,7 @@ void OptionsMenu::Render() {
if (ImGui::Button("Quitter la partie", buttonSize)) {
m_Client->Disconnect();
Disable();
m_Parent->Enable();
}
}
}

View File

@@ -10,15 +10,14 @@
namespace blitz {
namespace gui {
ServerGui::ServerGui(GuiWidget* parent, Client* client, input::InputManager& inputManager) :
GuiWidget(parent, client), m_InputManager(inputManager) {}
ServerGui::ServerGui(GuiWidget* parent, Client* client) : GuiWidget(parent, client) {}
void ServerGui::Render() {
if (!m_Client->IsAdmin())
return;
Keybinds keys = m_Client->GetConfig()->GetKeys();
if (ImGui::IsKeyPressed(ImGuiKey(keys[kaFenetreAdmin])) && m_InputManager.MouseGrabbed()) {
if (ImGui::IsKeyPressed(ImGuiKey(keys[kaFenetreAdmin])) && InputManager::MouseGrabbed()) {
ImGui::OpenPopup("FENETRE D'ADMIN");
}
@@ -33,7 +32,7 @@ void ServerGui::Render() {
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowSize(ImVec2(servergui_width, servergui_height));
if (ImGui::BeginPopupModal("FENETRE D'ADMIN", nullptr, servergui_flags)) {
m_InputManager.GrabMouse(false);
InputManager::GrabMouse(false);
ImGui::BeginChild("Mutateurs JOUEURS", ImVec2(servergui_width * (1.0f / 3.0f), 0.0f), true);
{
@@ -116,7 +115,7 @@ void ServerGui::Render() {
ImGui::SetCursorPosY(servergui_height - 2.0f * buttonSize.y);
if (ImGui::Button("Retour", buttonSize)) {
ImGui::CloseCurrentPopup();
m_InputManager.GrabMouse(true);
InputManager::GrabMouse(true);
}
ImGui::EndChild();

View File

@@ -26,7 +26,11 @@ BulletRenderer::~BulletRenderer() {}
void BulletRenderer::AddBullet(const Vec3f& origin, float yaw, float pitch, bool firstPersson) {
static const float TRAIL_LENGHT = 50;
Vec3f direction = maths::GetDirectionVectorFromRotation(yaw, pitch);
Vec3f direction = {
std::cos(yaw) * std::cos(pitch),
std::sin(pitch),
std::sin(yaw) * std::cos(pitch),
};
Vec3f middle = origin + direction * (TRAIL_LENGHT / 2.0f);
@@ -80,9 +84,5 @@ void BulletRenderer::Render() {
vao->Unbind();
}
void BulletRenderer::Clear() {
m_Trails.clear();
}
} // namespace render
} // namespace blitz

View File

@@ -7,8 +7,7 @@
namespace blitz {
namespace render {
/// \brief Eye height from center
static const float EyeHeight = 0.5f;
static const float EyeHeight = 1.25f;
void Camera::Update(float delta) {
int windowWidth = static_cast<int>(ImGui::GetIO().DisplaySize.x);
@@ -17,12 +16,8 @@ void Camera::Update(float delta) {
if (windowWidth != m_LastWindowSize.x || windowHeight != m_LastWindowSize.y) {
m_LastWindowSize = {windowWidth, windowHeight};
m_PerspectiveMatrix = maths::Perspective(
80.0f / 180.0f * maths::PI,
static_cast<float>(windowHeight) / static_cast<float>(windowWidth),
0.1f,
160.0f
);
m_PerspectiveMatrix =
maths::Perspective(80.0f / 180.0f * maths::PI, static_cast<float>(windowWidth) / windowHeight, 0.1f, 160.0f);
}
}
@@ -31,11 +26,12 @@ float Camera::GetPlayerEyeHeight() {
}
Mat4f Camera::GetViewMatrix() const {
Vec3f front = {
std::cos(m_Player->GetYaw()) * std::cos(m_Player->GetPitch()),
std::sin(m_Player->GetPitch()),
std::sin(m_Player->GetYaw()) * std::cos(m_Player->GetPitch()),
};
if (!m_Player)
return {};
Vec3f front = maths::GetDirectionVectorFromRotation(m_Player->GetYaw(), m_Player->GetPitch());
return maths::Look(m_Player->GetPosition() + Vec3f{0, EyeHeight, 0}, front, {0, 1, 0});
}

View File

@@ -24,8 +24,8 @@ namespace render {
static const Vec4f SkyColor = {0.6f, 0.8f, 1.0f, 1.0f};
static const Vec4f MenuColor = {0.0f, 0.0f, 0.0f, 0.0f};
MainRenderer::MainRenderer(Client* client, input::PlayerController& playerController) :
m_Client(client), m_ShootTime(0), m_BulletRenderer(m_Camera), m_PlayerController(playerController) {
MainRenderer::MainRenderer(Client* client) :
m_Client(client), m_PlayerController(m_Client), m_ShootTime(0), m_BulletRenderer(m_Camera) {
LoadModels();
@@ -54,15 +54,10 @@ MainRenderer::MainRenderer(Client* client, input::PlayerController& playerContro
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
MainRenderer::~MainRenderer() {
m_Client->UnbindListener(this);
m_PlayerController.UnbindListener(this);
m_PlayerController.UnbindListener(m_Client);
}
MainRenderer::~MainRenderer() {}
void MainRenderer::LoadModels() {
m_WorldModel = ModelLoader::LoadModel("sol.glb");
m_WorldModel = ModelLoader::LoadModel("base_deambu.glb");
m_PlayerModel = ModelLoader::LoadModel("human.obj");
m_GunModel = ModelLoader::LoadModel("fingergun.obj");
@@ -163,6 +158,7 @@ void MainRenderer::Update() {
float delta = ImGui::GetIO().DeltaTime;
m_PlayerController.Update(delta);
m_Camera.Update(delta);
m_BulletRenderer.Update(delta);
@@ -183,15 +179,11 @@ void MainRenderer::Update() {
m_ShootTime = std::max(0.0f, m_ShootTime - delta);
}
void MainRenderer::OnGameLeave() {
m_Camera.SetAttachedPlayer(nullptr);
m_BulletRenderer.Clear();
}
void MainRenderer::OnSpectatorChange(const game::PlayerID player) {
game::Player* playerPtr = m_Client->GetGame()->GetPlayerById(player);
m_Camera.SetAttachedPlayer(playerPtr);
m_PlayerController.SetAttachedPlayer(playerPtr);
}
} // namespace render

View File

@@ -101,15 +101,14 @@ Model LoadModel(const std::string& fileName) {
const aiScene* scene = importer.ReadFileFromMemory(fileData.data(), fileData.GetSize(),
aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_OptimizeGraph |
aiProcess_OptimizeMeshes | aiProcess_GenBoundingBoxes);
aiProcess_OptimizeMeshes);
if (nullptr == scene) {
utils::LOGE("[ModelLoader] Failed to load model !");
return {};
}
utils::LOGD(utils::Format("[ModelLoader]\tModel nodes : %i", scene->mRootNode->mNumChildren));
utils::LOGD(utils::Format("[ModelLoader]\tModel nodes : %i", scene->mRootNode->mNumMeshes));
Model model;
ProcessNode(scene->mRootNode, scene, model.mVaos, {});
@@ -117,47 +116,5 @@ Model LoadModel(const std::string& fileName) {
return model;
}
static void ProcessAABBNode(aiNode* node, const aiScene* scene, std::vector<maths::AABB>& aabbs, const aiMatrix4x4& transform) {
// recursive
for (unsigned int i = 0; i < node->mNumChildren; i++) {
ProcessAABBNode(node->mChildren[i], scene, aabbs, transform * node->mTransformation);
}
for (unsigned int i = 0; i < node->mNumMeshes; i++) {
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
aiAABB& aabb = mesh->mAABB;
aiVector3D aabbMin = transform * node->mTransformation * aabb.mMin;
aiVector3D aabbMax = transform * node->mTransformation * aabb.mMax;
aabbs.push_back({Vec3f{aabbMin.x, aabbMin.y, aabbMin.z}, {aabbMax.x, aabbMax.y, aabbMax.z}});
}
}
std::vector<maths::AABB> LoadModelAABBs(const std::string& fileName) {
DataBuffer fileData = utils::AssetsManager::GetAsset(fileName);
Assimp::Importer importer;
const aiScene* scene = importer.ReadFileFromMemory(fileData.data(), fileData.GetSize(), aiProcess_GenBoundingBoxes);
if (nullptr == scene) {
utils::LOGE("[ModelLoader] Failed to load AABB model !");
return {};
}
std::vector<maths::AABB> aabbs;
ProcessAABBNode(scene->mRootNode, scene, aabbs, {});
utils::LOGD(utils::Format("[ModelLoader]\tAABB count : %i", aabbs.size()));
return aabbs;
}
} // namespace ModelLoader
} // namespace blitz

View File

@@ -14,7 +14,7 @@
namespace blitz {
namespace server {
Server::Server() : m_TickCounter(SERVER_TPS), m_Game(this), m_ServerRunning(false), m_FreePlayerID(0) {}
Server::Server() : m_TickCounter(SERVER_TPS), m_Game(this), m_ServerRunning(false) {}
Server::~Server() {
StopThread();
@@ -112,8 +112,10 @@ void Server::Accept() {
}
game::PlayerID Server::GetNewPlayerID() {
m_FreePlayerID++;
return m_FreePlayerID - 1;
static game::PlayerID lastPlayerID = 0;
game::PlayerID newPlayerID = lastPlayerID;
lastPlayerID++;
return newPlayerID;
}
void Server::UpdateSockets() {
@@ -182,7 +184,11 @@ void Server::KickPlayer(game::PlayerID playerID) {
return;
m_Game.RemovePlayer(playerID);
RemoveConnexion(playerID);
if (player->IsBot()) {
} else {
RemoveConnexion(playerID);
}
}
} // namespace server

View File

@@ -20,23 +20,17 @@ namespace server {
ServerGame::ServerGame(Server* server) : m_Server(server), m_PositionTimer(SERVER_TPS) {
CancelGame();
InitGameConfig();
}
ServerGame::~ServerGame() {}
void ServerGame::StartGame() {
UpdateGameState(game::gsPreparing, m_ServerDuration.m_PrepDuration);
SetGameState(game::gsPreparing, m_ServerDuration.m_PrepDuration);
m_Server->BroadcastChatMessage(protocol::ChatPacket::GetTextColor(protocol::AQUA) + "La partie commence dans 10s !");
}
void ServerGame::CancelGame() {
UpdateGameState(game::gsWaiting, 0);
}
void ServerGame::InitGameConfig() {
m_Config.FiringRate = 120;
m_Config.Gravity = 20.0f;
SetGameState(game::gsWaiting, 0);
}
void ServerGame::Tick(std::uint64_t delta) {
@@ -47,18 +41,18 @@ void ServerGame::Tick(std::uint64_t delta) {
if (m_GameState != game::gsWaiting && m_GameTimer.Update(delta)) {
switch (m_GameState) {
case game::gsPreparing:
UpdateGameState(game::gsGame, m_ServerDuration.m_GameDuration);
SetGameState(game::gsGame, m_ServerDuration.m_GameDuration);
break;
case game::gsGame:
UpdateGameState(game::gsEnd, m_ServerDuration.m_EndDuration);
SetGameState(game::gsEnd, m_ServerDuration.m_EndDuration);
break;
case game::gsEnd: {
if (m_Players.size() > 1) {
UpdateGameState(game::gsGame, m_ServerDuration.m_GameDuration);
SetGameState(game::gsGame, m_ServerDuration.m_GameDuration);
} else {
UpdateGameState(game::gsWaiting, 0);
SetGameState(game::gsWaiting, 0);
}
break;
}
@@ -78,13 +72,15 @@ void ServerGame::SendPlayerPositions() {
void ServerGame::ProcessShoot(game::PlayerID shooter, Vec3f position, float yaw, float pitch) {
maths::Ray shootRay;
shootRay.origin = position + Vec3f{0.0, 0.85, 0.0};
shootRay.origin = position + Vec3f{0.0, 1.75, 0.0};
shootRay.direction = {
std::cos(yaw) * std::cos(pitch),
std::sin(pitch),
std::sin(yaw) * std::cos(pitch),
};
static const maths::AABB playerStaticAABB = {Vec3f{-0.5f, 0.0f, -0.5f}, Vec3f{0.5f, 1.8f, 0.5f}};
bool shootLanded = false;
game::Player* shooterPlayer = GetPlayerById(shooter);
@@ -92,7 +88,7 @@ void ServerGame::ProcessShoot(game::PlayerID shooter, Vec3f position, float yaw,
shooterPlayer->GetStats().m_ShootCount++;
for (auto& [playerId, player] : GetPlayers()) {
if (playerId != shooter && shootRay.Intersects(player.GetHitBox())) {
if (playerId != shooter && maths::Intersects(shootRay, playerStaticAABB + player.GetPosition())) {
if (!shootLanded) {
shootLanded = true;
shooterPlayer->GetStats().m_ShootSuccessCount++;
@@ -183,8 +179,10 @@ void ServerGame::ResetPlayerStats() {
}
}
void ServerGame::UpdateGameState(game::GameState gameState, std::uint64_t duration) {
Game::UpdateGameState(gameState, duration);
void ServerGame::SetGameState(game::GameState gameState, std::uint64_t duration) {
m_GameState = gameState;
m_GameTimer.SetInterval(duration);
m_GameTimer.Reset();
if (gameState == game::gsGame) {
ResetPlayerStats();

96
test/test_intersects.cpp Normal file → Executable file
View File

@@ -1,105 +1,105 @@
#include "blitz/misc/Test.h"
#include "blitz/maths/Physics.h"
#include "blitz/misc/Format.h"
#include "blitz/misc/Log.h"
#include "blitz/misc/Format.h"
#include <iostream>
#include <limits>
#include <ostream>
#include <limits>
using namespace blitz;
using namespace maths;
#define let auto // sexy boiiii
#define let auto // sexy boiiii
static void test_left() {
let box = AABB{{-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}};
let ray = Ray{{-2.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}};
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
let ray = Ray { {-2.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f} };
blitz_test_assert(ray.Intersects(box));
blitz_test_assert(Intersects(ray, box));
}
static void test_right() {
let box = AABB{{-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}};
let ray = Ray{{2.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}};
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
let ray = Ray { {2.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f} };
blitz_test_assert(ray.Intersects(box));
blitz_test_assert(Intersects(ray, box));
}
static void test_forward() {
let box = AABB{{-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}};
let ray = Ray{{0.0f, 2.0f, 0.0f}, {0.0f, -1.0f, 0.0f}};
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
let ray = Ray { {0.0f, 2.0f, 0.0f}, {0.0f, -1.0f, 0.0f} };
blitz_test_assert(ray.Intersects(box));
blitz_test_assert(Intersects(ray, box));
}
static void test_backward() {
let box = AABB{{-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}};
let ray = Ray{{0.0f, -2.0f, 0.0f}, {0.0f, 1.0f, 0.0f}};
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
let ray = Ray { {0.0f, -2.0f, 0.0f}, {0.0f, 1.0f, 0.0f} };
blitz_test_assert(ray.Intersects(box));
blitz_test_assert(Intersects(ray, box));
}
static void test_above() {
let box = AABB{{-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}};
let ray = Ray{{0.0f, 0.0f, 2.0f}, {0.0f, 0.0f, -1.0f}};
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
let ray = Ray { {0.0f, 0.0f, 2.0f}, {0.0f, 0.0f, -1.0f} };
blitz_test_assert(ray.Intersects(box));
blitz_test_assert(Intersects(ray, box));
}
static void test_below() {
let box = AABB{{-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}};
let ray = Ray{{0.0f, 0.0f, -2.0f}, {0.0f, 0.0f, 1.0f}};
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
let ray = Ray { {0.0f, 0.0f, -2.0f}, {0.0f, 0.0f, 1.0f} };
blitz_test_assert(ray.Intersects(box));
blitz_test_assert(Intersects(ray, box));
}
static void test_shifted() {
let box = AABB{{-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}};
let ray = Ray{{-3.0f, 0.0f, 100.0f}, {1.0f, 0.0f, 0.0f}};
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
let ray = Ray { {-3.0f, 0.0f, 100.0f}, {1.0f, 0.0f, 0.0f} };
blitz_test_assert(!ray.Intersects(box));
blitz_test_assert(!Intersects(ray, box));
}
static void test_corner_inside() {
let box = AABB{{0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}};
let ray = Ray{{0.0f, 0.0f, 0.0f}, {0.5f, 0.5f, 0.5f}};
let box = AABB { {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f} };
let ray = Ray { {0.0f, 0.0f, 0.0f}, {0.5f, 0.5f, 0.5f} };
blitz_test_assert(ray.Intersects(box));
blitz_test_assert(Intersects(ray, box));
}
static void test_corner_inside_weird() {
let box = AABB{{0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}};
let ray = Ray{{0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}};
let box = AABB { {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f} };
let ray = Ray { {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f} };
blitz_test_assert(ray.Intersects(box));
blitz_test_assert(Intersects(ray, box));
}
static void test_corner_inside_opposite_big() {
let box = AABB{{0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}};
let ray = Ray{{0.0f, 0.0f, 0.0f}, {1.5f, 1.5f, 1.5f}};
let box = AABB { {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f} };
let ray = Ray { {0.0f, 0.0f, 0.0f}, {1.5f, 1.5f, 1.5f} };
blitz_test_assert(ray.Intersects(box));
blitz_test_assert(Intersects(ray, box));
}
static void test_corner_inside_opposite_weird() {
let box = AABB{{0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}};
let ray = Ray{{0.4f, 0.4f, 0.4f}, {-1.0f, -1.0f, -1.0f}};
let box = AABB { {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f} };
let ray = Ray { {0.4f, 0.4f, 0.4f}, {-1.0f, -1.0f, -1.0f} };
blitz_test_assert(ray.Intersects(box));
blitz_test_assert(Intersects(ray, box));
}
int main(int argc, const char* args[]) {
test_left();
test_right();
test_forward();
test_backward();
test_below();
test_above();
test_shifted();
test_corner_inside();
test_corner_inside_weird();
test_corner_inside_opposite_big();
test_corner_inside_opposite_weird();
return BLITZ_TEST_SUCCESSFUL;
test_left();
test_right();
test_forward();
test_backward();
test_below();
test_above();
test_shifted();
test_corner_inside();
test_corner_inside_weird();
test_corner_inside_opposite_big();
test_corner_inside_opposite_weird();
return BLITZ_TEST_SUCCESSFUL;
}