add FindSafePoint

This commit is contained in:
aozhiwei 2019-04-19 21:02:37 +08:00
parent 05624058fd
commit c53d69926b
9 changed files with 254 additions and 35 deletions

View File

@ -95,3 +95,91 @@ bool ColliderComponent::Intersect(ColliderComponent* b)
} }
return false; return false;
} }
bool ColliderComponent::CalcSafePoint(ColliderComponent* b, Vector2D& 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*)this;
return CalcAabbAabbSafePoint(a_aabb->owner->pos + a_aabb->_min,
a_aabb->owner->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 CalcAabbAabbSafePoint(a_aabb->owner->pos + a_aabb->_min,
a_aabb->owner->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 CalcCircleAabbSafePoint(
a_circle->owner->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 CalcCircleCircleSafePoint(
a_circle->owner->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) {
case CT_Aabb:
{
delete (AabbCollider*)collider;
}
break;
case CT_Circle:
{
delete (CircleCollider*)collider;
}
break;
default:
{
delete collider;
}
break;
}
}

View File

@ -17,6 +17,7 @@ class ColliderComponent
bool Intersect(ColliderComponent* b); bool Intersect(ColliderComponent* b);
bool IntersectSegment(Vector2D& p0, Vector2D& p1); bool IntersectSegment(Vector2D& p0, Vector2D& p1);
bool CalcSafePoint(ColliderComponent* b, Vector2D& new_pos);
}; };
class AabbCollider : public ColliderComponent class AabbCollider : public ColliderComponent
@ -36,3 +37,5 @@ public:
CircleCollider() { type = CT_Circle; }; CircleCollider() { type = CT_Circle; };
}; };
void DestoryCollider(ColliderComponent* collider);

View File

@ -115,36 +115,69 @@ bool CircleContainCircle(Vector2D a_pos, float a_rad, Vector2D b_pos, float b_ra
return distance < a_rad - b_rad; return distance < a_rad - b_rad;
} }
bool CalcCircleAabbSafePoint(Vector2D a_min, Vector2D a_max, Vector2D b_pos, float b_rad, bool CalcCircleAabbSafePoint(Vector2D a_pos, float b_rad, Vector2D b_min, Vector2D b_max,
Vector2D& new_pos) Vector2D& new_pos)
{ {
new_pos = b_pos; new_pos = a_pos;
bool at_left = std::abs(b_pos.x - a_min.x) < std::abs(b_pos.x - a_max.x); bool at_left = std::abs(a_pos.x - b_min.x) < std::abs(a_pos.x - b_max.x);
bool at_down = std::abs(b_pos.y - a_min.y) < std::abs(b_pos.y - a_max.y); bool at_down = std::abs(a_pos.y - b_min.y) < std::abs(a_pos.y - b_max.y);
float x_len = at_left ? std::abs(b_pos.x - a_min.x) : std::abs(b_pos.x - a_max.x); float x_len = at_left ? std::abs(a_pos.x - b_min.x) : std::abs(a_pos.x - b_max.x);
float y_len = at_down ? std::abs(b_pos.y - a_min.y) : std::abs(b_pos.y - a_max.y); float y_len = at_down ? std::abs(a_pos.y - b_min.y) : std::abs(a_pos.y - b_max.y);
if (at_left) { if (at_left) {
if (x_len < y_len) { if (x_len < y_len) {
//左 //左
new_pos.x = a_min.x - b_rad - 1; new_pos.x = b_min.x - b_rad - 1;
} else { } else {
if (at_down) { if (at_down) {
new_pos.y = a_min.y - b_rad - 1; new_pos.y = b_min.y - b_rad - 1;
} else { } else {
new_pos.y = a_max.y + b_rad + 1; new_pos.y = b_max.y + b_rad + 1;
} }
} }
} else { } else {
if (x_len < y_len) { if (x_len < y_len) {
//右 //右
new_pos.x = a_max.x + b_rad + 1; new_pos.x = b_max.x + b_rad + 1;
} else { } else {
if (at_down) { if (at_down) {
new_pos.y = a_min.y - b_rad - 1; new_pos.y = b_min.y - b_rad - 1;
} else { } else {
new_pos.y = a_max.y + b_rad + 1; new_pos.y = b_max.y + b_rad + 1;
} }
} }
} }
return true; return true;
} }
bool CalcCircleCircleSafePoint(Vector2D a_pos, float a_rad, Vector2D b_pos, float b_rad,
Vector2D& new_pos)
{
Vector2D dir = a_pos - b_pos;
dir.Normalize();
new_pos = b_pos + dir*(a_rad + b_rad) + 1;
return true;
}
bool CalcAabbAabbSafePoint(Vector2D a_min, Vector2D a_max, Vector2D b_min, Vector2D b_max,
Vector2D& new_pos)
{
Vector2D a_pos = a_min + (a_max - a_min)/2.0f;
float a_rad = (a_max - a_min).Norm();
Vector2D b_pos = b_min + (b_max - b_min)/2.0f;
float b_rad = (b_max - b_min).Norm();
Vector2D dir = (a_pos - b_pos);
dir.Normalize();
new_pos = b_pos + dir*(a_rad + b_rad) + 1;
return true;
}
bool CalcAabbCircleSafePoint(Vector2D a_min, Vector2D a_max, Vector2D b_pos, float b_rad,
Vector2D& new_pos)
{
Vector2D a_pos = a_min + (a_max - a_min)/2.0f;
float a_rad = (a_max - a_min).Norm();
Vector2D dir = a_pos - b_pos;
dir.Normalize();
new_pos = b_pos + dir*(a_rad + b_rad) + 1;
return true;
}

