add FindSafePoint
This commit is contained in:
parent
05624058fd
commit
c53d69926b
@ -95,3 +95,91 @@ bool ColliderComponent::Intersect(ColliderComponent* b)
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ class ColliderComponent
|
||||
|
||||
bool Intersect(ColliderComponent* b);
|
||||
bool IntersectSegment(Vector2D& p0, Vector2D& p1);
|
||||
bool CalcSafePoint(ColliderComponent* b, Vector2D& new_pos);
|
||||
};
|
||||
|
||||
class AabbCollider : public ColliderComponent
|
||||
@ -36,3 +37,5 @@ public:
|
||||
|
||||
CircleCollider() { type = CT_Circle; };
|
||||
};
|
||||
|
||||
void DestoryCollider(ColliderComponent* collider);
|
||||
|
@ -115,36 +115,69 @@ bool CircleContainCircle(Vector2D a_pos, float a_rad, Vector2D b_pos, float b_ra
|
||||
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)
|
||||
{
|
||||
new_pos = b_pos;
|
||||
bool at_left = std::abs(b_pos.x - a_min.x) < std::abs(b_pos.x - a_max.x);
|
||||
bool at_down = std::abs(b_pos.y - a_min.y) < std::abs(b_pos.y - a_max.y);
|
||||
float x_len = at_left ? std::abs(b_pos.x - a_min.x) : std::abs(b_pos.x - a_max.x);
|
||||
float y_len = at_down ? std::abs(b_pos.y - a_min.y) : std::abs(b_pos.y - a_max.y);
|
||||
new_pos = a_pos;
|
||||
bool at_left = std::abs(a_pos.x - b_min.x) < std::abs(a_pos.x - b_max.x);
|
||||
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(a_pos.x - b_min.x) : std::abs(a_pos.x - b_max.x);
|
||||
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 (x_len < y_len) {
|
||||
//左
|
||||
new_pos.x = a_min.x - b_rad - 1;
|
||||
new_pos.x = b_min.x - b_rad - 1;
|
||||
} else {
|
||||
if (at_down) {
|
||||
new_pos.y = a_min.y - b_rad - 1;
|
||||
new_pos.y = b_min.y - b_rad - 1;
|
||||
} else {
|
||||
new_pos.y = a_max.y + b_rad + 1;
|
||||
new_pos.y = b_max.y + b_rad + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (x_len < y_len) {
|
||||
//右
|
||||
new_pos.x = a_max.x + b_rad + 1;
|
||||
new_pos.x = b_max.x + b_rad + 1;
|
||||
} else {
|
||||
if (at_down) {
|
||||
new_pos.y = a_min.y - b_rad - 1;
|
||||
new_pos.y = b_min.y - b_rad - 1;
|
||||
} else {
|
||||
new_pos.y = a_max.y + b_rad + 1;
|
||||
new_pos.y = b_max.y + b_rad + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -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 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 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);
|
||||
void TestGlm();
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "entity.h"
|
||||
#include "collider.h"
|
||||
#include "room.h"
|
||||
#include "building.h"
|
||||
|
||||
Entity::Entity()
|
||||
{
|
||||
@ -19,6 +20,14 @@ void Entity::Initialize()
|
||||
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)
|
||||
{
|
||||
for (auto& a_collider : colliders) {
|
||||
@ -35,23 +44,64 @@ void Entity::ClearColliders()
|
||||
{
|
||||
for (auto& itr : colliders) {
|
||||
ColliderComponent* collider = itr;
|
||||
switch (collider->type) {
|
||||
case CT_Aabb:
|
||||
{
|
||||
delete (AabbCollider*)collider;
|
||||
}
|
||||
break;
|
||||
case CT_Circle:
|
||||
{
|
||||
delete (CircleCollider*)collider;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
delete collider;
|
||||
}
|
||||
break;
|
||||
}
|
||||
DestoryCollider(collider);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -57,6 +57,9 @@ class Entity
|
||||
virtual void FillMFObjectPart(cs::MFObjectPart* part_data) {};
|
||||
virtual void FillMFObjectFull(cs::MFObjectFull* full_data) {};
|
||||
virtual float GetSpeed() { return 1.0f;};
|
||||
virtual ColliderComponent* GetBoxBound();
|
||||
bool TestCollision(Entity* b);
|
||||
void ClearColliders();
|
||||
void FindLocationWithTarget(Entity* target);
|
||||
|
||||
};
|
||||
|
@ -323,7 +323,6 @@ ColliderComponent* Human::GetFirstCollision()
|
||||
|
||||
void Human::FindPath()
|
||||
{
|
||||
ColliderComponent* first_collider = nullptr;
|
||||
Vector2D old_pos = pos;
|
||||
{
|
||||
float up_dot = Vector2D::UP.Dot(move_dir);
|
||||
@ -649,20 +648,20 @@ void Human::FindLocation()
|
||||
}
|
||||
if (!objects.empty()) {
|
||||
Building* building = (Building*)objects[0];
|
||||
Vector2D a_min = Vector2D(
|
||||
Vector2D b_min = Vector2D(
|
||||
building->pos.x - building->meta->i->tilewidth()/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.y + building->meta->i->tileheight()/2.0
|
||||
);
|
||||
Vector2D new_pos;
|
||||
bool ret = CalcCircleAabbSafePoint(
|
||||
a_min,
|
||||
a_max,
|
||||
pos,
|
||||
GetRadius(),
|
||||
b_min,
|
||||
b_max,
|
||||
new_pos
|
||||
);
|
||||
if (!ret) {
|
||||
@ -670,7 +669,27 @@ void Human::FindLocation()
|
||||
}
|
||||
if (ret) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
if (!be_added_hash_.empty()) {
|
||||
|
@ -65,6 +65,8 @@ public:
|
||||
std::function<void (Player*, a8::XParams&)> func);
|
||||
void TouchHumanList(a8::XParams param,
|
||||
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 DropItem(Vector2D pos, int item_id, int item_count);
|
||||
|
Loading…
x
Reference in New Issue
Block a user