Add vehicle sound sjeta

This commit is contained in:
tovjemam 2026-01-09 23:13:35 +01:00
parent 8f59d76cf9
commit 421fbdd710
19 changed files with 128 additions and 22 deletions

View File

@ -67,6 +67,7 @@ set(CLIENT_ONLY_SOURCES
"src/gameview/client_session.hpp" "src/gameview/client_session.hpp"
"src/gameview/client_session.cpp" "src/gameview/client_session.cpp"
"src/gameview/entityview.hpp" "src/gameview/entityview.hpp"
"src/gameview/entityview.cpp"
"src/gameview/vehicleview.hpp" "src/gameview/vehicleview.hpp"
"src/gameview/vehicleview.cpp" "src/gameview/vehicleview.cpp"
"src/gameview/worldview.hpp" "src/gameview/worldview.hpp"
@ -219,9 +220,15 @@ endif()
target_link_libraries(${MAIN_NAME} PRIVATE easywsclient) target_link_libraries(${MAIN_NAME} PRIVATE easywsclient)
# add openal # add openal
set(ALSOFT_EXAMPLES OFF) set(ALSOFT_EXAMPLES OFF CACHE BOOL "" FORCE)
add_subdirectory(external/openal-soft) add_subdirectory(external/openal-soft)
target_link_libraries(${MAIN_NAME} PRIVATE OpenAL) target_link_libraries(${MAIN_NAME} PRIVATE OpenAL::OpenAL)
add_custom_command(TARGET ${MAIN_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:OpenAL>
$<TARGET_FILE_DIR:${MAIN_NAME}>
)
# build server # build server
set(ASIO_INCLUDE_DIR "external/asio/include") set(ASIO_INCLUDE_DIR "external/asio/include")

View File

@ -19,7 +19,7 @@ class Category
{ {
public: public:
Category(const std::string& name); Category(const std::string& name);
DELETE_COPY_MOVE(Category) // DELETE_COPY_MOVE(Category) // HACK: make it possible to push into reserved vector
const std::string& GetName() const { return name_; } const std::string& GetName() const { return name_; }

View File

@ -31,12 +31,12 @@ std::shared_ptr<const audio::Sound> audio::Sound::LoadFromFile(const std::string
{ {
auto sound = std::make_shared<Sound>(); auto sound = std::make_shared<Sound>();
std::string ogg_path; std::string ogg_name;
assets::LoadCMDFile(path, [&](const std::string& cmd, std::istringstream& iss) { assets::LoadCMDFile(path, [&](const std::string& cmd, std::istringstream& iss) {
if (cmd == "ogg") if (cmd == "ogg")
{ {
iss >> ogg_path; iss >> ogg_name;
} }
else if (cmd == "category") else if (cmd == "category")
{ {
@ -55,7 +55,8 @@ std::shared_ptr<const audio::Sound> audio::Sound::LoadFromFile(const std::string
if (sound->category_name_.empty()) if (sound->category_name_.empty())
sound->category_name_ = "default"; sound->category_name_ = "default";
LoadBufferOGG(sound->GetBufferId(), ogg_path.c_str()); ogg_name = "data/" + ogg_name + ".ogg";
LoadBufferOGG(sound->GetBufferId(), ogg_name.c_str());
return sound; return sound;
} }

View File

@ -9,11 +9,8 @@ namespace audio
class Sound class Sound
{ {
private:
Sound();
friend std::shared_ptr<Sound> std::make_shared<Sound>();
public: public:
Sound();
static std::shared_ptr<const Sound> LoadFromFile(const std::string& path); static std::shared_ptr<const Sound> LoadFromFile(const std::string& path);
unsigned int GetBufferId() const { return buffer_; } unsigned int GetBufferId() const { return buffer_; }

View File

@ -9,7 +9,7 @@ audio::SoundSource::SoundSource(Player* player, std::shared_ptr<const Sound> sou
SetVolume(1.0f); SetVolume(1.0f);
SetPitch(1.0f); SetPitch(1.0f);
alSourcei(source_, AL_BUFFER, sound->GetBufferId()); alSourcei(source_, AL_BUFFER, sound_->GetBufferId());
} }
void audio::SoundSource::SetLooping(bool looping) void audio::SoundSource::SetLooping(bool looping)

View File

@ -11,7 +11,7 @@ App::App()
{ {
std::cout << "Initializing App..." << std::endl; std::cout << "Initializing App..." << std::endl;
audiomaster_.SetMasterVolume(0.2f);
} }
void App::Frame() void App::Frame()
@ -55,11 +55,15 @@ void App::Frame()
// glm::mat4 view = glm::lookAt(glm::vec3(15.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, -13.0f), glm::vec3(0.0f, 0.0f, 1.0f)); // glm::mat4 view = glm::lookAt(glm::vec3(15.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, -13.0f), glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 3000.0f); glm::mat4 proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 3000.0f);
glm::mat4 view = session_->GetViewMatrix();
gfx::DrawListParams params; gfx::DrawListParams params;
params.view_proj = proj * session_->GetViewMatrix(); params.view_proj = proj * view;
renderer_.DrawList(dlist_, params); renderer_.DrawList(dlist_, params);
glm::mat4 camera_world = glm::inverse(view);
audiomaster_.SetListenerOrientation(camera_world);
} }
if (time_ - last_send_time_ > 0.040f) if (time_ - last_send_time_ > 0.040f)

View File

@ -4,6 +4,7 @@
#include "game/player_input.hpp" #include "game/player_input.hpp"
#include "gfx/renderer.hpp" #include "gfx/renderer.hpp"
#include "audio/master.hpp"
#include "net/msg_producer.hpp" #include "net/msg_producer.hpp"
#include "net/inmessage.hpp" #include "net/inmessage.hpp"
@ -29,6 +30,8 @@ public:
float GetTime() const { return delta_time_; } float GetTime() const { return delta_time_; }
float GetDeltaTime() const { return delta_time_; } float GetDeltaTime() const { return delta_time_; }
audio::Master& GetAudioMaster() { return audiomaster_; }
~App(); ~App();
private: private:
@ -47,5 +50,7 @@ private:
gfx::Renderer renderer_; gfx::Renderer renderer_;
gfx::DrawList dlist_; gfx::DrawList dlist_;
audio::Master audiomaster_;
std::unique_ptr<game::view::ClientSession> session_; std::unique_ptr<game::view::ClientSession> session_;
}; };

View File

@ -153,7 +153,12 @@ static void PollEvents()
} }
} }
#ifdef NDEBUG
#define WS_URL "ws://deadfish.cz:11200/ws" #define WS_URL "ws://deadfish.cz:11200/ws"
#else
#define WS_URL "ws://127.0.0.1:11200/ws"
#endif
static bool s_ws_connected = false; static bool s_ws_connected = false;

View File

@ -105,6 +105,7 @@ void game::Vehicle::Update()
{ {
Super::Update(); Super::Update();
flags_ = 0;
ProcessInput(); ProcessInput();
UpdateWheels(); UpdateWheels();
@ -216,6 +217,12 @@ void game::Vehicle::ProcessInput()
vehicle_->setSteeringValue(steering_, 0); vehicle_->setSteeringValue(steering_, 0);
vehicle_->setSteeringValue(steering_, 1); vehicle_->setSteeringValue(steering_, 1);
if (glm::abs(engineForce) > 0)
flags_ |= VF_ACCELERATING;
if (glm::abs(breakingForce) > 0)
flags_ |= VF_BREAKING;
} }
void game::Vehicle::UpdateWheels() void game::Vehicle::UpdateWheels()
@ -232,6 +239,7 @@ void game::Vehicle::UpdateWheels()
void game::Vehicle::SendUpdateMsg() void game::Vehicle::SendUpdateMsg()
{ {
auto msg = BeginEntMsg(net::EMSG_UPDATE); auto msg = BeginEntMsg(net::EMSG_UPDATE);
msg.Write(flags_);
net::WriteTransform(msg, root_.local); net::WriteTransform(msg, root_.local);
// send wheel info // send wheel info

View File

@ -8,6 +8,7 @@
#include "controllable.hpp" #include "controllable.hpp"
#include "entity.hpp" #include "entity.hpp"
#include "world.hpp" #include "world.hpp"
#include "vehicleflags.hpp"
namespace game namespace game
{ {
@ -54,6 +55,8 @@ private:
size_t num_wheels_ = 0; size_t num_wheels_ = 0;
std::array<VehicleWheelState, MAX_WHEELS> wheels_; std::array<VehicleWheelState, MAX_WHEELS> wheels_;
VehicleFlags flags_;
}; };
} // namespace game } // namespace game

17
src/game/vehicleflags.hpp Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <cstdint>
namespace game
{
using VehicleFlags = uint8_t;
enum VehicleFlag : VehicleFlags
{
VF_NONE,
VF_ACCELERATING = 1,
VF_BREAKING = 2,
};
}

View File

@ -86,6 +86,11 @@ glm::mat4 game::view::ClientSession::GetViewMatrix() const
return glm::lookAt(eye, center, glm::vec3(0, 0, 1)); return glm::lookAt(eye, center, glm::vec3(0, 0, 1));
} }
audio::Master& game::view::ClientSession::GetAudioMaster() const
{
return app_.GetAudioMaster();
}
bool game::view::ClientSession::ProcessWorldMsg(net::InMessage& msg) bool game::view::ClientSession::ProcessWorldMsg(net::InMessage& msg)
{ {
net::MapName mapname; net::MapName mapname;

View File

@ -29,6 +29,8 @@ public:
glm::mat4 GetViewMatrix() const; glm::mat4 GetViewMatrix() const;
audio::Master& GetAudioMaster() const;
private: private:
// msg handlers // msg handlers
bool ProcessWorldMsg(net::InMessage& msg); bool ProcessWorldMsg(net::InMessage& msg);

View File

@ -0,0 +1,17 @@
#include "entityview.hpp"
#include "worldview.hpp"
game::view::EntityView::EntityView(WorldView& world) : world_(world), audioplayer_(world_.GetAudioMaster()) {}
bool game::view::EntityView::ProcessMsg(net::EntMsgType type, net::InMessage& msg)
{
return false;
}
void game::view::EntityView::Update(const UpdateInfo& info)
{
audioplayer_.Update();
}
void game::view::EntityView::Draw(gfx::DrawList& dlist) {}

View File

@ -4,6 +4,7 @@
#include "game/transform_node.hpp" #include "game/transform_node.hpp"
#include "gfx/draw_list.hpp" #include "gfx/draw_list.hpp"
#include "audio/player.hpp"
#include "net/defs.hpp" #include "net/defs.hpp"
#include "net/inmessage.hpp" #include "net/inmessage.hpp"
@ -24,12 +25,12 @@ struct UpdateInfo
class EntityView class EntityView
{ {
public: public:
EntityView(WorldView& world) : world_(world) {} EntityView(WorldView& world);
DELETE_COPY_MOVE(EntityView) DELETE_COPY_MOVE(EntityView)
virtual bool ProcessMsg(net::EntMsgType type, net::InMessage& msg) { return false; } virtual bool ProcessMsg(net::EntMsgType type, net::InMessage& msg);
virtual void Update(const UpdateInfo& info) {} virtual void Update(const UpdateInfo& info);
virtual void Draw(gfx::DrawList& dlist) {} virtual void Draw(gfx::DrawList& dlist);
const TransformNode& GetRoot() const { return root_; } const TransformNode& GetRoot() const { return root_; }
@ -37,9 +38,11 @@ public:
protected: protected:
WorldView& world_; WorldView& world_;
TransformNode root_; TransformNode root_;
bool visible_ = false; bool visible_ = false;
audio::Player audioplayer_;
}; };
} // namespace game::view } // namespace game::view

View File

@ -16,6 +16,8 @@ game::view::VehicleView::VehicleView(WorldView& world, std::shared_ptr<const ass
{ {
wheels_[i].node.parent = &root_; wheels_[i].node.parent = &root_;
} }
snd_accel_ = assets::CacheManager::GetSound("data/auto.snd");
} }
std::unique_ptr<game::view::VehicleView> game::view::VehicleView::InitFromMsg(WorldView& world, net::InMessage& msg) std::unique_ptr<game::view::VehicleView> game::view::VehicleView::InitFromMsg(WorldView& world, net::InMessage& msg)
@ -43,6 +45,8 @@ bool game::view::VehicleView::ProcessMsg(net::EntMsgType type, net::InMessage& m
void game::view::VehicleView::Update(const UpdateInfo& info) void game::view::VehicleView::Update(const UpdateInfo& info)
{ {
Super::Update(info);
float tps = 25.0f; float tps = 25.0f;
float t = (info.time - update_time_) * tps * 0.8f; // assume some jitter, interpolate for longer float t = (info.time - update_time_) * tps * 0.8f; // assume some jitter, interpolate for longer
t = glm::clamp(t, 0.0f, 2.0f); t = glm::clamp(t, 0.0f, 2.0f);
@ -68,6 +72,20 @@ void game::view::VehicleView::Update(const UpdateInfo& info)
wheels_[i].node.UpdateMatrix(); wheels_[i].node.UpdateMatrix();
} }
// update snds
bool accel = flags_ & VF_ACCELERATING;
if (accel && !snd_accel_src_)
{
snd_accel_src_ = audioplayer_.PlaySound(snd_accel_, &root_.local.position);
snd_accel_src_->SetLooping(true);
}
else if (!accel && snd_accel_src_)
{
snd_accel_src_->Delete();
snd_accel_src_ = nullptr;
}
} }
void game::view::VehicleView::Draw(gfx::DrawList& dlist) void game::view::VehicleView::Draw(gfx::DrawList& dlist)
@ -105,6 +123,9 @@ bool game::view::VehicleView::ProcessUpdateMsg(net::InMessage& msg)
auto& root_trans = root_trans_[1]; auto& root_trans = root_trans_[1];
update_time_ = world_.GetTime(); update_time_ = world_.GetTime();
if (!msg.Read(flags_))
return false;
if (!net::ReadTransform(msg, root_trans)) if (!net::ReadTransform(msg, root_trans))
return false; return false;

View File

@ -3,6 +3,7 @@
#include "entityview.hpp" #include "entityview.hpp"
#include "assets/vehiclemdl.hpp" #include "assets/vehiclemdl.hpp"
#include "game/vehicleflags.hpp"
#include <chrono> #include <chrono>
@ -20,6 +21,7 @@ struct VehicleWheelViewInfo
class VehicleView : public EntityView class VehicleView : public EntityView
{ {
using Super = EntityView;
public: public:
VehicleView(WorldView& world, std::shared_ptr<const assets::VehicleModel> model); VehicleView(WorldView& world, std::shared_ptr<const assets::VehicleModel> model);
static std::unique_ptr<VehicleView> InitFromMsg(WorldView& world, net::InMessage& msg); static std::unique_ptr<VehicleView> InitFromMsg(WorldView& world, net::InMessage& msg);
@ -39,6 +41,10 @@ private:
float update_time_ = 0.0f; float update_time_ = 0.0f;
Transform root_trans_[2]; Transform root_trans_[2];
VehicleFlags flags_ = 0;
std::shared_ptr<const audio::Sound> snd_accel_;
audio::SoundSource* snd_accel_src_ = nullptr;
}; };
} }

View File

@ -5,7 +5,9 @@
#include "vehicleview.hpp" #include "vehicleview.hpp"
#include "client_session.hpp" #include "client_session.hpp"
game::view::WorldView::WorldView(ClientSession& session) : session_(session) game::view::WorldView::WorldView(ClientSession& session) :
session_(session),
audiomaster_(session_.GetAudioMaster())
{ {
map_ = assets::CacheManager::GetMap("data/openworld.map"); map_ = assets::CacheManager::GetMap("data/openworld.map");
} }

View File

@ -26,6 +26,8 @@ public:
float GetTime() const { return time_; } float GetTime() const { return time_; }
audio::Master& GetAudioMaster() const { return audiomaster_; }
private: private:
// msg handlers // msg handlers
bool ProcessEntSpawnMsg(net::InMessage& msg); bool ProcessEntSpawnMsg(net::InMessage& msg);
@ -34,12 +36,13 @@ private:
private: private:
ClientSession& session_; ClientSession& session_;
std::shared_ptr<const assets::Map> map_; std::shared_ptr<const assets::Map> map_;
std::map<net::EntNum, std::unique_ptr<EntityView>> ents_; std::map<net::EntNum, std::unique_ptr<EntityView>> ents_;
float time_ = 0.0f; float time_ = 0.0f;
audio::Master& audiomaster_;
}; };
} // namespace game::view } // namespace game::view