139 lines
4.1 KiB
C++
139 lines
4.1 KiB
C++
#include "mapinstance.hpp"
|
|
|
|
#include <stdexcept>
|
|
|
|
#include "assets/cache.hpp"
|
|
|
|
game::MapInstance::MapInstance(collision::DynamicsWorld& world, std::string mapname)
|
|
: world_(world), mapname_(std::move(mapname))
|
|
{
|
|
map_ = assets::CacheManager::GetMap("data/" + mapname_ + ".map");
|
|
|
|
// add basemodel col
|
|
const auto& basemodel = map_->GetBaseModel();
|
|
if (basemodel)
|
|
{
|
|
Transform identity;
|
|
basemodel_col_ = std::make_unique<MapObjectCollision>(world_, basemodel, 0, identity, 0);
|
|
}
|
|
|
|
// add static objects
|
|
const auto& objs = map_->GetStaticObjects();
|
|
obj_cols_.resize(objs.size());
|
|
for (size_t i = 0; i < objs.size(); ++i)
|
|
{
|
|
SpawnObj(static_cast<net::ObjNum>(i));
|
|
}
|
|
}
|
|
|
|
void game::MapInstance::SpawnObj(net::ObjNum objnum)
|
|
{
|
|
if (objnum >= obj_cols_.size())
|
|
throw std::runtime_error("Invalid object number");
|
|
|
|
size_t i = static_cast<size_t>(objnum);
|
|
|
|
if (obj_cols_[i])
|
|
return; // already spawned
|
|
|
|
const auto& objs = map_->GetStaticObjects();
|
|
obj_cols_[i] = std::make_unique<MapObjectCollision>(world_, objs[i].model, static_cast<net::ObjNum>(i), objs[i].node.local, MAPOBJ_DESTRUCTIBLE);
|
|
}
|
|
|
|
std::unique_ptr<game::MapObjectCollision> game::MapInstance::DestroyObj(net::ObjNum objnum)
|
|
{
|
|
size_t i = static_cast<size_t>(objnum);
|
|
if (i >= obj_cols_.size())
|
|
throw std::runtime_error("Invalid object number");
|
|
|
|
auto obj = std::move(obj_cols_[i]);
|
|
|
|
if (obj)
|
|
{
|
|
obj->Break();
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
game::MapObjectCollision::MapObjectCollision(collision::DynamicsWorld& world,
|
|
std::shared_ptr<const assets::Model> model, net::ObjNum num,
|
|
const Transform& trans, MapObjectCollisionFlags flags)
|
|
: world_(world), model_(std::move(model)), num_(num)
|
|
{
|
|
auto cshape = model_->GetColShape();
|
|
auto cmesh = model_->GetColMesh();
|
|
|
|
const bool destructible = (flags & MAPOBJ_DESTRUCTIBLE) != 0 && cshape != nullptr;
|
|
|
|
btVector3 local_inertia(0, 0, 0);
|
|
float mass = 0.0f;
|
|
collision::ObjectFlags oflags = 0;
|
|
|
|
if (destructible)
|
|
{
|
|
oflags |= collision::OF_DESTRUCTIBLE;
|
|
model_->GetParamFloat("destr_th", destr_th_);
|
|
}
|
|
|
|
// prefer simple cshape which allow destruction
|
|
if (cshape)
|
|
{
|
|
body_ = std::make_unique<btRigidBody>(
|
|
btRigidBody::btRigidBodyConstructionInfo(mass, nullptr, cshape, local_inertia));
|
|
}
|
|
else if (cmesh)
|
|
{
|
|
body_ = std::make_unique<btRigidBody>(
|
|
btRigidBody::btRigidBodyConstructionInfo(mass, nullptr, cmesh->GetShape(), local_inertia));
|
|
}
|
|
|
|
auto offset_trans = trans;
|
|
offset_trans.position += trans.rotation * model_->GetColOffset();
|
|
|
|
body_->setWorldTransform(offset_trans.ToBtTransform());
|
|
|
|
collision::SetObjectInfo(body_.get(), collision::OT_MAP_OBJECT, oflags, this);
|
|
|
|
// world_.GetBtWorld().addRigidBody(body_.get(), btBroadphaseProxy::StaticFilter, btBroadphaseProxy::AllFilter);
|
|
world_.GetBtWorld().addRigidBody(body_.get());
|
|
}
|
|
|
|
void game::MapObjectCollision::Break()
|
|
{
|
|
if (!body_)
|
|
return;
|
|
|
|
btCollisionShape* shape = body_->getCollisionShape();
|
|
float mass = 10.0f;
|
|
model_->GetParamFloat("destr_mass", mass); // dont care if not present
|
|
btVector3 local_inertia(0, 0, 0);
|
|
shape->calculateLocalInertia(mass, local_inertia);
|
|
|
|
btTransform trans = body_->getWorldTransform();
|
|
|
|
// remove old
|
|
world_.GetBtWorld().removeRigidBody(body_.get());
|
|
body_.reset();
|
|
|
|
// make new
|
|
body_ = std::make_unique<btRigidBody>(btRigidBody::btRigidBodyConstructionInfo(mass, nullptr, shape, local_inertia));
|
|
body_->setWorldTransform(trans);
|
|
|
|
collision::SetObjectInfo(body_.get(), collision::OT_UNDEFINED, 0, this);
|
|
|
|
world_.GetBtWorld().addRigidBody(body_.get());
|
|
}
|
|
|
|
void game::MapObjectCollision::GetModelTransform(Transform& trans) const
|
|
{
|
|
trans.SetBtTransform(body_->getWorldTransform());
|
|
trans.position -= trans.rotation * model_->GetColOffset(); // unapply offset
|
|
}
|
|
|
|
game::MapObjectCollision::~MapObjectCollision()
|
|
{
|
|
if (body_)
|
|
world_.GetBtWorld().removeRigidBody(body_.get());
|
|
}
|