Some sound effects
This commit is contained in:
parent
986cbc12a6
commit
55efcceaf0
@ -13,6 +13,8 @@
|
|||||||
#include "gfx/font.hpp"
|
#include "gfx/font.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace assets
|
namespace assets
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -33,6 +35,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << "loading " << key << "..." << std::endl;
|
||||||
PtrType obj = Load(key);
|
PtrType obj = Load(key);
|
||||||
cache_[key] = obj; // Cache the loaded object
|
cache_[key] = obj; // Cache the loaded object
|
||||||
return obj;
|
return obj;
|
||||||
|
|||||||
@ -180,13 +180,16 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
|
|||||||
iss >> com.x >> com.y >> com.z;
|
iss >> com.x >> com.y >> com.z;
|
||||||
model->col_offset_ = com;
|
model->col_offset_ = com;
|
||||||
}
|
}
|
||||||
|
else if (command == "param")
|
||||||
|
{
|
||||||
|
std::string key, val;
|
||||||
|
iss >> key >> val;
|
||||||
|
model->params_[key] = val;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Unknown command in model file: " + command);
|
throw std::runtime_error("Unknown command in model file: " + command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: skeleton
|
|
||||||
});
|
});
|
||||||
|
|
||||||
CLIENT_ONLY(
|
CLIENT_ONLY(
|
||||||
@ -215,3 +218,29 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
|
|||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string* assets::Model::GetParam(const std::string& key) const
|
||||||
|
{
|
||||||
|
auto it = params_.find(key);
|
||||||
|
if (it == params_.end())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool assets::Model::GetParamFloat(const std::string& key, float& out) const
|
||||||
|
{
|
||||||
|
auto str_val = GetParam(key);
|
||||||
|
if (!str_val)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string str = *str_val;
|
||||||
|
|
||||||
|
auto dashpos = str.find(',');
|
||||||
|
if (dashpos != std::string::npos)
|
||||||
|
str[dashpos] = '.';
|
||||||
|
|
||||||
|
out = std::strtof(str.c_str(), nullptr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@ -34,7 +34,6 @@ namespace assets
|
|||||||
// };
|
// };
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
|
||||||
class Model
|
class Model
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -51,6 +50,9 @@ public:
|
|||||||
CLIENT_ONLY(const std::shared_ptr<const Mesh>& GetMesh() const { return mesh_; })
|
CLIENT_ONLY(const std::shared_ptr<const Mesh>& GetMesh() const { return mesh_; })
|
||||||
const AABB3& GetAABB() const { return aabb_; }
|
const AABB3& GetAABB() const { return aabb_; }
|
||||||
|
|
||||||
|
const std::string* GetParam(const std::string& key) const;
|
||||||
|
bool GetParamFloat(const std::string& key, float& out) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name_;
|
std::string name_;
|
||||||
glm::vec3 col_offset_ = glm::vec3(0.0f);
|
glm::vec3 col_offset_ = glm::vec3(0.0f);
|
||||||
@ -63,6 +65,8 @@ private:
|
|||||||
CLIENT_ONLY(std::shared_ptr<const Mesh> mesh_;);
|
CLIENT_ONLY(std::shared_ptr<const Mesh> mesh_;);
|
||||||
AABB3 aabb_;
|
AABB3 aabb_;
|
||||||
|
|
||||||
|
std::map<std::string, std::string> params_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -3,6 +3,8 @@
|
|||||||
#include <AL/al.h>
|
#include <AL/al.h>
|
||||||
#include <AL/alc.h>
|
#include <AL/alc.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
audio::SoundSource::SoundSource(Player* player, std::shared_ptr<const Sound> sound)
|
audio::SoundSource::SoundSource(Player* player, std::shared_ptr<const Sound> sound)
|
||||||
: Super(sound->GetCategoryName(), player), sound_(std::move(sound))
|
: Super(sound->GetCategoryName(), player), sound_(std::move(sound))
|
||||||
{
|
{
|
||||||
@ -26,6 +28,7 @@ void audio::SoundSource::SetPitch(float pitch)
|
|||||||
void audio::SoundSource::SetVolume(float volume)
|
void audio::SoundSource::SetVolume(float volume)
|
||||||
{
|
{
|
||||||
Super::SetSourceVolume(sound_->GetVolume() * volume);
|
Super::SetSourceVolume(sound_->GetVolume() * volume);
|
||||||
|
//std::cout << "src volume " << sound_->GetVolume() * volume << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::SoundSource::Update()
|
void audio::SoundSource::Update()
|
||||||
|
|||||||
@ -12,9 +12,9 @@ App::App()
|
|||||||
std::cout << "Initializing App..." << std::endl;
|
std::cout << "Initializing App..." << std::endl;
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef EMSCRIPTEN
|
||||||
audiomaster_.SetMasterVolume(0.2f);
|
audiomaster_.SetMasterVolume(1.0f);
|
||||||
#else
|
#else
|
||||||
audiomaster_.SetMasterVolume(0.8f);
|
audiomaster_.SetMasterVolume(2.0f);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
font_ = assets::CacheManager::GetFont("data/comic32.font");
|
font_ = assets::CacheManager::GetFont("data/comic32.font");
|
||||||
|
|||||||
@ -73,9 +73,9 @@ static void InitSDL()
|
|||||||
|
|
||||||
#ifndef PG_GLES
|
#ifndef PG_GLES
|
||||||
static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
|
static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
|
||||||
//if (severity == 0x826b)
|
if (severity == 0x826b)
|
||||||
// return;
|
return;
|
||||||
//
|
|
||||||
////std::cout << message << std::endl;
|
////std::cout << message << std::endl;
|
||||||
fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
|
fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
|
||||||
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
|
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
|
||||||
|
|||||||
49
src/collision/object_info.hpp
Normal file
49
src/collision/object_info.hpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <btBulletDynamicsCommon.h>
|
||||||
|
|
||||||
|
namespace collision
|
||||||
|
{
|
||||||
|
|
||||||
|
enum ObjectType : int
|
||||||
|
{
|
||||||
|
OT_UNDEFINED,
|
||||||
|
OT_MAP_OBJECT,
|
||||||
|
OT_ENTITY,
|
||||||
|
};
|
||||||
|
|
||||||
|
using ObjectFlags = int;
|
||||||
|
|
||||||
|
enum ObjectFlag : ObjectFlags
|
||||||
|
{
|
||||||
|
OF_DESTRUCTIBLE = 0x01,
|
||||||
|
OF_NOTIFY_CONTACT = 0x02,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ObjectCallback() = default;
|
||||||
|
|
||||||
|
virtual void OnContact(float impulse) {}
|
||||||
|
|
||||||
|
virtual ~ObjectCallback() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void SetObjectInfo(btCollisionObject* obj, ObjectType type, ObjectFlags flags, ObjectCallback* callback)
|
||||||
|
{
|
||||||
|
obj->setUserIndex(static_cast<int>(type));
|
||||||
|
obj->setUserIndex2(static_cast<int>(flags));
|
||||||
|
obj->setUserPointer(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void GetObjectInfo(const btCollisionObject* obj, ObjectType& type, ObjectFlags& flags, ObjectCallback*& callback)
|
||||||
|
{
|
||||||
|
type = static_cast<ObjectType>(obj->getUserIndex());
|
||||||
|
flags = static_cast<ObjectFlags>(obj->getUserIndex2());
|
||||||
|
callback = static_cast<ObjectCallback*>(obj->getUserPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace collision
|
|
||||||
{
|
|
||||||
|
|
||||||
enum ObjectType
|
|
||||||
{
|
|
||||||
OT_UNDEFINED = 0,
|
|
||||||
OT_MAP_STATIC = 1,
|
|
||||||
OT_MAP_DESTRUCTIBLE = 2,
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,11 +1,19 @@
|
|||||||
#include "destroyed_object.hpp"
|
#include "destroyed_object.hpp"
|
||||||
|
#include "utils/random.hpp"
|
||||||
|
|
||||||
game::DestroyedObject::DestroyedObject(World& world, std::unique_ptr<MapObjectCollision> col)
|
game::DestroyedObject::DestroyedObject(World& world, std::unique_ptr<MapObjectCollision> col)
|
||||||
: Super(world, col->GetModel()->GetName()), col_(std::move(col))
|
: Super(world, col->GetModel()->GetName()), col_(std::move(col))
|
||||||
{
|
{
|
||||||
// remove after 30s
|
auto destr_snd_str = col_->GetModel()->GetParam("destr_snd");
|
||||||
Schedule(30000, [this]()
|
if (destr_snd_str)
|
||||||
{
|
{
|
||||||
|
Schedule(1, [this, destr_snd_str] {
|
||||||
|
PlaySound(*destr_snd_str, RandomFloat(0.8f, 1.2f), RandomFloat(0.8f, 1.2f));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove after 30s
|
||||||
|
Schedule(30000, [this] {
|
||||||
Remove();
|
Remove();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "drivable_vehicle.hpp"
|
#include "drivable_vehicle.hpp"
|
||||||
#include "player_character.hpp"
|
#include "player_character.hpp"
|
||||||
|
#include "utils/random.hpp"
|
||||||
|
|
||||||
game::DrivableVehicle::DrivableVehicle(World& world, std::string model_name, const glm::vec3& color)
|
game::DrivableVehicle::DrivableVehicle(World& world, std::string model_name, const glm::vec3& color)
|
||||||
: Vehicle(world, std::move(model_name), color)
|
: Vehicle(world, std::move(model_name), color)
|
||||||
@ -13,6 +14,8 @@ void game::DrivableVehicle::Use(PlayerCharacter& character, uint32_t target_id)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
character.SetVehicle(this, target_id); // seat idx is same as target_id
|
character.SetVehicle(this, target_id); // seat idx is same as target_id
|
||||||
|
PlaySound("cardoor", 1.0f, RandomFloat(0.9f, 1.1f));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool game::DrivableVehicle::SetPassenger(uint32_t seat_idx, ControllableCharacter* character)
|
bool game::DrivableVehicle::SetPassenger(uint32_t seat_idx, ControllableCharacter* character)
|
||||||
|
|||||||
@ -52,6 +52,14 @@ void game::Entity::Attach(net::EntNum parentnum)
|
|||||||
SendAttachMsg();
|
SendAttachMsg();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void game::Entity::PlaySound(const std::string& name, float volume, float pitch)
|
||||||
|
{
|
||||||
|
auto msg = BeginEntMsg(net::EMSG_PLAYSOUND);
|
||||||
|
msg.Write(net::SoundName(name));
|
||||||
|
msg.Write<net::SoundVolumeQ>(volume);
|
||||||
|
msg.Write<net::SoundPitchQ>(pitch);
|
||||||
|
}
|
||||||
|
|
||||||
void game::Entity::WriteNametag(net::OutMessage& msg) const
|
void game::Entity::WriteNametag(net::OutMessage& msg) const
|
||||||
{
|
{
|
||||||
msg.Write(net::NameTag{nametag_});
|
msg.Write(net::NameTag{nametag_});
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "transform_node.hpp"
|
#include "transform_node.hpp"
|
||||||
#include "utils/defs.hpp"
|
#include "utils/defs.hpp"
|
||||||
#include "utils/scheduler.hpp"
|
#include "utils/scheduler.hpp"
|
||||||
|
#include "collision/object_info.hpp"
|
||||||
|
|
||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
@ -13,7 +14,7 @@ namespace game
|
|||||||
class World;
|
class World;
|
||||||
class Player;
|
class Player;
|
||||||
|
|
||||||
class Entity : public net::MsgProducer, public Scheduler
|
class Entity : public net::MsgProducer, public Scheduler, public collision::ObjectCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Entity(World& world, net::EntType viewtype);
|
Entity(World& world, net::EntType viewtype);
|
||||||
@ -33,11 +34,14 @@ public:
|
|||||||
void Attach(net::EntNum parentnum);
|
void Attach(net::EntNum parentnum);
|
||||||
net::EntNum GetParentNum() const { return parentnum_; }
|
net::EntNum GetParentNum() const { return parentnum_; }
|
||||||
|
|
||||||
|
void PlaySound(const std::string& name, float volume = 1.0f, float pitch = 1.0f);
|
||||||
|
|
||||||
void Remove() { removed_ = true; }
|
void Remove() { removed_ = true; }
|
||||||
bool IsRemoved() const { return removed_; }
|
bool IsRemoved() const { return removed_; }
|
||||||
|
|
||||||
const TransformNode& GetRoot() const { return root_; }
|
const TransformNode& GetRoot() const { return root_; }
|
||||||
const Transform& GetRootTransform() const { return root_.local; }
|
const Transform& GetRootTransform() const { return root_.local; }
|
||||||
|
|
||||||
float GetMaxDistance() const { return max_distance_; }
|
float GetMaxDistance() const { return max_distance_; }
|
||||||
|
|
||||||
virtual ~Entity() = default;
|
virtual ~Entity() = default;
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "assets/cache.hpp"
|
#include "assets/cache.hpp"
|
||||||
#include "collision/object_type.hpp"
|
|
||||||
|
|
||||||
game::MapInstance::MapInstance(collision::DynamicsWorld& world, std::string mapname)
|
game::MapInstance::MapInstance(collision::DynamicsWorld& world, std::string mapname)
|
||||||
: world_(world), mapname_(std::move(mapname))
|
: world_(world), mapname_(std::move(mapname))
|
||||||
@ -67,14 +66,13 @@ game::MapObjectCollision::MapObjectCollision(collision::DynamicsWorld& world,
|
|||||||
|
|
||||||
const bool destructible = (flags & MAPOBJ_DESTRUCTIBLE) != 0 && cshape != nullptr;
|
const bool destructible = (flags & MAPOBJ_DESTRUCTIBLE) != 0 && cshape != nullptr;
|
||||||
|
|
||||||
collision::ObjectType obj_type = collision::OT_MAP_STATIC;
|
|
||||||
|
|
||||||
btVector3 local_inertia(0, 0, 0);
|
btVector3 local_inertia(0, 0, 0);
|
||||||
float mass = 0.0f;
|
float mass = 0.0f;
|
||||||
|
collision::ObjectFlags oflags = 0;
|
||||||
|
|
||||||
if (destructible)
|
if (destructible)
|
||||||
{
|
{
|
||||||
obj_type = collision::OT_MAP_DESTRUCTIBLE;
|
oflags |= collision::OF_DESTRUCTIBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prefer simple cshape which allow destruction
|
// prefer simple cshape which allow destruction
|
||||||
@ -93,8 +91,8 @@ game::MapObjectCollision::MapObjectCollision(collision::DynamicsWorld& world,
|
|||||||
offset_trans.position += trans.rotation * model_->GetColOffset();
|
offset_trans.position += trans.rotation * model_->GetColOffset();
|
||||||
|
|
||||||
body_->setWorldTransform(offset_trans.ToBtTransform());
|
body_->setWorldTransform(offset_trans.ToBtTransform());
|
||||||
body_->setUserIndex(static_cast<int>(obj_type));
|
|
||||||
body_->setUserPointer(this);
|
collision::SetObjectInfo(body_.get(), collision::OT_MAP_OBJECT, oflags, this);
|
||||||
|
|
||||||
// world_.GetBtWorld().addRigidBody(body_.get(), btBroadphaseProxy::StaticFilter, btBroadphaseProxy::AllFilter);
|
// world_.GetBtWorld().addRigidBody(body_.get(), btBroadphaseProxy::StaticFilter, btBroadphaseProxy::AllFilter);
|
||||||
world_.GetBtWorld().addRigidBody(body_.get());
|
world_.GetBtWorld().addRigidBody(body_.get());
|
||||||
@ -119,7 +117,9 @@ void game::MapObjectCollision::Break()
|
|||||||
// make new
|
// make new
|
||||||
body_ = std::make_unique<btRigidBody>(btRigidBody::btRigidBodyConstructionInfo(mass, nullptr, shape, local_inertia));
|
body_ = std::make_unique<btRigidBody>(btRigidBody::btRigidBodyConstructionInfo(mass, nullptr, shape, local_inertia));
|
||||||
body_->setWorldTransform(trans);
|
body_->setWorldTransform(trans);
|
||||||
body_->setUserIndex(static_cast<int>(collision::OT_UNDEFINED));
|
|
||||||
|
collision::SetObjectInfo(body_.get(), collision::OT_UNDEFINED, 0, this);
|
||||||
|
|
||||||
world_.GetBtWorld().addRigidBody(body_.get());
|
world_.GetBtWorld().addRigidBody(body_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "assets/map.hpp"
|
#include "assets/map.hpp"
|
||||||
#include "collision/dynamicsworld.hpp"
|
#include "collision/dynamicsworld.hpp"
|
||||||
#include "net/defs.hpp"
|
#include "net/defs.hpp"
|
||||||
|
#include "collision/object_info.hpp"
|
||||||
|
|
||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
@ -14,7 +15,7 @@ enum MapObjectCollisionFlag : MapObjectCollisionFlags
|
|||||||
MAPOBJ_DESTRUCTIBLE = 0x01,
|
MAPOBJ_DESTRUCTIBLE = 0x01,
|
||||||
};
|
};
|
||||||
|
|
||||||
class MapObjectCollision
|
class MapObjectCollision : public collision::ObjectCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MapObjectCollision(collision::DynamicsWorld& world, std::shared_ptr<const assets::Model> model,
|
MapObjectCollision(collision::DynamicsWorld& world, std::shared_ptr<const assets::Model> model,
|
||||||
@ -29,8 +30,7 @@ public:
|
|||||||
btRigidBody& GetBtBody() { return *body_; }
|
btRigidBody& GetBtBody() { return *body_; }
|
||||||
net::ObjNum GetNum() const { return num_; }
|
net::ObjNum GetNum() const { return num_; }
|
||||||
|
|
||||||
|
virtual ~MapObjectCollision() override;
|
||||||
~MapObjectCollision();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
collision::DynamicsWorld& world_;
|
collision::DynamicsWorld& world_;
|
||||||
|
|||||||
@ -82,10 +82,9 @@ void game::OpenWorld::DestructibleDestroyed(net::ObjNum num, std::unique_ptr<Map
|
|||||||
{
|
{
|
||||||
auto& destroyed_obj = Spawn<DestroyedObject>(std::move(col));
|
auto& destroyed_obj = Spawn<DestroyedObject>(std::move(col));
|
||||||
|
|
||||||
// Schedule(100000, [this, objnum = num]()
|
Schedule(10000, [this, num] {
|
||||||
// {
|
RespawnObj(num);
|
||||||
// RespawnObj(objnum);
|
});
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::pair<game::Usable&, const game::UseTarget&>> game::OpenWorld::GetBestUseTarget(const glm::vec3& pos) const
|
std::optional<std::pair<game::Usable&, const game::UseTarget&>> game::OpenWorld::GetBestUseTarget(const glm::vec3& pos) const
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "net/utils.hpp"
|
#include "net/utils.hpp"
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
#include "player_input.hpp"
|
#include "player_input.hpp"
|
||||||
|
#include "utils/random.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@ -33,6 +34,8 @@ game::Vehicle::Vehicle(World& world, std::string model_name, const glm::vec3& co
|
|||||||
body_ = std::make_unique<btRigidBody>(rb_info);
|
body_ = std::make_unique<btRigidBody>(rb_info);
|
||||||
body_->setActivationState(DISABLE_DEACTIVATION);
|
body_->setActivationState(DISABLE_DEACTIVATION);
|
||||||
|
|
||||||
|
collision::SetObjectInfo(body_.get(), collision::OT_ENTITY, collision::OF_NOTIFY_CONTACT, this);
|
||||||
|
|
||||||
// setup vehicle
|
// setup vehicle
|
||||||
btRaycastVehicle::btVehicleTuning tuning;
|
btRaycastVehicle::btVehicleTuning tuning;
|
||||||
vehicle_ = std::make_unique<btRaycastVehicle>(tuning, body_.get(), &world_.GetVehicleRaycaster());
|
vehicle_ = std::make_unique<btRaycastVehicle>(tuning, body_.get(), &world_.GetVehicleRaycaster());
|
||||||
@ -100,6 +103,7 @@ void game::Vehicle::Update()
|
|||||||
root_.UpdateMatrix();
|
root_.UpdateMatrix();
|
||||||
|
|
||||||
flags_ = 0;
|
flags_ = 0;
|
||||||
|
UpdateCrash();
|
||||||
ProcessInput();
|
ProcessInput();
|
||||||
UpdateWheels();
|
UpdateWheels();
|
||||||
|
|
||||||
@ -123,6 +127,27 @@ void game::Vehicle::SendInitData(Player& player, net::OutMessage& msg) const
|
|||||||
msg.WriteAt(fields_pos, fields);
|
msg.WriteAt(fields_pos, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void game::Vehicle::OnContact(float impulse)
|
||||||
|
{
|
||||||
|
Super::OnContact(impulse);
|
||||||
|
|
||||||
|
crash_intensity_ += impulse;
|
||||||
|
|
||||||
|
if (impulse < 1000.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (window_health_ > 0.0f)
|
||||||
|
{
|
||||||
|
window_health_ -= impulse;
|
||||||
|
|
||||||
|
if (window_health_ <= 0.0f) // just broken
|
||||||
|
{
|
||||||
|
PlaySound("breakwindow", 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void game::Vehicle::SetInput(VehicleInputType type, bool enable)
|
void game::Vehicle::SetInput(VehicleInputType type, bool enable)
|
||||||
{
|
{
|
||||||
if (enable)
|
if (enable)
|
||||||
@ -293,6 +318,47 @@ void game::Vehicle::ProcessInput()
|
|||||||
flags_ |= VF_BREAKING;
|
flags_ |= VF_BREAKING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void game::Vehicle::UpdateCrash()
|
||||||
|
{
|
||||||
|
if (window_health_ <= 0.0f)
|
||||||
|
flags_ |= VF_BROKENWINDOWS;
|
||||||
|
|
||||||
|
if (no_crash_frames_)
|
||||||
|
{
|
||||||
|
--no_crash_frames_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (crash_intensity_ > 1000.0f)
|
||||||
|
{
|
||||||
|
float volume = RandomFloat(0.9f, 1.2f);
|
||||||
|
float pitch = RandomFloat(1.0f, 1.3f);
|
||||||
|
|
||||||
|
if (crash_intensity_ > 12000.0f)
|
||||||
|
{
|
||||||
|
volume *= 1.7f;
|
||||||
|
pitch *= 0.8f;
|
||||||
|
}
|
||||||
|
if (crash_intensity_ > 4000.0f)
|
||||||
|
{
|
||||||
|
volume *= 1.3f;
|
||||||
|
pitch *= 0.8f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
volume *= 0.8f;
|
||||||
|
pitch *= 1.2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaySound("crash", volume, pitch);
|
||||||
|
no_crash_frames_ = 7 + rand() % 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
crash_intensity_ = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
void game::Vehicle::UpdateWheels()
|
void game::Vehicle::UpdateWheels()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < num_wheels_; ++i)
|
for (size_t i = 0; i < num_wheels_; ++i)
|
||||||
|
|||||||
@ -40,6 +40,8 @@ public:
|
|||||||
virtual void Update() override;
|
virtual void Update() override;
|
||||||
virtual void SendInitData(Player& player, net::OutMessage& msg) const override;
|
virtual void SendInitData(Player& player, net::OutMessage& msg) const override;
|
||||||
|
|
||||||
|
virtual void OnContact(float impulse) override;
|
||||||
|
|
||||||
void SetInput(VehicleInputType type, bool enable);
|
void SetInput(VehicleInputType type, bool enable);
|
||||||
void SetInputs(VehicleInputFlags inputs) { in_ = inputs; }
|
void SetInputs(VehicleInputFlags inputs) { in_ = inputs; }
|
||||||
|
|
||||||
@ -59,6 +61,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void ProcessInput();
|
void ProcessInput();
|
||||||
|
void UpdateCrash();
|
||||||
void UpdateWheels();
|
void UpdateWheels();
|
||||||
void UpdateSyncState();
|
void UpdateSyncState();
|
||||||
VehicleSyncFieldFlags WriteState(net::OutMessage& msg, const VehicleSyncState& base) const;
|
VehicleSyncFieldFlags WriteState(net::OutMessage& msg, const VehicleSyncState& base) const;
|
||||||
@ -86,6 +89,11 @@ private:
|
|||||||
size_t sync_current_ = 0;
|
size_t sync_current_ = 0;
|
||||||
|
|
||||||
VehicleInputFlags in_ = 0;
|
VehicleInputFlags in_ = 0;
|
||||||
|
|
||||||
|
float window_health_ = 10000.0f;
|
||||||
|
|
||||||
|
float crash_intensity_ = 0.0f;
|
||||||
|
size_t no_crash_frames_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
@ -14,8 +14,9 @@ using VehicleFlags = uint8_t;
|
|||||||
enum VehicleFlag : VehicleFlags
|
enum VehicleFlag : VehicleFlags
|
||||||
{
|
{
|
||||||
VF_NONE,
|
VF_NONE,
|
||||||
VF_ACCELERATING = 1,
|
VF_ACCELERATING = 0x01,
|
||||||
VF_BREAKING = 2,
|
VF_BREAKING = 0x02,
|
||||||
|
VF_BROKENWINDOWS = 0x04,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VehicleSyncState
|
struct VehicleSyncState
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include "assets/cache.hpp"
|
#include "assets/cache.hpp"
|
||||||
#include "utils/allocnum.hpp"
|
#include "utils/allocnum.hpp"
|
||||||
#include "collision/object_type.hpp"
|
#include "collision/object_info.hpp"
|
||||||
|
|
||||||
game::World::World(std::string mapname) : Scheduler(time_ms_), map_(*this, std::move(mapname))
|
game::World::World(std::string mapname) : Scheduler(time_ms_), map_(*this, std::move(mapname))
|
||||||
{
|
{
|
||||||
@ -49,7 +49,7 @@ void game::World::Update(int64_t delta_time)
|
|||||||
// GetBtWorld().stepSimulation(delta_s, 1, delta_s);
|
// GetBtWorld().stepSimulation(delta_s, 1, delta_s);
|
||||||
GetBtWorld().stepSimulation(delta_s, 2, delta_s * 0.5f);
|
GetBtWorld().stepSimulation(delta_s, 2, delta_s * 0.5f);
|
||||||
|
|
||||||
DetectDestructibleCollisions();
|
HandleContacts();
|
||||||
|
|
||||||
RunTasks();
|
RunTasks();
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ void game::World::RespawnObj(net::ObjNum objnum)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void game::World::DetectDestructibleCollisions()
|
void game::World::HandleContacts()
|
||||||
{
|
{
|
||||||
auto& bt_world = GetBtWorld();
|
auto& bt_world = GetBtWorld();
|
||||||
int numManifolds = bt_world.getDispatcher()->getNumManifolds();
|
int numManifolds = bt_world.getDispatcher()->getNumManifolds();
|
||||||
@ -104,41 +104,48 @@ void game::World::DetectDestructibleCollisions()
|
|||||||
static std::vector<net::ObjNum> to_destroy;
|
static std::vector<net::ObjNum> to_destroy;
|
||||||
to_destroy.clear();
|
to_destroy.clear();
|
||||||
|
|
||||||
|
auto ProcessContact = [&](btRigidBody* body, btRigidBody* other_body, btManifoldPoint& pt) {
|
||||||
|
collision::ObjectType type;
|
||||||
|
collision::ObjectFlags flags;
|
||||||
|
collision::ObjectCallback* cb;
|
||||||
|
collision::GetObjectInfo(body, type, flags, cb);
|
||||||
|
|
||||||
|
if (cb && (flags & collision::OF_NOTIFY_CONTACT))
|
||||||
|
{
|
||||||
|
cb->OnContact(pt.getAppliedImpulse());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == collision::OT_MAP_OBJECT && (flags & collision::OF_DESTRUCTIBLE))
|
||||||
|
{
|
||||||
|
auto col = dynamic_cast<MapObjectCollision*>(cb);
|
||||||
|
if (!col)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const float break_threshold = 100.0f; // TODO: per-object threshold
|
||||||
|
|
||||||
|
if (pt.getAppliedImpulse() > break_threshold)
|
||||||
|
{
|
||||||
|
to_destroy.push_back(col->GetNum());
|
||||||
|
other_body->applyCentralImpulse(pt.m_normalWorldOnB * pt.getAppliedImpulse() * 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// std::cout << "Checking " << numManifolds << " manifolds for destructible collisions..." << std::endl;
|
// std::cout << "Checking " << numManifolds << " manifolds for destructible collisions..." << std::endl;
|
||||||
for (int i = 0; i < numManifolds; i++)
|
for (int i = 0; i < numManifolds; i++)
|
||||||
{
|
{
|
||||||
btPersistentManifold* contactManifold = bt_world.getDispatcher()->getManifoldByIndexInternal(i);
|
btPersistentManifold* contactManifold = bt_world.getDispatcher()->getManifoldByIndexInternal(i);
|
||||||
|
|
||||||
const btRigidBody* bodyA = static_cast<const btRigidBody*>(contactManifold->getBody0());
|
btRigidBody* body0 = const_cast<btRigidBody*>(static_cast<const btRigidBody*>(contactManifold->getBody0()));
|
||||||
const btRigidBody* bodyB = static_cast<const btRigidBody*>(contactManifold->getBody1());
|
btRigidBody* body1 = const_cast<btRigidBody*>(static_cast<const btRigidBody*>(contactManifold->getBody1()));
|
||||||
|
|
||||||
const btRigidBody* destructibleBody = nullptr;
|
|
||||||
|
|
||||||
if (bodyA->getUserIndex() == collision::OT_MAP_DESTRUCTIBLE)
|
|
||||||
destructibleBody = bodyA;
|
|
||||||
else if (bodyB->getUserIndex() == collision::OT_MAP_DESTRUCTIBLE)
|
|
||||||
destructibleBody = bodyB;
|
|
||||||
|
|
||||||
if (!destructibleBody)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (int j = 0; j < contactManifold->getNumContacts(); j++)
|
for (int j = 0; j < contactManifold->getNumContacts(); j++)
|
||||||
{
|
{
|
||||||
const float break_threshold = 100.0f; // TODO: per-object threshold
|
|
||||||
|
|
||||||
btManifoldPoint& pt = contactManifold->getContactPoint(j);
|
btManifoldPoint& pt = contactManifold->getContactPoint(j);
|
||||||
|
ProcessContact(body0, body1, pt);
|
||||||
if (pt.getAppliedImpulse() > break_threshold)
|
ProcessContact(body1, body0, pt);
|
||||||
{
|
|
||||||
std::cout << "Destructible collision detected: impulse = " << pt.getAppliedImpulse() << std::endl;
|
|
||||||
|
|
||||||
MapObjectCollision* obj_col = static_cast<MapObjectCollision*>(destructibleBody->getUserPointer());
|
|
||||||
to_destroy.push_back(obj_col->GetNum());
|
|
||||||
|
|
||||||
const btRigidBody* otherBody = (destructibleBody == bodyA) ? bodyB : bodyA;
|
|
||||||
btRigidBody* otherBodyNonConst = const_cast<btRigidBody*>(otherBody);
|
|
||||||
otherBodyNonConst->applyCentralImpulse(pt.m_normalWorldOnB * pt.getAppliedImpulse() * 0.5f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -56,7 +56,7 @@ public:
|
|||||||
virtual ~World() = default;
|
virtual ~World() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DetectDestructibleCollisions();
|
void HandleContacts();
|
||||||
|
|
||||||
void DestroyObject(net::ObjNum objnum);
|
void DestroyObject(net::ObjNum objnum);
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,8 @@ bool game::view::EntityView::ProcessMsg(net::EntMsgType type, net::InMessage& ms
|
|||||||
return ReadNametag(msg);
|
return ReadNametag(msg);
|
||||||
case net::EMSG_ATTACH:
|
case net::EMSG_ATTACH:
|
||||||
return ReadAttach(msg);
|
return ReadAttach(msg);
|
||||||
|
case net::EMSG_PLAYSOUND:
|
||||||
|
return ProcessPlaySoundMsg(msg);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -82,6 +84,21 @@ bool game::view::EntityView::ReadAttach(net::InMessage& msg)
|
|||||||
return msg.Read(parentnum_);
|
return msg.Read(parentnum_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool game::view::EntityView::ProcessPlaySoundMsg(net::InMessage& msg)
|
||||||
|
{
|
||||||
|
net::SoundName name;
|
||||||
|
float volume, pitch;
|
||||||
|
if (!msg.Read(name) || !msg.Read<net::SoundVolumeQ>(volume) || !msg.Read<net::SoundPitchQ>(pitch))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto sound = assets::CacheManager::GetSound("data/" + std::string(name) + ".snd");
|
||||||
|
auto snd = audioplayer_.PlaySound(sound, &root_.local.position);
|
||||||
|
snd->SetVolume(volume);
|
||||||
|
snd->SetPitch(pitch);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void game::view::EntityView::DrawNametag(const DrawArgs& args)
|
void game::view::EntityView::DrawNametag(const DrawArgs& args)
|
||||||
{
|
{
|
||||||
if (nametag_.empty())
|
if (nametag_.empty())
|
||||||
|
|||||||
@ -50,6 +50,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool ReadNametag(net::InMessage& msg);
|
bool ReadNametag(net::InMessage& msg);
|
||||||
bool ReadAttach(net::InMessage& msg);
|
bool ReadAttach(net::InMessage& msg);
|
||||||
|
bool ProcessPlaySoundMsg(net::InMessage& msg);
|
||||||
|
|
||||||
void DrawNametag(const DrawArgs& args);
|
void DrawNametag(const DrawArgs& args);
|
||||||
void DrawAxes(const DrawArgs& args);
|
void DrawAxes(const DrawArgs& args);
|
||||||
|
|||||||
@ -15,7 +15,7 @@ game::view::VehicleView::VehicleView(WorldView& world, net::InMessage& msg)
|
|||||||
throw EntityInitError();
|
throw EntityInitError();
|
||||||
|
|
||||||
model_ = assets::CacheManager::GetVehicleModel("data/" + std::string(modelname) + ".veh");
|
model_ = assets::CacheManager::GetVehicleModel("data/" + std::string(modelname) + ".veh");
|
||||||
|
mesh_ = *model_->GetModel()->GetMesh();
|
||||||
|
|
||||||
auto& modelwheels = model_->GetWheels();
|
auto& modelwheels = model_->GetWheels();
|
||||||
wheels_.resize(modelwheels.size());
|
wheels_.resize(modelwheels.size());
|
||||||
@ -102,17 +102,26 @@ void game::view::VehicleView::Update(const UpdateInfo& info)
|
|||||||
snd_accel_src_->Delete();
|
snd_accel_src_->Delete();
|
||||||
snd_accel_src_ = nullptr;
|
snd_accel_src_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update windows
|
||||||
|
if ((flags_ & VF_BROKENWINDOWS) && !windows_broken_)
|
||||||
|
{
|
||||||
|
windows_broken_ = true;
|
||||||
|
|
||||||
|
auto it = mesh_.surface_names.find("carwindows");
|
||||||
|
if (it != mesh_.surface_names.end())
|
||||||
|
{
|
||||||
|
size_t idx = it->second;
|
||||||
|
mesh_.surfaces[idx].texture = assets::CacheManager::GetTexture("data/carbrokenwindows.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void game::view::VehicleView::Draw(const DrawArgs& args)
|
void game::view::VehicleView::Draw(const DrawArgs& args)
|
||||||
{
|
{
|
||||||
Super::Draw(args);
|
Super::Draw(args);
|
||||||
|
|
||||||
// TOOD: chceck and fix
|
for (const auto& surface : mesh_.surfaces)
|
||||||
const auto& model = *model_->GetModel();
|
|
||||||
const auto& mesh = *model.GetMesh();
|
|
||||||
|
|
||||||
for (const auto& surface : mesh.surfaces)
|
|
||||||
{
|
{
|
||||||
gfx::DrawSurfaceCmd cmd;
|
gfx::DrawSurfaceCmd cmd;
|
||||||
cmd.surface = &surface;
|
cmd.surface = &surface;
|
||||||
|
|||||||
@ -36,6 +36,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<const assets::VehicleModel> model_;
|
std::shared_ptr<const assets::VehicleModel> model_;
|
||||||
|
assets::Mesh mesh_;
|
||||||
glm::vec4 color_;
|
glm::vec4 color_;
|
||||||
|
|
||||||
game::VehicleSyncState sync_;
|
game::VehicleSyncState sync_;
|
||||||
@ -48,6 +49,8 @@ private:
|
|||||||
|
|
||||||
std::shared_ptr<const audio::Sound> snd_accel_;
|
std::shared_ptr<const audio::Sound> snd_accel_;
|
||||||
audio::SoundSource* snd_accel_src_ = nullptr;
|
audio::SoundSource* snd_accel_src_ = nullptr;
|
||||||
|
|
||||||
|
bool windows_broken_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -27,6 +27,12 @@ game::view::WorldView::WorldView(ClientSession& session, net::InMessage& msg) :
|
|||||||
|
|
||||||
map_.EnableObj(objnum, false);
|
map_.EnableObj(objnum, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cache common snds and stuff
|
||||||
|
Cache(assets::CacheManager::GetSound("data/breaksign.snd"));
|
||||||
|
Cache(assets::CacheManager::GetSound("data/breakpatnik.snd"));
|
||||||
|
Cache(assets::CacheManager::GetSound("data/crash.snd"));
|
||||||
|
Cache(assets::CacheManager::GetSound("data/breakwindow.snd"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool game::view::WorldView::ProcessMsg(net::MessageType type, net::InMessage& msg)
|
bool game::view::WorldView::ProcessMsg(net::MessageType type, net::InMessage& msg)
|
||||||
@ -185,3 +191,8 @@ bool game::view::WorldView::ProcessObjDestroyOrRespawnMsg(net::InMessage& msg, b
|
|||||||
map_.EnableObj(objnum, enable);
|
map_.EnableObj(objnum, enable);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void game::view::WorldView::Cache(std::any val)
|
||||||
|
{
|
||||||
|
cache_.emplace_back(std::move(val));
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <any>
|
||||||
|
|
||||||
#include "assets/map.hpp"
|
#include "assets/map.hpp"
|
||||||
#include "draw_args.hpp"
|
#include "draw_args.hpp"
|
||||||
#include "net/defs.hpp"
|
#include "net/defs.hpp"
|
||||||
@ -38,6 +40,8 @@ private:
|
|||||||
|
|
||||||
bool ProcessObjDestroyOrRespawnMsg(net::InMessage& msg, bool enable);
|
bool ProcessObjDestroyOrRespawnMsg(net::InMessage& msg, bool enable);
|
||||||
|
|
||||||
|
void Cache(std::any val);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ClientSession& session_;
|
ClientSession& session_;
|
||||||
|
|
||||||
@ -47,6 +51,8 @@ private:
|
|||||||
float time_ = 0.0f;
|
float time_ = 0.0f;
|
||||||
|
|
||||||
audio::Master& audiomaster_;
|
audio::Master& audiomaster_;
|
||||||
|
|
||||||
|
std::vector<std::any> cache_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace game::view
|
} // namespace game::view
|
||||||
@ -86,6 +86,7 @@ enum EntMsgType : uint8_t
|
|||||||
EMSG_NAMETAG,
|
EMSG_NAMETAG,
|
||||||
EMSG_ATTACH,
|
EMSG_ATTACH,
|
||||||
EMSG_UPDATE,
|
EMSG_UPDATE,
|
||||||
|
EMSG_PLAYSOUND,
|
||||||
};
|
};
|
||||||
|
|
||||||
using PositionElemQ = Quantized<uint32_t, -10000, 10000, 1>;
|
using PositionElemQ = Quantized<uint32_t, -10000, 10000, 1>;
|
||||||
@ -110,6 +111,10 @@ using ColorQ = Quantized<uint8_t, 0, 1>;
|
|||||||
|
|
||||||
using NameTag = FixedStr<64>;
|
using NameTag = FixedStr<64>;
|
||||||
|
|
||||||
|
using SoundName = FixedStr<64>;
|
||||||
|
using SoundVolumeQ = Quantized<uint8_t, 0, 2>;
|
||||||
|
using SoundPitchQ = Quantized<uint8_t, 0, 2>;
|
||||||
|
|
||||||
using AnimBlendQ = Quantized<uint8_t, 0, 1>;
|
using AnimBlendQ = Quantized<uint8_t, 0, 1>;
|
||||||
using AnimTimeQ = Quantized<uint8_t, 0, 1>;
|
using AnimTimeQ = Quantized<uint8_t, 0, 1>;
|
||||||
|
|
||||||
|
|||||||
8
src/utils/random.hpp
Normal file
8
src/utils/random.hpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
inline float RandomFloat(float min, float max)
|
||||||
|
{
|
||||||
|
return min + (max - min) * static_cast<float>(rand() % 100) * 0.01f;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user