2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:29:17 +01:00
|
|
|
#include "gsai_avoid_collisions.h"
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
GSAISteeringAgent GSAIAvoidCollisions::get_ *_first_neighbor() {
|
|
|
|
return *_first_neighbor;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
void GSAIAvoidCollisions::set_ *_first_neighbor(const GSAISteeringAgent &val) {
|
|
|
|
*_first_neighbor = val;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
float GSAIAvoidCollisions::get__shortest_time() const {
|
2023-01-13 21:35:07 +01:00
|
|
|
return _shortest_time;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSAIAvoidCollisions::set__shortest_time(const float val) {
|
2023-01-13 21:35:07 +01:00
|
|
|
_shortest_time = val;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
float GSAIAvoidCollisions::get__first_minimum_separation() const {
|
2023-01-13 21:35:07 +01:00
|
|
|
return _first_minimum_separation;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSAIAvoidCollisions::set__first_minimum_separation(const float val) {
|
2023-01-13 21:35:07 +01:00
|
|
|
_first_minimum_separation = val;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
float GSAIAvoidCollisions::get__first_distance() const {
|
2023-01-13 21:35:07 +01:00
|
|
|
return _first_distance;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSAIAvoidCollisions::set__first_distance(const float val) {
|
2023-01-13 21:35:07 +01:00
|
|
|
_first_distance = val;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 GSAIAvoidCollisions::get__first_relative_position() {
|
2023-01-13 21:35:07 +01:00
|
|
|
return _first_relative_position;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSAIAvoidCollisions::set__first_relative_position(const Vector3 &val) {
|
2023-01-13 21:35:07 +01:00
|
|
|
_first_relative_position = val;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 GSAIAvoidCollisions::get__first_relative_velocity() {
|
2023-01-13 21:35:07 +01:00
|
|
|
return _first_relative_velocity;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSAIAvoidCollisions::set__first_relative_velocity(const Vector3 &val) {
|
2023-01-13 21:35:07 +01:00
|
|
|
_first_relative_velocity = val;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
// Steers the agent to avoid obstacles in its path. Approximates obstacles as;
|
|
|
|
// spheres.;
|
|
|
|
// @category - Group behaviors;
|
|
|
|
GSAISteeringAgent *_first_neighbor;
|
|
|
|
float _shortest_time = 0.0;
|
|
|
|
float _first_minimum_separation = 0.0;
|
|
|
|
float _first_distance = 0.0;
|
|
|
|
Vector3 _first_relative_position = ;
|
|
|
|
Vector3 _first_relative_velocity = ;
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
void GSAIAvoidCollisions::_calculate_steering(const GSAITargetAcceleration &acceleration) {
|
|
|
|
_shortest_time = INF;
|
|
|
|
_first_neighbor = null;
|
|
|
|
_first_minimum_separation = 0;
|
|
|
|
_first_distance = 0;
|
|
|
|
int neighbor_count = proximity.find_neighbors(_callback);
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
if (neighbor_count == 0 || not _first_neighbor) {
|
|
|
|
acceleration.set_zero();
|
|
|
|
}
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
else {
|
|
|
|
if ((_first_minimum_separation <= 0 || _first_distance < agent.bounding_radius + _first_neighbor.bounding_radius)) {
|
|
|
|
acceleration.linear = _first_neighbor.position - agent.position;
|
|
|
|
}
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
else {
|
|
|
|
acceleration.linear = (_first_relative_position + (_first_relative_velocity * _shortest_time));
|
|
|
|
}
|
|
|
|
}
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
acceleration.linear = (acceleration.linear.normalized() * -agent.linear_acceleration_max);
|
|
|
|
acceleration.angular = 0;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
// Callback for the proximity to call when finding neighbors. Keeps track of every `neighbor`;
|
|
|
|
// that was found but only keeps the one the owning agent will most likely collide with.;
|
|
|
|
// @tags - virtual;
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
bool GSAIAvoidCollisions::_report_neighbor(const GSAISteeringAgent &neighbor) {
|
|
|
|
Vector3 relative_position = neighbor.position - agent.position;
|
|
|
|
Vector3 relative_velocity = neighbor.linear_velocity - agent.linear_velocity;
|
|
|
|
float relative_speed_squared = relative_velocity.length_squared();
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
if (relative_speed_squared == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
else {
|
|
|
|
float time_to_collision = -relative_position.dot(relative_velocity) / relative_speed_squared;
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
if (time_to_collision <= 0 || time_to_collision >= _shortest_time) {
|
|
|
|
return false;
|
|
|
|
}
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
else {
|
|
|
|
Variant = relative_position.length();
|
|
|
|
float minimum_separation = (distance - sqrt(relative_speed_squared) * time_to_collision);
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
if (minimum_separation > agent.bounding_radius + neighbor.bounding_radius) {
|
|
|
|
return false;
|
|
|
|
}
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
else {
|
|
|
|
_shortest_time = time_to_collision;
|
|
|
|
_first_neighbor = neighbor;
|
|
|
|
_first_minimum_separation = minimum_separation;
|
|
|
|
_first_distance = distance;
|
|
|
|
_first_relative_position = relative_position;
|
|
|
|
_first_relative_velocity = relative_velocity;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
GSAIAvoidCollisions::GSAIAvoidCollisions() {
|
|
|
|
*_first_neighbor;
|
|
|
|
_shortest_time = 0.0;
|
|
|
|
_first_minimum_separation = 0.0;
|
|
|
|
_first_distance = 0.0;
|
|
|
|
_first_relative_position = ;
|
|
|
|
_first_relative_velocity = ;
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
GSAIAvoidCollisions::~GSAIAvoidCollisions() {
|
2023-01-13 21:13:57 +01:00
|
|
|
}
|
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
static void GSAIAvoidCollisions::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("get_*_first_neighbor"), &GSAIAvoidCollisions::get_ * _first_neighbor);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_*_first_neighbor", "value"), &GSAIAvoidCollisions::set_ * _first_neighbor);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*_first_neighbor", PROPERTY_HINT_RESOURCE_TYPE, "GSAISteeringAgent"), "set_*_first_neighbor", "get_*_first_neighbor");
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
ClassDB::bind_method(D_METHOD("get__shortest_time"), &GSAIAvoidCollisions::get__shortest_time);
|
|
|
|
ClassDB::bind_method(D_METHOD("set__shortest_time", "value"), &GSAIAvoidCollisions::set__shortest_time);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "_shortest_time"), "set__shortest_time", "get__shortest_time");
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
ClassDB::bind_method(D_METHOD("get__first_minimum_separation"), &GSAIAvoidCollisions::get__first_minimum_separation);
|
|
|
|
ClassDB::bind_method(D_METHOD("set__first_minimum_separation", "value"), &GSAIAvoidCollisions::set__first_minimum_separation);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "_first_minimum_separation"), "set__first_minimum_separation", "get__first_minimum_separation");
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("get__first_distance"), &GSAIAvoidCollisions::get__first_distance);
|
|
|
|
ClassDB::bind_method(D_METHOD("set__first_distance", "value"), &GSAIAvoidCollisions::set__first_distance);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "_first_distance"), "set__first_distance", "get__first_distance");
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
ClassDB::bind_method(D_METHOD("get__first_relative_position"), &GSAIAvoidCollisions::get__first_relative_position);
|
|
|
|
ClassDB::bind_method(D_METHOD("set__first_relative_position", "value"), &GSAIAvoidCollisions::set__first_relative_position);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "_first_relative_position"), "set__first_relative_position", "get__first_relative_position");
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
ClassDB::bind_method(D_METHOD("get__first_relative_velocity"), &GSAIAvoidCollisions::get__first_relative_velocity);
|
|
|
|
ClassDB::bind_method(D_METHOD("set__first_relative_velocity", "value"), &GSAIAvoidCollisions::set__first_relative_velocity);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "_first_relative_velocity"), "set__first_relative_velocity", "get__first_relative_velocity");
|
2023-01-13 21:13:57 +01:00
|
|
|
|
2023-01-13 21:35:07 +01:00
|
|
|
ClassDB::bind_method(D_METHOD("_calculate_steering", "acceleration"), &GSAIAvoidCollisions::_calculate_steering);
|
|
|
|
ClassDB::bind_method(D_METHOD("_report_neighbor", "neighbor"), &GSAIAvoidCollisions::_report_neighbor);
|
|
|
|
}
|