18const float DynamicWorld::ghostHeight =140;
19const float DynamicWorld::worldHeight =20000;
22 HumShape(btScalar radius, btScalar height):btCapsuleShape(
27 void getAabb(
const btTransform& t, btVector3& aabbMin, btVector3& aabbMax)
const override {
28 const btScalar rad = getRadius();
29 btVector3 extent(rad,rad,rad);
30 extent[m_upAxis] = rad + getHalfHeight();
31 btVector3 center = t.getOrigin();
33 aabbMin = center - extent;
34 aabbMax = center + extent;
39 NpcBody(btCollisionShape* shape):btRigidBody(0,nullptr,shape){}
41 delete m_collisionShape;
51 return reinterpret_cast<Npc*
>(getUserPointer());
60 setWorldTransform(trans);
76 static const float dimMax = 45.f;
78 float dx = max.x-min.x;
79 float dz = max.z-min.z;
80 float dim = (dx+dz)*0.5f;
81 float height = max.y-min.y;
91 obj->setWorldTransform(trans);
93 obj->setCollisionFlags(btCollisionObject::CF_NO_CONTACT_RESPONSE);
117 bool del(
void* b,std::vector<Record>& arr){
118 for(
size_t i=0;i<arr.size();++i){
129 auto& fr = arr[b->
frozen];
130 const float x = fr.x;
133 fr.x = fr.body->pos.x;
146 n.
r = std::max((dx+dz)*0.5f, dz)*0.5f;
153 if(n.
frozen!=
size_t(-1)) {
167 bool rayTest(
NpcBody& npc,
const Tempest::Vec3& s,
const Tempest::Vec3& e,
float extR,
float& proj) {
171 auto at = npc.
pos - s;
173 float lenL = ln.length();
175 float dot = Tempest::Vec3::dotProduct(ln,at);
177 proj = dot/(lenL<=0 ? 1.f : (lenL*lenL));
178 proj = std::max(0.f,std::min(proj,1.f));
181 auto& tr = npc.getWorldTransform();
184 auto nr = ln*proj + s;
186 float R = 0.5f*(npc.
rX + npc.
rZ) + extR;
187 if(dp.x*dp.x+dp.z*dp.z > R*R)
194 NpcBody*
rayTest(
const Tempest::Vec3& s,
const Tempest::Vec3& e,
float extR,
const Npc* except) {
200 if(i.body->toNpc()!=except &&
rayTest(*i.body, s, e, extR, proj)) {
209 if(i.body!=
nullptr && i.body->toNpc()!=except &&
rayTest(*i.body, s, e, extR, proj)) {
220 static bool disable=
false;
242 auto l = arr.begin();
246 const float dX =
maxR+n.
r;
247 l = std::lower_bound(arr.begin(),arr.end(),n.
pos.x-dX,[](
const Record& b,
float x){ return b.x<x; });
248 r = std::upper_bound(arr.begin(),arr.end(),n.
pos.x+dX,[](
float x,
const Record& b){ return x<b.x; });
251 const auto dist = std::distance(l,r);
258 if(v.body!=
nullptr && v.body->enable &&
hasCollision(n,*v.body,normal)) {
259 npc = v.body->toNpc();
274 if(dy>b.
h || dy<-a.
h)
288 for(
size_t i=0; i<
frozen.size(); ++i)
293 for(
size_t i=0;i<
body.size();) {
306 for(
size_t i=0;i<
frozen.size();) {
312 frozen[i].body->frozen=size_t(-1);
339 body.push_front(std::move(b));
340 return &
body.front();
344 for(
auto i=
body.begin(), e=
body.end();i!=e;++i){
354 wrld.moveBullet(i,i.dir,dt);
363 if(i.cb!=
nullptr && list.
rayTest(npc,i.lastPos,i.
pos,i.tgRange,proj)) {
364 i.cb->onCollide(*npc.
toNpc());
378 body.emplace_back(b);
382 for(
auto i=
body.begin(), e=
body.end();i!=e;++i){
391 struct CallBack:btCollisionWorld::ClosestRayResultCallback {
392 using ClosestRayResultCallback::ClosestRayResultCallback;
394 CallBack callback{s,e};
396 btTransform rayFromTrans,rayToTrans;
397 rayFromTrans.setIdentity();
398 rayFromTrans.setOrigin(s);
399 rayToTrans.setIdentity();
400 rayToTrans.setOrigin(e);
408 const btTransform& e,
BBoxBody& npc,
409 btCollisionWorld::RayResultCallback& callback){
410 wrld.world->rayTestSingle(s, e, npc.obj,
412 npc.obj->getWorldTransform(),
414 return callback.hasHit();
427 for(
size_t i=0;i<sectors.size();++i)
428 sectors[i] = pkg.
subMeshes[i].material.name;
430 landVbo.resize(pkg.
vertices.size());
431 for(
size_t i=0;i<pkg.
vertices.size();++i) {
436 landMesh .reset(
new PhysicVbo(&landVbo));
437 waterMesh.reset(
new PhysicVbo(&landVbo));
439 for(
size_t i=0;i<pkg.
subMeshes.size();++i) {
441 if(!sm.material.disable_collision && sm.iboLength>0) {
442 if(sm.material.group==zenkit::MaterialGroup::WATER) {
443 waterMesh->addIndex(pkg.
indices,sm.iboOffset,sm.iboLength,sm.material.group);
445 landMesh ->addIndex(pkg.
indices,sm.iboOffset,sm.iboLength,sm.material.group,sectors[i].c_str());
451 btVector3 bbox[2] = {btVector3(0,0,0), btVector3(0,0,0)};
452 if(!landMesh->isEmpty()) {
453 Tempest::Matrix4x4 mt;
455 landShape.reset(
new btMultimaterialTriangleMeshShape(landMesh.get(),landMesh->useQuantization(),
true));
459 btVector3 b[2] = {btVector3(0,0,0), btVector3(0,0,0)};
460 landBody->getAabb(b[0],b[1]);
461 bbox[0].setMin(b[0]);
462 bbox[1].setMax(b[1]);
465 if(!waterMesh->isEmpty()) {
466 Tempest::Matrix4x4 mt;
468 waterShape.reset(
new btMultimaterialTriangleMeshShape(waterMesh.get(),waterMesh->useQuantization(),
true));
469 waterBody = world->addCollisionBody(*waterShape,mt,0);
470 waterBody->setUserIndex(
C_Water);
471 waterBody->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE);
474 btVector3 b[2] = {btVector3(0,0,0), btVector3(0,0,0)};
475 landBody->getAabb(b[0],b[1]);
476 bbox[0].setMin(b[0]);
477 bbox[1].setMax(b[1]);
480 world->setBBox(bbox[0],bbox[1]);
483 bboxList .reset(
new BBoxList (*
this));
485 world->setItemHitCallback([&](
::Item& itm, zenkit::MaterialGroup mat,
float impulse,
float mass) {
487 float v = impulse/mass;
488 float vol = snd.volume()*std::min(v/10.f,1.f);
498 world->updateAabbs();
501 return ray(Tempest::Vec3(from.x,from.y+
ghostPadding,from.z), Tempest::Vec3(from.x,from.y-maxDy,from.z));
505 world->updateAabbs();
506 return implWaterRay(from, Tempest::Vec3(from.x,from.y+worldHeight,from.z));
510 world->updateAabbs();
511 return implWaterRay(from, to);
515 struct CallBack:btCollisionWorld::ClosestRayResultCallback {
516 using ClosestRayResultCallback::ClosestRayResultCallback;
518 btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,
bool normalInWorldSpace)
override {
519 return ClosestRayResultCallback::addSingleResult(rayResult,normalInWorldSpace);
524 callback.m_flags = btTriangleRaycastCallback::kF_KeepUnflippedNormal | btTriangleRaycastCallback::kF_FilterBackfaces;
526 if(waterBody!=
nullptr) {
527 btTransform rayFromTrans,rayToTrans;
528 rayFromTrans.setIdentity();
529 rayFromTrans.setOrigin(callback.m_rayFromWorld);
530 rayToTrans.setIdentity();
531 rayToTrans.setOrigin(callback.m_rayToWorld);
532 world->rayTestSingle(rayFromTrans, rayToTrans,
534 waterBody->getCollisionShape(),
535 waterBody->getWorldTransform(),
540 if(callback.hasHit()) {
541 float waterY = callback.m_hitPointWorld.y()*100.f;
542 auto cave =
ray(from,Tempest::Vec3(to.x,waterY,to.z));
543 if(cave.hasCol && cave.v.y<waterY) {
544 ret.wdepth = from.y-worldHeight;
553 ret.wdepth = from.y-worldHeight;
559 struct CallBack:btCollisionWorld::AllHitsRayResultCallback {
560 using AllHitsRayResultCallback::AllHitsRayResultCallback;
562 btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,
bool normalInWorldSpace)
override {
564 return AllHitsRayResultCallback::addSingleResult(rayResult,normalInWorldSpace);
571 callback.m_flags = btTriangleRaycastCallback::kF_KeepUnflippedNormal | btTriangleRaycastCallback::kF_FilterBackfaces;
573 if(waterBody!=
nullptr) {
574 btTransform rayFromTrans,rayToTrans;
575 rayFromTrans.setIdentity();
576 rayFromTrans.setOrigin(callback.m_rayFromWorld);
577 rayToTrans.setIdentity();
578 rayToTrans.setOrigin(callback.m_rayToWorld);
579 world->rayTestSingle(rayFromTrans, rayToTrans,
581 waterBody->getCollisionShape(),
582 waterBody->getWorldTransform(),
587 ret.
waterCol = int(callback.m_collisionObjects.size());
592 struct CallBack:btCollisionWorld::ClosestRayResultCallback {
593 using ClosestRayResultCallback::ClosestRayResultCallback;
594 zenkit::MaterialGroup matId = zenkit::MaterialGroup::UNDEFINED;
595 const char* sector =
nullptr;
598 bool needsCollision(btBroadphaseProxy* proxy0)
const override {
599 auto obj=
reinterpret_cast<btCollisionObject*
>(proxy0->m_clientObject);
600 if(obj->getUserIndex()==C_Landscape || obj->getUserIndex()==C_Object)
601 return ClosestRayResultCallback::needsCollision(proxy0);
605 btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,
bool normalInWorldSpace)
override {
606 auto shape = rayResult.m_collisionObject->getCollisionShape();
608 auto s =
reinterpret_cast<const btMultimaterialTriangleMeshShape*
>(shape);
609 auto mt =
reinterpret_cast<const PhysicVbo*
>(s->getMeshInterface());
611 size_t id = size_t(rayResult.m_localShapeInfo->m_shapePart);
612 matId = mt->materialId(
id);
613 sector = mt->sectorName(
id);
615 colCat =
Category(rayResult.m_collisionObject->getUserIndex());
616 return ClosestRayResultCallback::addSingleResult(rayResult,normalInWorldSpace);
621 callback.m_flags = btTriangleRaycastCallback::kF_KeepUnflippedNormal | btTriangleRaycastCallback::kF_FilterBackfaces;
623 world->rayCast(from,to,callback);
625 Tempest::Vec3 hitPos = to, hitNorm;
626 if(callback.hasHit()){
629 hitNorm.x = callback.m_hitNormalWorld.x();
630 hitNorm.y = callback.m_hitNormalWorld.y();
631 hitNorm.z = callback.m_hitNormalWorld.z();
637 ret.
mat = callback.matId;
638 ret.
hasCol = callback.hasHit();
640 ret.
sector = callback.sector;
647 if(
auto ptr = npcList->rayTest(from, (r.
hasCol ? r.
v : to), 1, except)) {
655 struct CallBack:btCollisionWorld::AllHitsRayResultCallback {
656 using AllHitsRayResultCallback::AllHitsRayResultCallback;
658 enum { FRAC_MAX=16 };
660 float frac[FRAC_MAX] = {};
662 bool needsCollision(btBroadphaseProxy* proxy0)
const override {
663 auto obj=
reinterpret_cast<btCollisionObject*
>(proxy0->m_clientObject);
664 int id = obj->getUserIndex();
665 if(
id==C_Landscape ||
id==C_Water ||
id==C_Object)
666 return AllHitsRayResultCallback::needsCollision(proxy0);
670 btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,
bool normalInWorldSpace)
override {
672 frac[cnt] = rayResult.m_hitFraction;
674 return AllHitsRayResultCallback::addSingleResult(rayResult,normalInWorldSpace);
679 callback.m_flags = btTriangleRaycastCallback::kF_KeepUnflippedNormal;
681 world->rayCast(from,to,callback);
685 if(callback.cnt>=CallBack::FRAC_MAX)
689 std::sort(callback.frac,callback.frac+callback.cnt);
690 for(
size_t i=1;i<callback.cnt;i+=2) {
691 fr += (callback.frac[i]-callback.frac[i-1]);
694 float tlen = (callback.m_rayFromWorld-callback.m_rayToWorld).length();
696 return (tlen*fr)/1.5f;
700 Tempest::Vec3 min={0,0,0}, max={0,0,0};
702 min = sk->bboxCol[0];
703 max = sk->bboxCol[1];
705 auto obj = npcList->create(min,max);
706 float dim = std::max(obj->rX,obj->rZ);
707 return NpcItem(
this,obj,dim*0.5f);
713 return createObj(&shape->shape,
false,m,0,shape->
friction(),IT_Static);
719 return createObj(&shape->shape,
false,m,0,shape->
friction(),IT_Movable);
722DynamicWorld::Item DynamicWorld::createObj(btCollisionShape* shape,
bool ownShape,
const Tempest::Matrix4x4& m,
float mass,
float friction, ItemType type) {
723 std::unique_ptr<CollisionWorld::CollisionBody> obj;
727 obj = world->addCollisionBody(*shape,m,friction);
731 obj = world->addDynamicBody(*shape,m,friction,mass);
732 obj->setUserIndex(
C_Item);
735 return Item(
this,obj.release(),ownShape ? shape : nullptr);
743 float mass = density*(hExt[0])*(hExt[1])*(hExt[2]);
746 hExt[i] = std::max(hExt[i]*0.5f,0.15f);
748 std::unique_ptr<btCollisionShape> shape {
new btBoxShape(hExt) };
749 return createObj(shape.release(),
true,pos,mass,
materialFriction(mat),IT_Dynamic);
753 return bulletList->add(cb);
764void DynamicWorld::moveBullet(BulletBody &b,
const Tempest::Vec3& dir, uint64_t dt) {
765 const float dtF = float(dt);
766 const bool isSpell = b.isSpell();
769 auto to = pos + dir*dtF - Tempest::Vec3(0,(isSpell ? 0 :
gravity*dtF*dtF),0);
771 struct CallBack:btCollisionWorld::ClosestRayResultCallback {
772 using ClosestRayResultCallback::ClosestRayResultCallback;
773 zenkit::MaterialGroup matId = zenkit::MaterialGroup::NONE;
775 bool needsCollision(btBroadphaseProxy* proxy0)
const override {
776 auto obj=
reinterpret_cast<btCollisionObject*
>(proxy0->m_clientObject);
777 if(obj->getUserIndex()==C_Landscape || obj->getUserIndex()==C_Object)
778 return ClosestRayResultCallback::needsCollision(proxy0);
782 btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,
bool normalInWorldSpace)
override {
783 auto shape = rayResult.m_collisionObject->getCollisionShape();
785 auto s =
reinterpret_cast<const btMultimaterialTriangleMeshShape*
>(shape);
786 auto mt =
reinterpret_cast<const PhysicVbo*
>(s->getMeshInterface());
788 size_t id = size_t(rayResult.m_localShapeInfo->m_shapePart);
789 matId = mt->materialId(
id);
791 return ClosestRayResultCallback::addSingleResult(rayResult,normalInWorldSpace);
797 CallBack callback{s,e};
798 callback.m_flags = btTriangleRaycastCallback::kF_KeepUnflippedNormal | btTriangleRaycastCallback::kF_FilterBackfaces;
800 if(
auto ptr = bboxList->rayTest(s,e)) {
801 if(ptr->cb!=
nullptr) {
802 ptr->cb->onCollide(b);
806 world->rayCast(pos, to, callback);
808 bool stopBullet =
false;
809 if(callback.matId != zenkit::MaterialGroup::NONE) {
812 b.cb->onCollide(callback.matId);
815 if(callback.matId==zenkit::MaterialGroup::METAL ||
816 callback.matId==zenkit::MaterialGroup::STONE) {
818 btVector3 m = {d.x,d.y,d.z};
819 btVector3 n = callback.m_hitNormalWorld;
822 const float l = b.speed();
825 btVector3 dir = m - 2*m.dot(n)*n;
828 float a = callback.m_closestHitFraction;
829 b.move(pos + (to-pos)*a);
831 b.setDirection({dir.x(),dir.y(),dir.z()});
835 b.cb->onCollide(callback.matId);
838 float a = callback.m_closestHitFraction;
839 b.move(pos + (to-pos)*a);
840 b.addPathLen((to-pos).length()*a);
843 b.cb->onCollide(callback.matId);
848 if(
auto ptr = npcList->rayTest(pos,to,b.targetRange(),
nullptr)) {
850 stopBullet |= b.cb->onCollide(*ptr->toNpc());
else
853 const float l = b.speed();
854 auto d = b.direction();
862 if(stopBullet || b.hitCount()>3 || b.pathLength()>10000) {
869 npcList ->tickAabbs();
870 bulletList->tick(dt);
875 bulletList->del(obj);
881 case zenkit::MaterialGroup::UNDEFINED:
883 case zenkit::MaterialGroup::METAL:
885 case zenkit::MaterialGroup::STONE:
887 case zenkit::MaterialGroup::WOOD:
889 case zenkit::MaterialGroup::EARTH:
891 case zenkit::MaterialGroup::WATER:
893 case zenkit::MaterialGroup::SNOW:
895 case zenkit::MaterialGroup::NONE:
903 case zenkit::MaterialGroup::UNDEFINED:
904 case zenkit::MaterialGroup::NONE:
906 case zenkit::MaterialGroup::METAL:
908 case zenkit::MaterialGroup::STONE:
910 case zenkit::MaterialGroup::WOOD:
912 case zenkit::MaterialGroup::EARTH:
914 case zenkit::MaterialGroup::WATER:
916 case zenkit::MaterialGroup::SNOW:
923 return landMesh->validateSectorName(name);
926bool DynamicWorld::hasCollision(
const NpcItem& it, CollisionTest& out) {
927 if(npcList->hasCollision(it,out.normal,out.npc)){
928 out.normal /= out.normal.length();
932 return world->hasCollision(*it.obj,out.normal,out.vob);
938 owner->world->touchAabbs();
939 if(!owner->npcList->del(obj))
940 owner->world->removeCollisionObject(obj);
945 implSetPosition(pos);
946 owner->npcList->onMove(*obj);
947 owner->bulletList->onMoveNpc(*obj,*owner->npcList);
951void DynamicWorld::NpcItem::implSetPosition(
const Tempest::Vec3& pos) {
952 obj->setPosition(pos);
956 if(obj==
nullptr || obj->enable==e)
959 owner->world->touchAabbs();
963 obj->setUserPointer(p);
968 const btTransform& tr = obj->getWorldTransform();
969 return tr.getOrigin().y()*100.f;
982 return testMove(to,obj->pos,out);
988 auto prev = obj->pos;
989 auto code = implTryMove(to,pos0,out);
990 implSetPosition(prev);
996 static const float eps = 2;
1001 auto dp = to - obj->pos;
1002 if(std::abs(dp.x)<eps && std::abs(dp.y)<eps && std::abs(dp.z)<eps) {
1007 auto code = implTryMove(to,obj->pos,out);
1016 owner->npcList->onMove(*obj);
1017 owner->bulletList->onMoveNpc(*obj,*owner->npcList);
1024 auto initial = pos0;
1027 auto dp = to-initial;
1029 if((dp.x*dp.x+dp.z*dp.z)>r*r || dp.y>obj->h*0.5f) {
1030 const int countXZ = int(std::ceil(std::sqrt(dp.x*dp.x+dp.z*dp.z)/r));
1031 const int countY = int(std::ceil(std::abs(dp.y)/(obj->h*0.5f)));
1033 count = std::max(countXZ,countY);
1036 auto prev = initial;
1037 for(
int i=1; i<=count; ++i) {
1038 auto pos = initial+(dp*float(i))/
float(count);
1039 implSetPosition(pos);
1040 if(owner->hasCollision(*
this,out)) {
1046 implSetPosition(initial);
1047 if(owner->hasCollision(*
this,out)) {
1049 implSetPosition(to);
1063 return owner->hasCollision(*
this,info);
1074 trans.setFromOpenGLMatrix(
reinterpret_cast<const btScalar*
>(&m));
1075 trans.getOrigin()*=0.01f;
1076 if(obj->getWorldTransform()==trans)
1078 obj->setWorldTransform(trans);
1080 owner->world->updateSingleAabb(obj);
1086 obj->setUserPointer(it);
1087 obj->setUserIndex2(1);
1092 obj->setUserPointer(it);
1093 obj->setUserIndex2(2);
1097 :owner(wrld), cb(cb) {
1101 : pos(other.pos), lastPos(other.lastPos),
1102 dir(other.dir), dirL(other.dirL), totalL(other.totalL), spl(other.spl){
1103 std::swap(owner,other.owner);
1104 std::swap(cb,other.cb);
1139 const float dx = dir.x/dirL;
1140 const float dy = dir.y/dirL;
1141 const float dz = dir.z/dirL;
1143 float a2 = std::asin(dy)*float(180/M_PI);
1144 float ang = std::atan2(dz,dx)*float(180/M_PI)+180.f;
1146 Tempest::Matrix4x4 mat;
1148 mat.translate(pos.x,pos.y,pos.z);
1155 : owner(ow), cb(cb) {
1156 btVector3 hExt =
CollisionWorld::toMeters(Tempest::Vec3{bbox.max.x-bbox.min.x, bbox.max.y-bbox.min.y, bbox.max.z-bbox.min.z})*0.5f;
1157 btVector3 pos =
CollisionWorld::toMeters(Tempest::Vec3{bbox.max.x+bbox.min.x, bbox.max.y+bbox.min.y, bbox.max.z+bbox.min.z})*0.5f;
1159 shape =
new btBoxShape(hExt);
1160 obj =
new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(0,
nullptr,shape));
1163 trans.setIdentity();
1164 trans.setOrigin(pos);
1166 obj->setWorldTransform(trans);
1168 obj->setCollisionFlags(btCollisionObject::CF_NO_CONTACT_RESPONSE);
1170 owner->bboxList->add(
this);
1174 : owner(ow), cb(cb) {
1177 shape =
new btCapsuleShape(R,4.f);
1178 obj =
new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(0,
nullptr,shape));
1181 trans.setIdentity();
1182 trans.setOrigin(pos);
1184 obj->setWorldTransform(trans);
1186 obj->setCollisionFlags(btCollisionObject::CF_NO_CONTACT_RESPONSE);
1188 owner->bboxList->add(
this);
1192 :owner(other.owner),cb(other.cb),shape(other.shape),obj(other.obj) {
1193 other.owner =
nullptr;
1195 other.shape =
nullptr;
1196 other.obj =
nullptr;
1198 if(owner!=
nullptr) {
1199 owner->bboxList->del(&other);
1200 owner->bboxList->add(
this);
1205 if(other.owner!=
nullptr)
1206 other.owner->bboxList->del(&other);
1208 owner->bboxList->del(
this);
1210 std::swap(owner,other.owner);
1211 std::swap(cb, other.cb);
1212 std::swap(shape,other.shape);
1213 std::swap(obj, other.obj);
1215 if(other.owner!=
nullptr)
1216 other.owner->bboxList->add(&other);
1218 owner->bboxList->add(
this);
1226 owner->bboxList->del(
this);
static const Tempest::Vec3 toCentimeters(const btVector3 &v)
static float toMeters(const float v)
Item movableObj(const PhysicMeshShape *src, const Tempest::Matrix4x4 &m)
RayWaterResult waterRay(const Tempest::Vec3 &from) const
RayCamResult cameraRay(const Tempest::Vec3 &from, const Tempest::Vec3 &to) const
static const float ghostPadding
static constexpr float gravity
static float materialFriction(zenkit::MaterialGroup mat)
BBoxBody bboxObj(BBoxCallback *cb, const zenkit::AxisAlignedBoundingBox &bbox)
void deleteObj(BulletBody *obj)
float soundOclusion(const Tempest::Vec3 &from, const Tempest::Vec3 &to) const
RayLandResult landRay(const Tempest::Vec3 &from, float maxDy=0) const
Item dynamicObj(const Tempest::Matrix4x4 &pos, const Bounds &bbox, zenkit::MaterialGroup mat)
RayLandResult ray(const Tempest::Vec3 &from, const Tempest::Vec3 &to) const
std::string_view validateSectorName(std::string_view name) const
static float materialDensity(zenkit::MaterialGroup mat)
Item staticObj(const PhysicMeshShape *src, const Tempest::Matrix4x4 &m)
BulletBody * bulletObj(BulletCallback *cb)
DynamicWorld(World &world, const zenkit::Mesh &mesh)
NpcItem ghostObj(std::string_view visual)
RayQueryResult rayNpc(const Tempest::Vec3 &from, const Tempest::Vec3 &to, const Npc *except) const
const zenkit::IItem & handle() const
std::vector< SubMesh > subMeshes
std::vector< uint32_t > indices
std::vector< Vertex > vertices
static const Skeleton * loadSkeleton(std::string_view name)
auto transform() const -> const Tempest::Matrix4x4 &
Sound addLandHitEffect(ItemMaterial src, zenkit::MaterialGroup reciver, const Tempest::Matrix4x4 &pos)
BBoxBody & operator=(BBoxBody &&other)
BBoxList(DynamicWorld &wrld)
bool rayTestSingle(const btTransform &s, const btTransform &e, BBoxBody &npc, btCollisionWorld::RayResultCallback &callback)
BBoxBody * rayTest(const btVector3 &s, const btVector3 &e)
std::vector< BBoxBody * > body
void setPosition(const Tempest::Vec3 &pos)
BulletBody(DynamicWorld *wrld, BulletCallback *cb)
void setTargetRange(float tgRange)
void move(const Tempest::Vec3 &to)
Tempest::Matrix4x4 matrix() const
void setDirection(const Tempest::Vec3 &dir)
void onMoveNpc(NpcBody &npc, NpcBodyList &list)
BulletsList(DynamicWorld &wrld)
BulletBody * add(BulletCallback *cb)
std::list< BulletBody > body
HumShape(btScalar radius, btScalar height)
void getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const override
void setInteractive(Interactive *it)
void setObjMatrix(const Tempest::Matrix4x4 &m)
NpcBody * create(const Tempest::Vec3 &min, const Tempest::Vec3 &max)
void resize(NpcBody &n, float h, float dx, float dz)
std::vector< Record > frozen
bool delMisordered(NpcBody *b, std::vector< Record > &arr)
std::vector< Record > body
NpcBodyList(DynamicWorld &wrld)
NpcBody * rayTest(const Tempest::Vec3 &s, const Tempest::Vec3 &e, float extR, const Npc *except)
bool rayTest(NpcBody &npc, const Tempest::Vec3 &s, const Tempest::Vec3 &e, float extR, float &proj)
bool hasCollision(const NpcBody &a, const NpcBody &b, Tempest::Vec3 &normal)
bool del(void *b, std::vector< Record > &arr)
bool hasCollision(const NpcBody &n, const std::vector< Record > &arr, Tempest::Vec3 &normal, Npc *&npc, bool sorted)
bool hasCollision(const DynamicWorld::NpcItem &obj, Tempest::Vec3 &normal, Npc *&npc)
void setPosition(const Tempest::Vec3 &p)
NpcBody(btCollisionShape *shape)
bool testMove(const Tempest::Vec3 &to, CollisionTest &out)
void setPosition(const Tempest::Vec3 &pos)
bool hasCollision() const
void setUserPointer(void *p)
const Tempest::Vec3 & position() const
auto tryMove(const Tempest::Vec3 &to, CollisionTest &out) -> DynamicWorld::MoveCode
zenkit::MaterialGroup mat