287 lines
8.7 KiB
C++
287 lines
8.7 KiB
C++
#include "precompile.h"
|
|
|
|
#include <math.h>
|
|
#include <memory.h>
|
|
|
|
#include "mapservice.h"
|
|
#include "collider.h"
|
|
#include "entity.h"
|
|
#include "roomobstacle.h"
|
|
|
|
MapService::MapService()
|
|
{
|
|
|
|
}
|
|
|
|
MapService::~MapService()
|
|
{
|
|
for (auto pair : node_hash_) {
|
|
CellNode* node = pair.second;
|
|
while (node) {
|
|
CellNode* pdelnode = node;
|
|
node = node->next;
|
|
|
|
list_del_init(&pdelnode->entry);
|
|
delete pdelnode;
|
|
}
|
|
}
|
|
node_hash_.clear();
|
|
|
|
if (map_cells_) {
|
|
free(map_cells_);
|
|
map_cells_ = nullptr;
|
|
}
|
|
}
|
|
|
|
void MapService::Init(int width, int height, int cell_width)
|
|
{
|
|
if (width < 1 || height < 1 || cell_width < 1) {
|
|
abort();
|
|
}
|
|
map_width_ = width;
|
|
map_height_ = height;
|
|
cell_width_ = cell_width;
|
|
max_grid_id_ = map_width_ * map_height_;
|
|
|
|
grid_offset_arr_[0] = - (map_width_ + 1);
|
|
grid_offset_arr_[1] = - (map_width_ + 0);
|
|
grid_offset_arr_[2] = - (map_width_ + -1);
|
|
|
|
grid_offset_arr_[3] = - 1;
|
|
grid_offset_arr_[4] = 0;
|
|
grid_offset_arr_[5] = 1;
|
|
|
|
grid_offset_arr_[6] = map_width_ - 1;
|
|
grid_offset_arr_[7] = map_width_;
|
|
grid_offset_arr_[8] = map_width_ + 1;
|
|
|
|
map_cells_ = (list_head*)malloc(sizeof(list_head) * width * height);
|
|
memset(map_cells_, 0, sizeof(list_head) * width * height);
|
|
for (int i = 0; i < max_grid_id_; ++i) {
|
|
INIT_LIST_HEAD(&map_cells_[i]);
|
|
}
|
|
}
|
|
|
|
void MapService::UnInit()
|
|
{
|
|
|
|
}
|
|
|
|
void MapService::AddCollider(ColliderComponent* collider)
|
|
{
|
|
if (!(collider->owner->IsEntityType(ET_Obstacle) ||
|
|
collider->owner->IsEntityType(ET_Building))) {
|
|
abort();
|
|
}
|
|
CellNode* top_node = nullptr;
|
|
CellNode* bot_node = nullptr;
|
|
switch (collider->type) {
|
|
case CT_Aabb:
|
|
case CT_Circle:
|
|
{
|
|
AabbCollider aabb;
|
|
if (collider->type == CT_Aabb) {
|
|
aabb = *((AabbCollider*)collider);
|
|
} else if (collider->type == CT_Circle) {
|
|
CircleCollider* circle_box = (CircleCollider*)collider;
|
|
aabb.owner = circle_box->owner;
|
|
aabb._min.x = 0 - circle_box->rad;
|
|
aabb._min.y = 0 - circle_box->rad;
|
|
aabb._max.x = 0 + circle_box->rad;
|
|
aabb._max.y = 0 + circle_box->rad;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
float min_x = (collider->owner->GetPos() + aabb._min).x - 2;
|
|
float min_y = (collider->owner->GetPos() + aabb._min).y - 2;
|
|
float max_x = (collider->owner->GetPos() + aabb._max).x + 2;
|
|
float max_y = (collider->owner->GetPos() + aabb._max).y + 2;
|
|
#if 1
|
|
int min_grid_x = floor(min_x / cell_width_);
|
|
int min_grid_y = floor(min_y / cell_width_);
|
|
int max_grid_x = ceil(max_x / cell_width_);
|
|
int max_grid_y = ceil(max_y / cell_width_);
|
|
#else
|
|
int min_grid_x = ceil(min_x / cell_width_) - 1;
|
|
int min_grid_y = ceil(min_y / cell_width_) - 1;
|
|
int max_grid_x = ceil(max_x / cell_width_) - 1;
|
|
int max_grid_y = ceil(max_y / cell_width_) - 1;
|
|
#endif
|
|
if (min_grid_x == -1) {
|
|
min_grid_x = 0;
|
|
}
|
|
if (min_grid_x < 0) {
|
|
abort();
|
|
}
|
|
if (max_grid_x >= map_width_) {
|
|
max_grid_x = map_width_ - 1;
|
|
}
|
|
if (min_grid_y == -1) {
|
|
min_grid_y = 0;
|
|
}
|
|
if (min_grid_y < 0) {
|
|
abort();
|
|
}
|
|
if (max_grid_y >= map_height_) {
|
|
max_grid_y = map_height_ - 1;
|
|
}
|
|
for (int x = min_grid_x; x <= max_grid_x; ++x) {
|
|
for (int y = min_grid_y; y <= max_grid_y; ++y) {
|
|
int grid_id = x + y * map_width_;
|
|
list_head* head = &map_cells_[grid_id];
|
|
CellNode* node = new CellNode();
|
|
node->collider = collider;
|
|
list_add_tail(&node->entry, head);
|
|
node->next = top_node;
|
|
top_node = node;
|
|
if (!bot_node) {
|
|
bot_node = node;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (top_node) {
|
|
auto pair = node_hash_.find(collider);
|
|
if (pair != node_hash_.end()) {
|
|
bot_node->next = pair->second;
|
|
pair->second = top_node;
|
|
} else {
|
|
node_hash_[collider] = top_node;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MapService::RemoveCollider(ColliderComponent* collider)
|
|
{
|
|
auto pair = node_hash_.find(collider);
|
|
if (pair != node_hash_.end()) {
|
|
CellNode* node = pair->second;
|
|
while (node) {
|
|
CellNode* pdelnode = node;
|
|
node = node->next;
|
|
|
|
list_del_init(&pdelnode->entry);
|
|
delete pdelnode;
|
|
}
|
|
node_hash_.erase(pair);
|
|
}
|
|
}
|
|
|
|
void MapService::GetColliders(Room* room,
|
|
float world_x,
|
|
float world_y,
|
|
std::set<ColliderComponent*>& colliders)
|
|
{
|
|
int center_grid_id = GetGridId(world_x, world_y);
|
|
if (center_grid_id < 0 || center_grid_id >= max_grid_id_) {
|
|
return;
|
|
}
|
|
for (int i = 0; i < a8::ArraySize(grid_offset_arr_); ++i) {
|
|
int grid_id = center_grid_id + grid_offset_arr_[i];
|
|
if (grid_id >= 0 && grid_id < max_grid_id_) {
|
|
list_head* head = &map_cells_[grid_id];
|
|
if (list_empty(head)) {
|
|
continue;
|
|
}
|
|
struct CellNode *node, *tmp;
|
|
list_for_each_entry_safe(node, tmp, head, entry) {
|
|
if (node->collider->tag != 0 && !a8::HasBitFlag(node->collider->tag, kHalfWallTag)) {
|
|
continue;
|
|
}
|
|
switch (node->collider->owner->GetEntityType()) {
|
|
case ET_Obstacle:
|
|
{
|
|
switch (node->collider->owner->GetEntitySubType()) {
|
|
case EST_PermanentObstacle:
|
|
{
|
|
colliders.insert(node->collider);
|
|
}
|
|
break;
|
|
case EST_RoomObstacle:
|
|
{
|
|
RoomObstacle* obstacle = (RoomObstacle*)node->collider->owner;
|
|
if (obstacle->room == room) {
|
|
colliders.insert(node->collider);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
abort();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case ET_Building:
|
|
{
|
|
colliders.insert(node->collider);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
abort();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MapService::GetSpecColliders(long long flags,
|
|
Room* room,
|
|
float world_x,
|
|
float world_y,
|
|
std::set<ColliderComponent*>& colliders)
|
|
{
|
|
int center_grid_id = GetGridId(world_x, world_y);
|
|
if (center_grid_id < 0 || center_grid_id >= max_grid_id_) {
|
|
return;
|
|
}
|
|
for (int i = 0; i < a8::ArraySize(grid_offset_arr_); ++i) {
|
|
int grid_id = center_grid_id + grid_offset_arr_[i];
|
|
if (grid_id >= 0 && grid_id < max_grid_id_) {
|
|
list_head* head = &map_cells_[grid_id];
|
|
if (list_empty(head)) {
|
|
continue;
|
|
}
|
|
struct CellNode *node, *tmp;
|
|
list_for_each_entry_safe(node, tmp, head, entry) {
|
|
if ((flags & (long long)node->collider->tag) != 0) {
|
|
colliders.insert(node->collider);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int MapService::GetGridId(float world_x, float world_y)
|
|
{
|
|
int grid_id = (int)(world_x/cell_width_) + (int)(world_y/cell_width_) * map_width_;
|
|
return grid_id;
|
|
}
|
|
|
|
int MapService::FindPathRequest(Human* hum,
|
|
const a8::Vec2& start_pos,
|
|
const a8::Vec2& end_pos,
|
|
int max_step_num)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
FindPathStatus* MapService::QueryFindPathStatus(int query_id)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
void MapService::RemoveFindPathRequest(Human* hum, int query_id)
|
|
{
|
|
|
|
}
|