diff --git a/server/gameserver/collider.cc b/server/gameserver/collider.cc index 0542074..0b3c0fc 100644 --- a/server/gameserver/collider.cc +++ b/server/gameserver/collider.cc @@ -97,6 +97,71 @@ bool ColliderComponent::Intersect(ColliderComponent* b) return false; } +bool ColliderComponent::IntersectEx(const a8::Vec2& pos, ColliderComponent* b) +{ + switch (type) { + case CT_None: + break; + case CT_Aabb: + { + AabbCollider* a_aabb = (AabbCollider*)this; + switch (b->type) { + case CT_None: + break; + case CT_Aabb: + { + AabbCollider* b_aabb = (AabbCollider*)b; + return a8::IntersectAabbAabb(a_aabb->owner->pos + a_aabb->_min, + a_aabb->owner->pos + a_aabb->_max, + pos + b_aabb->_min, + pos + b_aabb->_max + ); + } + break; + case CT_Circle: + { + CircleCollider* b_circle = (CircleCollider*)b; + return a8::IntersectAabbCircle(a_aabb->owner->pos + a_aabb->_min, + a_aabb->owner->pos + a_aabb->_max, + pos + b_circle->pos, + b_circle->rad); + } + break; + } + }; + break; + case CT_Circle: + { + CircleCollider* a_circle = (CircleCollider*)this; + switch (b->type) { + case CT_None: + break; + case CT_Aabb: + { + AabbCollider* b_aabb = (AabbCollider*)b; + return a8::IntersectAabbCircle(pos + b_aabb->_min, + pos + b_aabb->_max, + a_circle->owner->pos + a_circle->pos, + a_circle->rad); + } + break; + case CT_Circle: + { + CircleCollider* b_circle = (CircleCollider*)b; + return a8::IntersectCircleCircle( + a_circle->owner->pos + a_circle->pos, + a_circle->rad, + pos + b_circle->pos, + b_circle->rad); + } + break; + } + } + break; + } + return false; +} + bool ColliderComponent::CalcSafePoint(ColliderComponent* b, a8::Vec2& new_pos) { switch (type) { @@ -164,6 +229,73 @@ bool ColliderComponent::CalcSafePoint(ColliderComponent* b, a8::Vec2& new_pos) return false; } +bool ColliderComponent::CalcSafePointEx(const a8::Vec2& a_pos, ColliderComponent* b, a8::Vec2& new_pos) +{ + switch (type) { + case CT_None: + break; + case CT_Aabb: + { + AabbCollider* a_aabb = (AabbCollider*)this; + switch (b->type) { + case CT_Aabb: + { + AabbCollider* b_aabb = (AabbCollider*)b; + return a8::CalcAabbAabbSafePoint(a_pos + a_aabb->_min, + a_pos + a_aabb->_max, + b_aabb->owner->pos + b_aabb->_min, + b_aabb->owner->pos + b_aabb->_max, + new_pos); + } + break; + case CT_Circle: + { + CircleCollider* b_circle = (CircleCollider*)b; + return a8::CalcAabbAabbSafePoint(a_pos + a_aabb->_min, + a_pos + a_aabb->_max, + b_circle->owner->pos + b_circle->pos, + b_circle->rad, + new_pos); + } + break; + } + } + break; + case CT_Circle: + { + CircleCollider* a_circle = (CircleCollider*)this; + switch (b->type) { + case CT_Aabb: + { + AabbCollider* b_aabb = (AabbCollider*)b; + return a8::CalcCircleAabbSafePoint( + a_pos + a_circle->pos, + a_circle->rad, + b_aabb->owner->pos + b_aabb->_min, + b_aabb->owner->pos + b_aabb->_max, + new_pos); + } + break; + case CT_Circle: + { + CircleCollider* b_circle = (CircleCollider*)b; + return a8::CalcCircleCircleSafePoint( + a_pos + a_circle->pos, + a_circle->rad, + b_circle->owner->pos + b_circle->pos, + b_circle->rad, + new_pos); + } + break; + } + } + break; + default: + break; + } + return false; +} + void DestoryCollider(ColliderComponent* collider) { switch (collider->type) { diff --git a/server/gameserver/collider.h b/server/gameserver/collider.h index 148a2f8..ceb0e81 100644 --- a/server/gameserver/collider.h +++ b/server/gameserver/collider.h @@ -16,8 +16,10 @@ class ColliderComponent bool active = true; bool Intersect(ColliderComponent* b); + bool IntersectEx(const a8::Vec2& pos, ColliderComponent* b); bool IntersectSegment(a8::Vec2& p0, a8::Vec2& p1); bool CalcSafePoint(ColliderComponent* b, a8::Vec2& new_pos); + bool CalcSafePointEx(const a8::Vec2& a_pos, ColliderComponent* b, a8::Vec2& new_pos); }; class AabbCollider : public ColliderComponent diff --git a/server/gameserver/entity.cc b/server/gameserver/entity.cc index 9791e85..0aa949c 100644 --- a/server/gameserver/entity.cc +++ b/server/gameserver/entity.cc @@ -61,6 +61,16 @@ bool Entity::TestCollision(ColliderComponent* b) return false; } +bool Entity::TestCollisionEx(const a8::Vec2& aabb_pos, AabbCollider& aabb_box) +{ + for (auto& a_collider : colliders) { + if (a_collider->IntersectEx(aabb_pos, &aabb_box)) { + return true; + } + } + return false; +} + void Entity::ClearColliders() { for (auto& itr : colliders) { diff --git a/server/gameserver/entity.h b/server/gameserver/entity.h index 0636104..de4da75 100644 --- a/server/gameserver/entity.h +++ b/server/gameserver/entity.h @@ -43,6 +43,7 @@ class Entity virtual void GetCircleBox(CircleCollider& circle_box); bool TestCollision(Entity* b); bool TestCollision(ColliderComponent* b); + bool TestCollisionEx(const a8::Vec2& aabb_pos, AabbCollider& aabb_box); void FindLocationWithTarget(Entity* target); void BroadcastFullState(); void BroadcastDeleteState(); diff --git a/server/gameserver/room.cc b/server/gameserver/room.cc index 599ac35..2af7893 100644 --- a/server/gameserver/room.cc +++ b/server/gameserver/room.cc @@ -333,17 +333,6 @@ void Room::FillSMJoinedNotify(Player* self_hum, cs::SMJoinedNotify& msg) msg.set_player_id(self_hum->entity_uniid); msg.set_started(false); msg.set_room_uuid(a8::XValue(room_uuid).GetString()); - #if 0 - for (auto& pair : uniid_hash_) { - if (pair.second->entity_type == ET_Player) { - Human* hum = (Human*)pair.second; - cs::MFPlayerInfo* info = msg.add_player_infos(); - info->set_player_id(hum->entity_uniid); - info->set_team_id(hum->team_id); - info->set_name(hum->name); - } - } - #endif } void Room::ScatterDrop(a8::Vec2 center, int drop_id) @@ -735,6 +724,99 @@ void Room::OnPlayerOffline(Player* hum) } } +Entity* Room::FindFirstCollisonEntity(const a8::Vec2& aabb_pos, AabbCollider& aabb_box) +{ + Entity* target = nullptr; + std::set grid_list; + grid_service.GetAllCellsByXy(aabb_pos.x, aabb_pos.y, grid_list); + for (auto& grid : grid_list) { + for (Entity* entity : grid->entity_list) { + switch (entity->entity_type) { + case ET_Obstacle: + { + if (!target) { + if (entity->TestCollisionEx(aabb_pos, aabb_box)) { + target = entity; + } + } + } + break; + case ET_Building: + { + if (!target || target->entity_type != ET_Building) { + AabbCollider building_aabb_box; + entity->GetAabbBox(building_aabb_box); + if (building_aabb_box.IntersectEx(aabb_pos, &aabb_box)) { + target = entity; + } + } + } + break; + } + } + } + return target; +} + +void Room::FindLocationWithAabb(Entity* target, const a8::Vec2& aabb_pos, AabbCollider* aabb_box, + float& new_x, float& new_y) +{ + a8::Vec2 old_pos = aabb_pos; + a8::Vec2 new_pos = aabb_pos; + AabbCollider target_collider; + target->GetAabbBox(target_collider); + { + bool ret = aabb_box->CalcSafePointEx(aabb_pos, &target_collider, new_pos); + if (!ret) { + abort(); + } + } + a8::Vec2 new_pos_dir = new_pos - old_pos; + new_pos_dir.Normalize(); + float distance = (new_pos - old_pos).Norm(); + for (int i = distance; i < 10000000; i += 5) { + a8::Vec2 pos = old_pos + new_pos_dir * i; + + Entity* building = nullptr; + std::set new_grid_list; + grid_service.GetAllCellsByXy(pos.x, pos.y, new_grid_list); + for (auto& grid : new_grid_list) { + for (Entity* entity : grid->entity_list) { + switch (entity->entity_type) { + case ET_Building: + { + if (entity->TestCollisionEx(pos, *aabb_box)) { + building = entity; + } + } + break; + } + if (building) { + break; + } + } + if (building) { + break; + } + } + + if (!building) { + bool is_collision = false; + std::set colliders; + map_service.GetColliders(pos.x, pos.y, colliders); + for (ColliderComponent* collider : colliders) { + if (collider->IntersectEx(pos, &target_collider)) { + is_collision = true; + break; + } + } + if (!is_collision) { + break; + } + } + } +} + std::set* Room::GetAliveTeam() { for (auto& pair : team_hash_) { @@ -1116,7 +1198,6 @@ void Room::AirDrop(int appear_time, int box_id) a8::Vec2 dir = a8::Vec2::UP; dir.Rotate(a8::RandAngle()); a8::Vec2 box_pos = gas_data.pos_new + dir * (500 + rand() % 300); - #if 1 if (box_pos.x < 1.0f) { box_pos.x = 1.0f; } @@ -1129,7 +1210,21 @@ void Room::AirDrop(int appear_time, int box_id) if (box_pos.y >= MAP_HEIGHT) { box_pos.y = MAP_HEIGHT - 1; } - #endif + AabbCollider air_drop_aabb_box; + { + air_drop_aabb_box._min.x = box_pos.x - thing_meta->i->width()/2.0f; + air_drop_aabb_box._min.y = box_pos.y - thing_meta->i->height()/2.0f; + air_drop_aabb_box._max.x = box_pos.x + thing_meta->i->width()/2.0f; + air_drop_aabb_box._max.y = box_pos.y + thing_meta->i->height()/2.0f; + } + Entity* target = FindFirstCollisonEntity(box_pos, air_drop_aabb_box); + if (target) { + float new_x = box_pos.x; + float new_y = box_pos.y; + FindLocationWithAabb(target, box_pos, &air_drop_aabb_box, new_x, new_y); + box_pos.x = new_x; + box_pos.y = new_y; + } frame_event.AddAirDrop(appear_time, box_id, box_pos); xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE * appear_time / 1000.f, a8::XParams() diff --git a/server/gameserver/room.h b/server/gameserver/room.h index dd83210..80fe864 100644 --- a/server/gameserver/room.h +++ b/server/gameserver/room.h @@ -30,6 +30,7 @@ class Human; class Player; class Building; class Hero; +class AabbCollider; class Room { public: @@ -93,6 +94,9 @@ public: std::set* GetAliveTeam(); bool CanJoin(const std::string& accountid); void OnPlayerOffline(Player* hum); + Entity* FindFirstCollisonEntity(const a8::Vec2& aabb_pos, AabbCollider& aabb_box); + void FindLocationWithAabb(Entity* target, const a8::Vec2& aabb_pos, AabbCollider* aabb_box, + float& new_x, float& new_y); private: int AllocUniid();