#include "precompile.h" #include "gridservice.h" #include "human.h" #include "bullet.h" #include "room.h" #include "gridcell.h" /* 1 2 3 4 5 6 7 8 9 */ GridService::GridService() { } GridService::~GridService() { } void GridService::Init(int width, int height, int cell_width) { map_width_ = width; map_height_ = height; cell_width_ = cell_width; cell_count_per_row_ = (map_height_ / cell_width + 1) + 2; cell_count_per_col_ = (map_width_ / cell_width + 1) + 2; max_grid_id_ = cell_count_per_row_ * cell_count_per_col_; cells_ = new GridCell[max_grid_id_ + 1]; grid_offset_arr_[0] = -(cell_count_per_row_ - 1); grid_offset_arr_[1] = -cell_count_per_row_; grid_offset_arr_[2] = -(cell_count_per_row_ + 1); grid_offset_arr_[3] = -1; grid_offset_arr_[4] = 0; grid_offset_arr_[5] = 1; grid_offset_arr_[6] = cell_count_per_row_ - 1; grid_offset_arr_[7] = cell_count_per_row_; grid_offset_arr_[8] = cell_count_per_row_ + 1; min_x_ = cell_width_ * 1; min_y_ = cell_width_ * 1; max_x_ = cell_width_ * (cell_count_per_row_ - 1); max_y_ = cell_width_ * (cell_count_per_col_ - 1); } void GridService::UnInit() { if (cells_) { delete[] cells_; cells_ = nullptr; } } bool GridService::BroderOverFlow(int x, int y) { return x <= min_x_ || x >= max_x_ || y <= min_y_ || y >= max_y_; } void GridService::GetAllCells(Room* room, int grid_id, std::set& grid_list) { for (size_t i = 1; i <= 9; ++i) { GetGridList(grid_id, i, grid_list); } } void GridService::GetAllCellsByXy(Room* room, int x, int y, std::set& grid_list) { int new_x = x + cell_width_; int new_y = y + cell_width_; int new_grid_id = new_x/cell_width_ + (new_y/cell_width_) * cell_count_per_row_; if (BroderOverFlow(new_x, new_y)) { abort(); } GetAllCells(room, new_grid_id, grid_list); } bool GridService::CanAdd(float x, float y) { int new_x = (int)x + cell_width_; int new_y = (int)x + cell_width_; return !BroderOverFlow(new_x, new_y); } void GridService::ClearRoomData(Room* room) { if (room->GetRoomIdx() <= 0) { abort(); } for (int i = 0; i < (max_grid_id_ + 1); ++i) { GridCell& cell = cells_[i]; cell.ClearRoomData(room); } } void GridService::AddCreature(Creature* c) { int x = (int)c->GetX() + cell_width_; int y = (int)c->GetY() + cell_width_; if (BroderOverFlow(x, y)) { abort(); } c->SetGridId(x/cell_width_ + (y/cell_width_) * cell_count_per_row_); if (c->GetGridId() == 0 || c->GetGridId() > max_grid_id_) { abort(); } cells_[c->GetGridId()].AddCreature(c); GetAllCells(c->room, c->GetGridId(), c->GetGridList()); } void GridService::RemoveCreature(Creature* c) { GridCell& cell = cells_[c->GetGridId()]; cell.RemoveCreature(c); } void GridService::MoveCreature(Creature* c) { int new_x = (int)c->GetX() + cell_width_; int new_y = (int)c->GetY() + cell_width_; int new_grid_id = new_x/cell_width_ + (new_y/cell_width_) * cell_count_per_row_; if (BroderOverFlow(new_x, new_y)) { abort(); } if (new_grid_id == 0 || new_grid_id > max_grid_id_) { abort(); } if (new_grid_id != c->GetGridId()) { std::set inc_grid_list; std::set dec_grid_list; std::set old_grid_list = c->GetGridList(); ComputeDiff(c->room, c->GetGridId(), new_grid_id, c->GetGridList(), inc_grid_list, dec_grid_list); cells_[c->GetGridId()].RemoveCreature(c); cells_[new_grid_id].AddCreature(c); c->SetGridId(new_grid_id); c->OnGridListChange(old_grid_list, inc_grid_list, dec_grid_list); } } void GridService::AddBullet(Bullet* bullet) { int x = (int)bullet->GetX() + cell_width_; int y = (int)bullet->GetY() + cell_width_; if (BroderOverFlow(x, y)) { abort(); } bullet->SetGridId(x/cell_width_ + (y/cell_width_) * cell_count_per_row_); if (bullet->GetGridId() == 0 || bullet->GetGridId() > max_grid_id_) { abort(); } cells_[bullet->GetGridId()].AddBullet(bullet); GetAllCells(bullet->room, bullet->GetGridId(), bullet->GetGridList()); } void GridService::MoveBullet(Bullet* bullet) { int new_x = (int)bullet->GetX() + cell_width_; int new_y = (int)bullet->GetY() + cell_width_; int new_grid_id = new_x/cell_width_ + (new_y/cell_width_) * cell_count_per_row_; if (BroderOverFlow(new_x, new_y)) { abort(); } if (new_grid_id == 0 || new_grid_id > max_grid_id_) { abort(); } if (new_grid_id != bullet->GetGridId()) { std::set inc_grid_list; std::set dec_grid_list; std::set old_grid_list = bullet->GetGridList(); ComputeDiff(bullet->room, bullet->GetGridId(), new_grid_id, bullet->GetGridList(), inc_grid_list, dec_grid_list); cells_[bullet->GetGridId()].RemoveBullet(bullet); cells_[new_grid_id].AddBullet(bullet); bullet->SetGridId(new_grid_id); } } void GridService::DelBullet(Bullet* bullet) { GridCell& cell = cells_[bullet->GetGridId()]; cell.RemoveBullet(bullet); } void GridService::AddRoomEntity(Room* room, Entity* entity) { assert(!entity->IsEntityType(ET_Player)); int x = (int)entity->GetX() + cell_width_; int y = (int)entity->GetY() + cell_width_; if (BroderOverFlow(x, y)) { abort(); } entity->SetGridId(x/cell_width_ + (y/cell_width_) * cell_count_per_row_); if (entity->GetGridId() == 0 || entity->GetGridId() > max_grid_id_) { abort(); } cells_[entity->GetGridId()].AddRoomEntity(room, entity); } void GridService::DelRoomEntity(Room* room, Entity* entity) { GridCell& cell = cells_[entity->GetGridId()]; cell.RemoveRoomEntity(room, entity); } void GridService::AddPermanentEntity(Entity* entity) { assert(!entity->IsEntityType(ET_Player)); int x = (int)entity->GetX() + cell_width_; int y = (int)entity->GetY() + cell_width_; if (BroderOverFlow(x, y)) { abort(); } entity->SetGridId(x/cell_width_ + (y/cell_width_) * cell_count_per_row_); if (entity->GetGridId() == 0 || entity->GetGridId() > max_grid_id_) { abort(); } cells_[entity->GetGridId()].AddPermanentEntity(entity); } bool GridService::CreatureInGridList(Creature* c, std::set& grid_list) { for (auto& cell : grid_list) { if (cell->CreatureExists(c)) { return true; } } return false; } bool GridService::EntityInGridList(Room* room, Entity* entity, std::set& grid_list) { for (auto& cell : grid_list) { if (cell->EntityExists(room, entity)) { return true; } } return false; } bool GridService::InView(int a_grid, int b_grid) { return a_grid + grid_offset_arr_[0] == b_grid || a_grid + grid_offset_arr_[1] == b_grid || a_grid + grid_offset_arr_[2] == b_grid || a_grid + grid_offset_arr_[3] == b_grid || a_grid + grid_offset_arr_[4] == b_grid || a_grid + grid_offset_arr_[5] == b_grid || a_grid + grid_offset_arr_[6] == b_grid || a_grid + grid_offset_arr_[7] == b_grid || a_grid + grid_offset_arr_[8] == b_grid; } bool GridService::InView(int grid_id, float x, float y) { int b_grid_id = x/cell_width_ + (y/cell_width_) * cell_count_per_row_; bool in_view = InView(grid_id, b_grid_id); #ifdef DEBUG if (in_view) { a8::UdpLog::Instance()->Debug("InView %d %d %f %f", { grid_id, b_grid_id, x, y }); } #endif return in_view; } void GridService::GetGridList(int grid_id, int offset, std::set& grid_list) { if (offset <1 || offset > 9) { abort(); } if (grid_id <= 0 || grid_id >= max_grid_id_) { return; } int tmp_grid_id = grid_id + grid_offset_arr_[offset - 1]; if (tmp_grid_id > 0) { grid_list.insert(&cells_[tmp_grid_id]); } } void GridService::ComputeDiff(Room* room, int old_grid_id, int new_grid_id, std::set& grid_list, std::set& inc_grid_list, std::set& dec_grid_list) { #if 1 { std::set new_grid_list; GetAllCells(room, new_grid_id, new_grid_list); for (auto& cell : new_grid_list) { if (grid_list.find(cell) == grid_list.end()) { inc_grid_list.insert(cell); } } for (auto& cell : grid_list) { if (new_grid_list.find(cell) == new_grid_list.end()) { dec_grid_list.insert(cell); } } } #endif grid_list.clear(); GetAllCells(room, new_grid_id, grid_list); } void GridService::TraverseLayer0EntityList(std::set& grid_list, std::function func) { bool stop = false; for (auto& cell : grid_list) { cell->TraverseLayer0EntityList(func, stop); if (stop) { return; } } } void GridService::TraverseLayer1EntityList(int room_idx, std::set& grid_list, std::function func) { bool stop = false; for (auto& cell : grid_list) { cell->TraverseLayer1EntityList(func, room_idx, stop); if (stop) { return; } } } void GridService::TraverseAllLayerEntityList(int room_idx, std::set& grid_list, std::function func) { bool stop = false; for (auto& cell : grid_list) { cell->TraverseAllLayerEntityList(func, room_idx, stop); if (stop) { return; } } } void GridService::TraverseAllLayerHumanList(int room_idx, std::set& grid_list, std::function func) { bool stop = false; for (auto& cell : grid_list) { cell->TraverseHumanList(func, room_idx, stop); if (stop) { return; } } } void GridService::TraverseCreatures(int room_idx, std::set& grid_list, std::function func) { bool stop = false; for (auto& cell : grid_list) { cell->TraverseCreatures(func, room_idx, stop); if (stop) { return; } } } void GridService::DeatchHuman(Human* target) { for (auto& cell : target->GetGridList()) { bool stop = false; cell->TraverseHumanList ( [target] (Human* hum, bool& stop) { hum->AddOutObjects(target); }, target->room->GetRoomIdx(), stop); cell->RemoveCreature(target); } target->SetGridId(0); target->GetGridList().clear(); }