View File

@ -6,6 +6,12 @@ bool IntersectAabbCircle(Vector2D a_min, Vector2D a_max, Vector2D b_pos, float b
bool IntersectAabbAabb(Vector2D a_min, Vector2D a_max, Vector2D b_min, Vector2D b_max); bool IntersectAabbAabb(Vector2D a_min, Vector2D a_max, Vector2D b_min, Vector2D b_max);
bool IntersectCircleCircle(Vector2D a_pos, float a_rad, Vector2D b_pos, float b_rad); bool IntersectCircleCircle(Vector2D a_pos, float a_rad, Vector2D b_pos, float b_rad);
bool CircleContainCircle(Vector2D a_pos, float a_rad, Vector2D b_pos, float b_rad); bool CircleContainCircle(Vector2D a_pos, float a_rad, Vector2D b_pos, float b_rad);
bool CalcCircleAabbSafePoint(Vector2D a_min, Vector2D a_max, Vector2D b_pos, float b_rad, bool CalcCircleAabbSafePoint(Vector2D a_pos, float a_rad, Vector2D b_min, Vector2D b_max,
Vector2D& new_pos);
bool CalcCircleCircleSafePoint(Vector2D a_pos, float a_rad, Vector2D b_pos, float b_rad,
Vector2D& new_pos);
bool CalcAabbAabbSafePoint(Vector2D a_min, Vector2D a_max, Vector2D b_min, Vector2D b_max,
Vector2D& new_pos);
bool CalcAabbCircleSafePoint(Vector2D a_min, Vector2D a_max, Vector2D b_pos, float b_rad,
Vector2D& new_pos); Vector2D& new_pos);
void TestGlm(); void TestGlm();

View File

@ -3,6 +3,7 @@
#include "entity.h" #include "entity.h"
#include "collider.h" #include "collider.h"
#include "room.h" #include "room.h"
#include "building.h"
Entity::Entity() Entity::Entity()
{ {
@ -19,6 +20,14 @@ void Entity::Initialize()
xtimer_attacher.xtimer = &room->xtimer; xtimer_attacher.xtimer = &room->xtimer;
} }
ColliderComponent* Entity::GetBoxBound()
{
CircleCollider* collider = new CircleCollider();
collider->active = true;
collider->owner = this;
return collider;
}
bool Entity::TestCollision(Entity* b) bool Entity::TestCollision(Entity* b)
{ {
for (auto& a_collider : colliders) { for (auto& a_collider : colliders) {
@ -35,23 +44,64 @@ void Entity::ClearColliders()
{ {
for (auto& itr : colliders) { for (auto& itr : colliders) {
ColliderComponent* collider = itr; ColliderComponent* collider = itr;
switch (collider->type) { DestoryCollider(collider);
case CT_Aabb:
{
delete (AabbCollider*)collider;
}
break;
case CT_Circle:
{
delete (CircleCollider*)collider;
}
break;
default:
{
delete collider;
}
break;
}
} }
colliders.clear(); colliders.clear();
} }
void Entity::FindLocationWithTarget(Entity* target)
{
ColliderComponent* a_collider = GetBoxBound();
Vector2D old_pos = pos;
Vector2D new_pos = pos;
#if 0
{
std::vector<Entity*> objects;
room->BuildingBoxBoundCollisionDetection(this, objects);
if (objects.size() > 1) {
abort();
}
if (!objects.empty()) {
Building* building = (Building*)objects[0];
ColliderComponent* building_collider = building->GetBoxBound();
bool ret = a_collider->CalcSafePoint(building_collider, new_pos);
if (!ret) {
abort();
}
if (ret) {
pos = new_pos;
DestoryCollider(a_collider);
DestoryCollider(building_collider);
return;
} else {
DestoryCollider(building_collider);
}
}
}
#endif
ColliderComponent* target_collider = target->GetBoxBound();
{
bool ret = a_collider->CalcSafePoint(target_collider, new_pos);
if (!ret) {
abort();
}
}
Vector2D new_pos_dir = new_pos - old_pos;
float distance = (new_pos - old_pos).Norm();
new_pos_dir.Normalize();
for (float i = distance; i < 10000000; i += 5.0f) {
pos = old_pos + new_pos_dir * i;
std::vector<Entity*> objects;
int detection_flags = 0;
{
a8::SetBitFlag(detection_flags, ET_Obstacle);
}
room->CollisionDetection(this, detection_flags, objects);
if (objects.empty()) {
break;
}
}
DestoryCollider(target_collider);
DestoryCollider(a_collider);
}

View File

@ -57,6 +57,9 @@ class Entity
virtual void FillMFObjectPart(cs::MFObjectPart* part_data) {}; virtual void FillMFObjectPart(cs::MFObjectPart* part_data) {};
virtual void FillMFObjectFull(cs::MFObjectFull* full_data) {}; virtual void FillMFObjectFull(cs::MFObjectFull* full_data) {};
virtual float GetSpeed() { return 1.0f;}; virtual float GetSpeed() { return 1.0f;};
virtual ColliderComponent* GetBoxBound();
bool TestCollision(Entity* b); bool TestCollision(Entity* b);
void ClearColliders(); void ClearColliders();
void FindLocationWithTarget(Entity* target);
}; };

View File

@ -323,7 +323,6 @@ ColliderComponent* Human::GetFirstCollision()
void Human::FindPath() void Human::FindPath()
{ {
ColliderComponent* first_collider = nullptr;
Vector2D old_pos = pos; Vector2D old_pos = pos;
{ {
float up_dot = Vector2D::UP.Dot(move_dir); float up_dot = Vector2D::UP.Dot(move_dir);
@ -649,20 +648,20 @@ void Human::FindLocation()
} }
if (!objects.empty()) { if (!objects.empty()) {
Building* building = (Building*)objects[0]; Building* building = (Building*)objects[0];
Vector2D a_min = Vector2D( Vector2D b_min = Vector2D(
building->pos.x - building->meta->i->tilewidth()/2.0, building->pos.x - building->meta->i->tilewidth()/2.0,
building->pos.y - building->meta->i->tileheight()/2.0 building->pos.y - building->meta->i->tileheight()/2.0
); );
Vector2D a_max = Vector2D( Vector2D b_max = Vector2D(
building->pos.x + building->meta->i->tilewidth()/2.0, building->pos.x + building->meta->i->tilewidth()/2.0,
building->pos.y + building->meta->i->tileheight()/2.0 building->pos.y + building->meta->i->tileheight()/2.0
); );
Vector2D new_pos; Vector2D new_pos;
bool ret = CalcCircleAabbSafePoint( bool ret = CalcCircleAabbSafePoint(
a_min,
a_max,
pos, pos,
GetRadius(), GetRadius(),
b_min,
b_max,
new_pos new_pos
); );
if (!ret) { if (!ret) {
@ -670,7 +669,27 @@ void Human::FindLocation()
} }
if (ret) { if (ret) {
pos = new_pos; pos = new_pos;
return;
} }
} }
} }
{
std::vector<Entity*> objects;
int detection_flags = 0;
{
a8::SetBitFlag(detection_flags, ET_Obstacle);
a8::SetBitFlag(detection_flags, ET_Player);
}
room->CollisionDetection(this, detection_flags, objects);
if (objects.empty()) {
return;
}
std::sort(objects.begin(), objects.end(),
[this] (Entity* a, Entity *b) -> bool
{
return (this->pos - a->pos).Norm() < (this->pos - b->pos).Norm();
});
Entity* target = objects[0];
FindLocationWithTarget(target);
}
} }

View File

@ -762,6 +762,21 @@ void Room::TouchHumanList(a8::XParams param,
} }
} }
void Room::TouchEntityList(a8::XParams param,
std::function<bool (Entity*, a8::XParams&)> func)
{
if (!func) {
return;
}
for (auto& pair : uniid_hash_) {
if (pair.second) {
if (!func(pair.second, param)) {
break;
}
}
}
}
void Room::ProcAddedObjects() void Room::ProcAddedObjects()
{ {
if (!be_added_hash_.empty()) { if (!be_added_hash_.empty()) {

View File

@ -65,6 +65,8 @@ public:
std::function<void (Player*, a8::XParams&)> func); std::function<void (Player*, a8::XParams&)> func);
void TouchHumanList(a8::XParams param, void TouchHumanList(a8::XParams param,
std::function<bool (Human*, a8::XParams&)> func); std::function<bool (Human*, a8::XParams&)> func);
void TouchEntityList(a8::XParams param,
std::function<bool (Entity*, a8::XParams&)> func);
void ScatterDrop(Vector2D center, int drop_id); void ScatterDrop(Vector2D center, int drop_id);
void DropItem(Vector2D pos, int item_id, int item_count); void DropItem(Vector2D pos, int item_id, int item_count);