Added a new steering_ai module.

It's a modified verion of https://github.com/GDQuest/godot-steering-ai-framework which I converted to c++ using thr converter srcipt.
It still needs to be cleaned.
This commit is contained in:
Relintai 2023-01-13 21:13:57 +01:00
parent 4b09cb47ab
commit 9fed52de03
64 changed files with 5029 additions and 0 deletions

View File

@ -0,0 +1,296 @@
#include "gsaikinematicbody2dagent.h"
KinematicBody2D GSAIKinematicBody2DAgent::get_*body() {
return *body;
}
void GSAIKinematicBody2DAgent::set_*body(const KinematicBody2D &val) {
*body = val;
}
int GSAIKinematicBody2DAgent::get_movement_type() const {
return movement_type;
}
void GSAIKinematicBody2DAgent::set_movement_type(const int val) {
movement_type = val;
}
Vector2 GSAIKinematicBody2DAgent::get__last_position() {
return _last_position;
}
void GSAIKinematicBody2DAgent::set__last_position(const Vector2 &val) {
_last_position = val;
}
Ref<WeakRef> GSAIKinematicBody2DAgent::get__body_ref() {
return _body_ref;
}
void GSAIKinematicBody2DAgent::set__body_ref(const Ref<WeakRef> &val) {
_body_ref = val;
}
// A specialized steering agent that updates itself every frame so the user does;
// not have to using a KinematicBody2D;
// @category - Specialized agents;
// SLIDE uses `move_and_slide`;
// COLLIDE uses `move_and_collide`;
// POSITION changes the `global_position` directly;
};
// The KinematicBody2D to keep track of;
// setget _set_body;
KinematicBody2D *body;
// The type of movement the body executes;
int movement_type = MovementType.SLIDE;
Vector2 _last_position = ;
Ref<WeakRef> _body_ref;
void GSAIKinematicBody2DAgent::_body_ready() {
// warning-ignore:return_value_discarded;
body.get_tree().connect("physics_frame", self, "_on_SceneTree_physics_frame");
}
// Moves the agent's `body` by target `acceleration`.;
// @tags - virtual;
void GSAIKinematicBody2DAgent::_apply_steering(const GSAITargetAcceleration &acceleration, const float delta) {
applied_steering = true;
if (movement_type == MovementType.COLLIDE) {
_apply_collide_steering(acceleration.linear, delta);
}
else if (movement_type == MovementType.SLIDE) {
_apply_sliding_steering(acceleration.linear, delta);
}
else {
_apply_position_steering(acceleration.linear, delta);
}
_apply_orientation_steering(acceleration.angular, delta);
}
void GSAIKinematicBody2DAgent::_apply_sliding_steering(const Vector3 &accel, const float delta) {
KinematicBody2D *_body = _body_ref.get_ref();
if (!_body) {
return;
}
if (!_body.is_inside_tree() || _body.get_tree().paused) {
return;
}
Vector2 velocity = GSAIUtils.to_vector2(linear_velocity + accel * delta).clamped(linear_speed_max);
if (apply_linear_drag) {
velocity = velocity.linear_interpolate(Vector2.ZERO, linear_drag_percentage);
}
velocity = _body.move_and_slide(velocity);
if (calculate_velocities) {
linear_velocity = GSAIUtils.to_vector3(velocity);
}
}
void GSAIKinematicBody2DAgent::_apply_collide_steering(const Vector3 &accel, const float delta) {
KinematicBody2D *_body = _body_ref.get_ref();
if (!_body) {
return;
}
Vector3 velocity = GSAIUtils.clampedv3(linear_velocity + accel * delta, linear_speed_max);
if (apply_linear_drag) {
velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
}
// warning-ignore:return_value_discarded;
_body.move_and_collide(GSAIUtils.to_vector2(velocity) * delta);
if (calculate_velocities) {
linear_velocity = velocity;
}
}
void GSAIKinematicBody2DAgent::_apply_position_steering(const Vector3 &accel, const float delta) {
KinematicBody2D *_body = _body_ref.get_ref();
if (!_body) {
return;
}
Vector3 velocity = GSAIUtils.clampedv3(linear_velocity + accel * delta, linear_speed_max);
if (apply_linear_drag) {
velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
}
_body.global_position += GSAIUtils.to_vector2(velocity) * delta;
if (calculate_velocities) {
linear_velocity = velocity;
}
}
void GSAIKinematicBody2DAgent::_apply_orientation_steering(const float angular_acceleration, const float delta) {
KinematicBody2D *_body = _body_ref.get_ref();
if (!_body) {
return;
}
Variant = clamp(angular_velocity + angular_acceleration * delta, -angular_speed_max, angular_speed_max);
if (apply_angular_drag) {
velocity = lerp(velocity, 0, angular_drag_percentage);
}
_body.rotation += velocity * delta;
if (calculate_velocities) {
angular_velocity = velocity;
}
}
void GSAIKinematicBody2DAgent::_set_body(const KinematicBody2D &value) {
bool had_body = false;
if (body) {
had_body = true;
}
body = value;
_body_ref = weakref(body);
_last_position = value.global_position;
last_orientation = value.rotation;
position = GSAIUtils.to_vector3(_last_position);
orientation = last_orientation;
if (!had_body) {
if (!body.is_inside_tree()) {
body.connect("ready", self, "_body_ready");
}
else {
_body_ready();
}
}
}
void GSAIKinematicBody2DAgent::_on_SceneTree_physics_frame() {
KinematicBody2D *_body = _body_ref.get_ref();
if (!_body) {
return;
}
Vector2 current_position = _body.global_position;
float current_orientation = _body.rotation;
position = GSAIUtils.to_vector3(current_position);
orientation = current_orientation;
if (calculate_velocities) {
if (applied_steering) {
applied_steering = false;
}
else {
linear_velocity = GSAIUtils.clampedv3(GSAIUtils.to_vector3(current_position - _last_position), linear_speed_max);
if (apply_linear_drag) {
linear_velocity = linear_velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
}
angular_velocity = clamp(last_orientation - current_orientation, -angular_speed_max, angular_speed_max);
if (apply_angular_drag) {
angular_velocity = lerp(angular_velocity, 0, angular_drag_percentage);
}
_last_position = current_position;
last_orientation = current_orientation;
}
}
}
}
GSAIKinematicBody2DAgent::GSAIKinematicBody2DAgent() {
*body;
movement_type = MovementType.SLIDE;
_last_position = ;
_body_ref;
}
GSAIKinematicBody2DAgent::~GSAIKinematicBody2DAgent() {
}
static void GSAIKinematicBody2DAgent::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_*body"), &GSAIKinematicBody2DAgent::get_*body);
ClassDB::bind_method(D_METHOD("set_*body", "value"), &GSAIKinematicBody2DAgent::set_*body);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*body", PROPERTY_HINT_RESOURCE_TYPE, "KinematicBody2D"), "set_*body", "get_*body");
ClassDB::bind_method(D_METHOD("get_movement_type"), &GSAIKinematicBody2DAgent::get_movement_type);
ClassDB::bind_method(D_METHOD("set_movement_type", "value"), &GSAIKinematicBody2DAgent::set_movement_type);
ADD_PROPERTY(PropertyInfo(Variant::INT, "movement_type"), "set_movement_type", "get_movement_type");
ClassDB::bind_method(D_METHOD("get__last_position"), &GSAIKinematicBody2DAgent::get__last_position);
ClassDB::bind_method(D_METHOD("set__last_position", "value"), &GSAIKinematicBody2DAgent::set__last_position);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "_last_position"), "set__last_position", "get__last_position");
ClassDB::bind_method(D_METHOD("get__body_ref"), &GSAIKinematicBody2DAgent::get__body_ref);
ClassDB::bind_method(D_METHOD("set__body_ref", "value"), &GSAIKinematicBody2DAgent::set__body_ref);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "_body_ref", PROPERTY_HINT_RESOURCE_TYPE, "Ref<WeakRef>"), "set__body_ref", "get__body_ref");
ClassDB::bind_method(D_METHOD("_body_ready"), &GSAIKinematicBody2DAgent::_body_ready);
ClassDB::bind_method(D_METHOD("_apply_steering", "acceleration", "delta"), &GSAIKinematicBody2DAgent::_apply_steering);
ClassDB::bind_method(D_METHOD("_apply_sliding_steering", "accel", "delta"), &GSAIKinematicBody2DAgent::_apply_sliding_steering);
ClassDB::bind_method(D_METHOD("_apply_collide_steering", "accel", "delta"), &GSAIKinematicBody2DAgent::_apply_collide_steering);
ClassDB::bind_method(D_METHOD("_apply_position_steering", "accel", "delta"), &GSAIKinematicBody2DAgent::_apply_position_steering);
ClassDB::bind_method(D_METHOD("_apply_orientation_steering", "angular_acceleration", "delta"), &GSAIKinematicBody2DAgent::_apply_orientation_steering);
ClassDB::bind_method(D_METHOD("_set_body", "value"), &GSAIKinematicBody2DAgent::_set_body);
ClassDB::bind_method(D_METHOD("_on_SceneTree_physics_frame"), &GSAIKinematicBody2DAgent::_on_SceneTree_physics_frame);
}

View File

@ -0,0 +1,63 @@
#ifndef GSAIKINEMATICBODY2DAGENT_H
#define GSAIKINEMATICBODY2DAGENT_H
class GSAIKinematicBody2DAgent : public GSAISpecializedAgent {
GDCLASS(GSAIKinematicBody2DAgent, GSAISpecializedAgent);
public:
KinematicBody2D get_*body();
void set_*body(const KinematicBody2D &val);
int get_movement_type() const;
void set_movement_type(const int val);
Vector2 get__last_position();
void set__last_position(const Vector2 &val);
Ref<WeakRef> get__body_ref();
void set__body_ref(const Ref<WeakRef> &val);
enum MovementType {
SLIDE,
COLLIDE,
POSITION
};
void _body_ready();
void _apply_steering(const GSAITargetAcceleration &acceleration, const float delta);
void _apply_sliding_steering(const Vector3 &accel, const float delta);
void _apply_collide_steering(const Vector3 &accel, const float delta);
void _apply_position_steering(const Vector3 &accel, const float delta);
void _apply_orientation_steering(const float angular_acceleration, const float delta);
void _set_body(const KinematicBody2D &value);
void _on_SceneTree_physics_frame();
GSAIKinematicBody2DAgent();
~GSAIKinematicBody2DAgent();
protected:
static void _bind_methods();
// A specialized steering agent that updates itself every frame so the user does
// not have to using a KinematicBody2D
// @category - Specialized agents
// SLIDE uses `move_and_slide`
// COLLIDE uses `move_and_collide`
// POSITION changes the `global_position` directly
};
// The KinematicBody2D to keep track of
// setget _set_body
KinematicBody2D *body;
// The type of movement the body executes
int movement_type = MovementType.SLIDE;
Vector2 _last_position = ;
Ref<WeakRef> _body_ref;
// Moves the agent's `body` by target `acceleration`.
// @tags - virtual
};
#endif

View File

@ -0,0 +1,296 @@
#include "gsaikinematicbody3dagent.h"
KinematicBody GSAIKinematicBody3DAgent::get_*body() {
return *body;
}
void GSAIKinematicBody3DAgent::set_*body(const KinematicBody &val) {
*body = val;
}
int GSAIKinematicBody3DAgent::get_movement_type() const {
return movement_type;
}
void GSAIKinematicBody3DAgent::set_movement_type(const int val) {
movement_type = val;
}
Vector3 GSAIKinematicBody3DAgent::get__last_position() {
return _last_position;
}
void GSAIKinematicBody3DAgent::set__last_position(const Vector3 &val) {
_last_position = val;
}
Ref<WeakRef> GSAIKinematicBody3DAgent::get__body_ref() {
return _body_ref;
}
void GSAIKinematicBody3DAgent::set__body_ref(const Ref<WeakRef> &val) {
_body_ref = val;
}
// A specialized steering agent that updates itself every frame so the user does;
// not have to using a KinematicBody;
// @category - Specialized agents;
// SLIDE uses `move_and_slide`;
// COLLIDE uses `move_and_collide`;
// POSITION changes the global_position directly;
};
// The KinematicBody to keep track of;
// setget _set_body;
KinematicBody *body;
// The type of movement the body executes;
int movement_type = 0;
Vector3 _last_position = ;
Ref<WeakRef> _body_ref;
void GSAIKinematicBody3DAgent::_body_ready() {
// warning-ignore:return_value_discarded;
body.get_tree().connect("physics_frame", self, "_on_SceneTree_physics_frame");
}
// Moves the agent's `body` by target `acceleration`.;
// @tags - virtual;
void GSAIKinematicBody3DAgent::_apply_steering(const GSAITargetAcceleration &acceleration, const float delta) {
applied_steering = true;
if (movement_type == MovementType.COLLIDE) {
_apply_collide_steering(acceleration.linear, delta);
}
else if (movement_type == MovementType.SLIDE) {
_apply_sliding_steering(acceleration.linear, delta);
}
else {
_apply_position_steering(acceleration.linear, delta);
}
_apply_orientation_steering(acceleration.angular, delta);
}
void GSAIKinematicBody3DAgent::_apply_sliding_steering(const Vector3 &accel, const float delta) {
KinematicBody *_body = _body_ref.get_ref();
if (!_body) {
return;
}
Vector3 velocity = GSAIUtils.clampedv3(linear_velocity + accel * delta, linear_speed_max);
if (apply_linear_drag) {
velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
}
velocity = _body.move_and_slide(velocity);
if (calculate_velocities) {
linear_velocity = velocity;
}
}
void GSAIKinematicBody3DAgent::_apply_collide_steering(const Vector3 &accel, const float delta) {
KinematicBody *_body = _body_ref.get_ref();
if (!_body) {
return;
}
Vector3 velocity = GSAIUtils.clampedv3(linear_velocity + accel * delta, linear_speed_max);
if (apply_linear_drag) {
velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
}
// warning-ignore:return_value_discarded;
_body.move_and_collide(velocity * delta);
if (calculate_velocities) {
linear_velocity = velocity;
}
}
void GSAIKinematicBody3DAgent::_apply_position_steering(const Vector3 &accel, const float delta) {
KinematicBody *_body = _body_ref.get_ref();
if (!_body) {
return;
}
Vector3 velocity = GSAIUtils.clampedv3(linear_velocity + accel * delta, linear_speed_max);
if (apply_linear_drag) {
velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
}
_body.global_transform.origin += velocity * delta;
if (calculate_velocities) {
linear_velocity = velocity;
}
}
void GSAIKinematicBody3DAgent::_apply_orientation_steering(const float angular_acceleration, const float delta) {
KinematicBody *_body = _body_ref.get_ref();
if (!_body) {
return;
}
Variant = clamp(angular_velocity + angular_acceleration * delta,-angular_speed_max,angular_speed_max);
if (apply_angular_drag) {
velocity = lerp(velocity, 0, angular_drag_percentage);
}
_body.rotation.y += velocity * delta;
if (calculate_velocities) {
angular_velocity = velocity;
}
}
void GSAIKinematicBody3DAgent::_set_body(const KinematicBody &value) {
bool had_body = false;
if (body) {
had_body = true;
}
body = value;
_body_ref = weakref(value);
_last_position = value.transform.origin;
last_orientation = value.rotation.y;
position = _last_position;
orientation = last_orientation;
if (!had_body) {
if (!body.is_inside_tree()) {
body.connect("ready", self, "_body_ready");
}
else {
_body_ready();
}
}
}
void GSAIKinematicBody3DAgent::_on_SceneTree_physics_frame() {
KinematicBody *_body = _body_ref.get_ref();
if (!_body) {
return;
}
if (!_body.is_inside_tree() || _body.get_tree().paused) {
return;
}
Vector3 current_position = _body.transform.origin;
float current_orientation = _body.rotation.y;
position = current_position;
orientation = current_orientation;
if (calculate_velocities) {
if (applied_steering) {
applied_steering = false;
}
else {
linear_velocity = GSAIUtils.clampedv3(current_position - _last_position, linear_speed_max);
if (apply_linear_drag) {
linear_velocity = linear_velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage);
}
angular_velocity = clamp(last_orientation - current_orientation,-angular_speed_max,angular_speed_max);
if (apply_angular_drag) {
angular_velocity = lerp(angular_velocity, 0, angular_drag_percentage);
}
_last_position = current_position;
last_orientation = current_orientation;
}
}
}
}
GSAIKinematicBody3DAgent::GSAIKinematicBody3DAgent() {
*body;
movement_type = 0;
_last_position = ;
_body_ref;
}
GSAIKinematicBody3DAgent::~GSAIKinematicBody3DAgent() {
}
static void GSAIKinematicBody3DAgent::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_*body"), &GSAIKinematicBody3DAgent::get_*body);
ClassDB::bind_method(D_METHOD("set_*body", "value"), &GSAIKinematicBody3DAgent::set_*body);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*body", PROPERTY_HINT_RESOURCE_TYPE, "KinematicBody"), "set_*body", "get_*body");
ClassDB::bind_method(D_METHOD("get_movement_type"), &GSAIKinematicBody3DAgent::get_movement_type);
ClassDB::bind_method(D_METHOD("set_movement_type", "value"), &GSAIKinematicBody3DAgent::set_movement_type);
ADD_PROPERTY(PropertyInfo(Variant::INT, "movement_type"), "set_movement_type", "get_movement_type");
ClassDB::bind_method(D_METHOD("get__last_position"), &GSAIKinematicBody3DAgent::get__last_position);
ClassDB::bind_method(D_METHOD("set__last_position", "value"), &GSAIKinematicBody3DAgent::set__last_position);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "_last_position"), "set__last_position", "get__last_position");
ClassDB::bind_method(D_METHOD("get__body_ref"), &GSAIKinematicBody3DAgent::get__body_ref);
ClassDB::bind_method(D_METHOD("set__body_ref", "value"), &GSAIKinematicBody3DAgent::set__body_ref);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "_body_ref", PROPERTY_HINT_RESOURCE_TYPE, "Ref<WeakRef>"), "set__body_ref", "get__body_ref");
ClassDB::bind_method(D_METHOD("_body_ready"), &GSAIKinematicBody3DAgent::_body_ready);
ClassDB::bind_method(D_METHOD("_apply_steering", "acceleration", "delta"), &GSAIKinematicBody3DAgent::_apply_steering);
ClassDB::bind_method(D_METHOD("_apply_sliding_steering", "accel", "delta"), &GSAIKinematicBody3DAgent::_apply_sliding_steering);
ClassDB::bind_method(D_METHOD("_apply_collide_steering", "accel", "delta"), &GSAIKinematicBody3DAgent::_apply_collide_steering);
ClassDB::bind_method(D_METHOD("_apply_position_steering", "accel", "delta"), &GSAIKinematicBody3DAgent::_apply_position_steering);
ClassDB::bind_method(D_METHOD("_apply_orientation_steering", "angular_acceleration", "delta"), &GSAIKinematicBody3DAgent::_apply_orientation_steering);
ClassDB::bind_method(D_METHOD("_set_body", "value"), &GSAIKinematicBody3DAgent::_set_body);
ClassDB::bind_method(D_METHOD("_on_SceneTree_physics_frame"), &GSAIKinematicBody3DAgent::_on_SceneTree_physics_frame);
}

View File

@ -0,0 +1,63 @@
#ifndef GSAIKINEMATICBODY3DAGENT_H
#define GSAIKINEMATICBODY3DAGENT_H
class GSAIKinematicBody3DAgent : public GSAISpecializedAgent {
GDCLASS(GSAIKinematicBody3DAgent, GSAISpecializedAgent);
public:
KinematicBody get_*body();
void set_*body(const KinematicBody &val);
int get_movement_type() const;
void set_movement_type(const int val);
Vector3 get__last_position();
void set__last_position(const Vector3 &val);
Ref<WeakRef> get__body_ref();
void set__body_ref(const Ref<WeakRef> &val);
enum MovementType {
SLIDE,
COLLIDE,
POSITION
};
void _body_ready();
void _apply_steering(const GSAITargetAcceleration &acceleration, const float delta);
void _apply_sliding_steering(const Vector3 &accel, const float delta);
void _apply_collide_steering(const Vector3 &accel, const float delta);
void _apply_position_steering(const Vector3 &accel, const float delta);
void _apply_orientation_steering(const float angular_acceleration, const float delta);
void _set_body(const KinematicBody &value);
void _on_SceneTree_physics_frame();
GSAIKinematicBody3DAgent();
~GSAIKinematicBody3DAgent();
protected:
static void _bind_methods();
// A specialized steering agent that updates itself every frame so the user does
// not have to using a KinematicBody
// @category - Specialized agents
// SLIDE uses `move_and_slide`
// COLLIDE uses `move_and_collide`
// POSITION changes the global_position directly
};
// The KinematicBody to keep track of
// setget _set_body
KinematicBody *body;
// The type of movement the body executes
int movement_type = 0;
Vector3 _last_position = ;
Ref<WeakRef> _body_ref;
// Moves the agent's `body` by target `acceleration`.
// @tags - virtual
};
#endif

View File

@ -0,0 +1,168 @@
#include "gsairigidbody2dagent.h"
RigidBody2D GSAIRigidBody2DAgent::get_*body() {
return *body;
}
void GSAIRigidBody2DAgent::set_*body(const RigidBody2D &val) {
*body = val;
}
Vector2 GSAIRigidBody2DAgent::get__last_position() {
return _last_position;
}
void GSAIRigidBody2DAgent::set__last_position(const Vector2 &val) {
_last_position = val;
}
Ref<WeakRef> GSAIRigidBody2DAgent::get__body_ref() {
return _body_ref;
}
void GSAIRigidBody2DAgent::set__body_ref(const Ref<WeakRef> &val) {
_body_ref = val;
}
// A specialized steering agent that updates itself every frame so the user does;
// not have to using a RigidBody2D;
// @category - Specialized agents;
// The RigidBody2D to keep track of;
// setget _set_body;
RigidBody2D *body;
Vector2 _last_position = ;
Ref<WeakRef> _body_ref;
void GSAIRigidBody2DAgent::_body_ready() {
// warning-ignore:return_value_discarded;
body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame");
}
// Moves the agent's `body` by target `acceleration`.;
// @tags - virtual;
void GSAIRigidBody2DAgent::_apply_steering(const GSAITargetAcceleration &acceleration, const float _delta) {
RigidBody2D *_body = _body_ref.get_ref();
if (not _body) {
return;
}
applied_steering = true;
_body.apply_central_impulse(GSAIUtils.to_vector2(acceleration.linear));
_body.apply_torque_impulse(acceleration.angular);
if (calculate_velocities) {
linear_velocity = GSAIUtils.to_vector3(_body.linear_velocity);
angular_velocity = _body.angular_velocity;
}
}
void GSAIRigidBody2DAgent::_set_body(const RigidBody2D &value) {
bool had_body = false;
if (body) {
had_body = true;
}
body = value;
_body_ref = weakref(value);
_last_position = value.global_position;
last_orientation = value.rotation;
position = GSAIUtils.to_vector3(_last_position);
orientation = last_orientation;
if (!had_body) {
if (!body.is_inside_tree()) {
body.connect("ready", self, "_body_ready");
}
else {
_body_ready();
}
}
}
void GSAIRigidBody2DAgent::_on_SceneTree_frame() {
RigidBody2D *_body = _body_ref.get_ref();
if (!_body) {
return;
}
if (!_body.is_inside_tree() || _body.get_tree().paused) {
return;
}
Vector2 current_position = _body.global_position;
float current_orientation = _body.rotation;
position = GSAIUtils.to_vector3(current_position);
orientation = current_orientation;
if (calculate_velocities) {
if (applied_steering) {
applied_steering = false;
}
else {
linear_velocity = GSAIUtils.to_vector3(_body.linear_velocity);
angular_velocity = _body.angular_velocity;
}
}
}
}
GSAIRigidBody2DAgent::GSAIRigidBody2DAgent() {
*body;
_last_position = ;
_body_ref;
}
GSAIRigidBody2DAgent::~GSAIRigidBody2DAgent() {
}
static void GSAIRigidBody2DAgent::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_*body"), &GSAIRigidBody2DAgent::get_*body);
ClassDB::bind_method(D_METHOD("set_*body", "value"), &GSAIRigidBody2DAgent::set_*body);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*body", PROPERTY_HINT_RESOURCE_TYPE, "RigidBody2D"), "set_*body", "get_*body");
ClassDB::bind_method(D_METHOD("get__last_position"), &GSAIRigidBody2DAgent::get__last_position);
ClassDB::bind_method(D_METHOD("set__last_position", "value"), &GSAIRigidBody2DAgent::set__last_position);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "_last_position"), "set__last_position", "get__last_position");
ClassDB::bind_method(D_METHOD("get__body_ref"), &GSAIRigidBody2DAgent::get__body_ref);
ClassDB::bind_method(D_METHOD("set__body_ref", "value"), &GSAIRigidBody2DAgent::set__body_ref);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "_body_ref", PROPERTY_HINT_RESOURCE_TYPE, "Ref<WeakRef>"), "set__body_ref", "get__body_ref");
ClassDB::bind_method(D_METHOD("_body_ready"), &GSAIRigidBody2DAgent::_body_ready);
ClassDB::bind_method(D_METHOD("_apply_steering", "acceleration", "_delta"), &GSAIRigidBody2DAgent::_apply_steering);
ClassDB::bind_method(D_METHOD("_set_body", "value"), &GSAIRigidBody2DAgent::_set_body);
ClassDB::bind_method(D_METHOD("_on_SceneTree_frame"), &GSAIRigidBody2DAgent::_on_SceneTree_frame);
}

View File

@ -0,0 +1,43 @@
#ifndef GSAIRIGIDBODY2DAGENT_H
#define GSAIRIGIDBODY2DAGENT_H
class GSAIRigidBody2DAgent : public GSAISpecializedAgent {
GDCLASS(GSAIRigidBody2DAgent, GSAISpecializedAgent);
public:
RigidBody2D get_*body();
void set_*body(const RigidBody2D &val);
Vector2 get__last_position();
void set__last_position(const Vector2 &val);
Ref<WeakRef> get__body_ref();
void set__body_ref(const Ref<WeakRef> &val);
void _body_ready();
void _apply_steering(const GSAITargetAcceleration &acceleration, const float _delta);
void _set_body(const RigidBody2D &value);
void _on_SceneTree_frame();
GSAIRigidBody2DAgent();
~GSAIRigidBody2DAgent();
protected:
static void _bind_methods();
// A specialized steering agent that updates itself every frame so the user does
// not have to using a RigidBody2D
// @category - Specialized agents
// The RigidBody2D to keep track of
// setget _set_body
RigidBody2D *body;
Vector2 _last_position = ;
Ref<WeakRef> _body_ref;
// Moves the agent's `body` by target `acceleration`.
// @tags - virtual
};
#endif

View File

@ -0,0 +1,168 @@
#include "gsairigidbody3dagent.h"
RigidBody GSAIRigidBody3DAgent::get_*body() {
return *body;
}
void GSAIRigidBody3DAgent::set_*body(const RigidBody &val) {
*body = val;
}
Vector3 GSAIRigidBody3DAgent::get__last_position() {
return _last_position;
}
void GSAIRigidBody3DAgent::set__last_position(const Vector3 &val) {
_last_position = val;
}
Ref<WeakRef> GSAIRigidBody3DAgent::get__body_ref() {
return _body_ref;
}
void GSAIRigidBody3DAgent::set__body_ref(const Ref<WeakRef> &val) {
_body_ref = val;
}
// A specialized steering agent that updates itself every frame so the user does;
// not have to using a RigidBody;
// @category - Specialized agents;
// The RigidBody to keep track of;
// setget _set_body;
RigidBody *body;
Vector3 _last_position = ;
Ref<WeakRef> _body_ref;
void GSAIRigidBody3DAgent::_body_ready() {
// warning-ignore:return_value_discarded;
body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame");
}
// Moves the agent's `body` by target `acceleration`.;
// @tags - virtual;
void GSAIRigidBody3DAgent::_apply_steering(const GSAITargetAcceleration &acceleration, const float _delta) {
RigidBody *_body = _body_ref.get_ref();
if (!_body) {
return;
}
applied_steering = true;
_body.apply_central_impulse(acceleration.linear);
_body.apply_torque_impulse(Vector3.UP * acceleration.angular);
if (calculate_velocities) {
linear_velocity = _body.linear_velocity;
angular_velocity = _body.angular_velocity.y;
}
}
void GSAIRigidBody3DAgent::_set_body(const RigidBody &value) {
bool had_body = false;
if (body) {
had_body = true;
}
body = value;
_body_ref = weakref(value);
_last_position = value.transform.origin;
last_orientation = value.rotation.y;
position = _last_position;
orientation = last_orientation;
if (!had_body) {
if (!body.is_inside_tree()) {
body.connect("ready", self, "_body_ready");
}
else {
_body_ready();
}
}
}
void GSAIRigidBody3DAgent::_on_SceneTree_frame() {
RigidBody *_body = _body_ref.get_ref();
if (not _body) {
return;
}
if (not _body.is_inside_tree() || _body.get_tree().paused) {
return;
}
Vector3 current_position = _body.transform.origin;
float current_orientation = _body.rotation.y;
position = current_position;
orientation = current_orientation;
if (calculate_velocities) {
if (applied_steering) {
applied_steering = false;
}
else {
linear_velocity = _body.linear_velocity;
angular_velocity = _body.angular_velocity.y;
}
}
}
}
GSAIRigidBody3DAgent::GSAIRigidBody3DAgent() {
*body;
_last_position = ;
_body_ref;
}
GSAIRigidBody3DAgent::~GSAIRigidBody3DAgent() {
}
static void GSAIRigidBody3DAgent::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_*body"), &GSAIRigidBody3DAgent::get_*body);
ClassDB::bind_method(D_METHOD("set_*body", "value"), &GSAIRigidBody3DAgent::set_*body);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*body", PROPERTY_HINT_RESOURCE_TYPE, "RigidBody"), "set_*body", "get_*body");
ClassDB::bind_method(D_METHOD("get__last_position"), &GSAIRigidBody3DAgent::get__last_position);
ClassDB::bind_method(D_METHOD("set__last_position", "value"), &GSAIRigidBody3DAgent::set__last_position);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "_last_position"), "set__last_position", "get__last_position");
ClassDB::bind_method(D_METHOD("get__body_ref"), &GSAIRigidBody3DAgent::get__body_ref);
ClassDB::bind_method(D_METHOD("set__body_ref", "value"), &GSAIRigidBody3DAgent::set__body_ref);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "_body_ref", PROPERTY_HINT_RESOURCE_TYPE, "Ref<WeakRef>"), "set__body_ref", "get__body_ref");
ClassDB::bind_method(D_METHOD("_body_ready"), &GSAIRigidBody3DAgent::_body_ready);
ClassDB::bind_method(D_METHOD("_apply_steering", "acceleration", "_delta"), &GSAIRigidBody3DAgent::_apply_steering);
ClassDB::bind_method(D_METHOD("_set_body", "value"), &GSAIRigidBody3DAgent::_set_body);
ClassDB::bind_method(D_METHOD("_on_SceneTree_frame"), &GSAIRigidBody3DAgent::_on_SceneTree_frame);
}

View File

@ -0,0 +1,43 @@
#ifndef GSAIRIGIDBODY3DAGENT_H
#define GSAIRIGIDBODY3DAGENT_H
class GSAIRigidBody3DAgent : public GSAISpecializedAgent {
GDCLASS(GSAIRigidBody3DAgent, GSAISpecializedAgent);
public:
RigidBody get_*body();
void set_*body(const RigidBody &val);
Vector3 get__last_position();
void set__last_position(const Vector3 &val);
Ref<WeakRef> get__body_ref();
void set__body_ref(const Ref<WeakRef> &val);
void _body_ready();
void _apply_steering(const GSAITargetAcceleration &acceleration, const float _delta);
void _set_body(const RigidBody &value);
void _on_SceneTree_frame();
GSAIRigidBody3DAgent();
~GSAIRigidBody3DAgent();
protected:
static void _bind_methods();
// A specialized steering agent that updates itself every frame so the user does
// not have to using a RigidBody
// @category - Specialized agents
// The RigidBody to keep track of
// setget _set_body
RigidBody *body;
Vector3 _last_position = ;
Ref<WeakRef> _body_ref;
// Moves the agent's `body` by target `acceleration`.
// @tags - virtual
};
#endif

View File

@ -0,0 +1,164 @@
#include "gsaispecializedagent.h"
bool GSAISpecializedAgent::get_calculate_velocities() const {
return calculate_velocities;
}
void GSAISpecializedAgent::set_calculate_velocities(const bool val) {
calculate_velocities = val;
}
bool GSAISpecializedAgent::get_apply_linear_drag() const {
return apply_linear_drag;
}
void GSAISpecializedAgent::set_apply_linear_drag(const bool val) {
apply_linear_drag = val;
}
bool GSAISpecializedAgent::get_apply_angular_drag() const {
return apply_angular_drag;
}
void GSAISpecializedAgent::set_apply_angular_drag(const bool val) {
apply_angular_drag = val;
}
float GSAISpecializedAgent::get_linear_drag_percentage() const {
return linear_drag_percentage;
}
void GSAISpecializedAgent::set_linear_drag_percentage(const float val) {
linear_drag_percentage = val;
}
float GSAISpecializedAgent::get_angular_drag_percentage() const {
return angular_drag_percentage;
}
void GSAISpecializedAgent::set_angular_drag_percentage(const float val) {
angular_drag_percentage = val;
}
float GSAISpecializedAgent::get_last_orientation() const {
return last_orientation;
}
void GSAISpecializedAgent::set_last_orientation(const float val) {
last_orientation = val;
}
bool GSAISpecializedAgent::get_applied_steering() const {
return applied_steering;
}
void GSAISpecializedAgent::set_applied_steering(const bool val) {
applied_steering = val;
}
// A base class for a specialized steering agent that updates itself every frame;
// so the user does not have to. All other specialized agents derive from this.;
// @category - Specialized agents;
// @tags - abstract;
// If `true`, calculates linear and angular velocities based on the previous;
// frame. When `false`, the user must keep those values updated.;
bool calculate_velocities = true;
// If `true`, interpolates the current linear velocity towards 0 by the;
// `linear_drag_percentage` value.;
// Does not apply to `RigidBody` and `RigidBody2D` nodes.;
bool apply_linear_drag = true;
// If `true`, interpolates the current angular velocity towards 0 by the;
// `angular_drag_percentage` value.;
// Does not apply to `RigidBody` and `RigidBody2D` nodes.;
bool apply_angular_drag = true;
// The percentage between the current linear velocity and 0 to interpolate by if;
// `apply_linear_drag` is true.;
// Does not apply to `RigidBody` and `RigidBody2D` nodes.;
float linear_drag_percentage = 0.0;
// The percentage between the current angular velocity and 0 to interpolate by if;
// `apply_angular_drag` is true.;
// Does not apply to `RigidBody` and `RigidBody2D` nodes.;
float angular_drag_percentage = 0.0;
float last_orientation = 0.0;
bool applied_steering = false;
void GSAISpecializedAgent::apply_steering(const GSAITargetAcceleration &_acceleration, const float _delta) {
call("_apply_steering", _acceleration, _delta);
}
// Moves the agent's body by target `acceleration`.;
// @tags - virtual;
void GSAISpecializedAgent::_apply_steering(const GSAITargetAcceleration &_acceleration, const float _delta) {
pass;
}
}
GSAISpecializedAgent::GSAISpecializedAgent() {
calculate_velocities = true;
apply_linear_drag = true;
apply_angular_drag = true;
linear_drag_percentage = 0.0;
angular_drag_percentage = 0.0;
last_orientation = 0.0;
applied_steering = false;
}
GSAISpecializedAgent::~GSAISpecializedAgent() {
}
static void GSAISpecializedAgent::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_calculate_velocities"), &GSAISpecializedAgent::get_calculate_velocities);
ClassDB::bind_method(D_METHOD("set_calculate_velocities", "value"), &GSAISpecializedAgent::set_calculate_velocities);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "calculate_velocities"), "set_calculate_velocities", "get_calculate_velocities");
ClassDB::bind_method(D_METHOD("get_apply_linear_drag"), &GSAISpecializedAgent::get_apply_linear_drag);
ClassDB::bind_method(D_METHOD("set_apply_linear_drag", "value"), &GSAISpecializedAgent::set_apply_linear_drag);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "apply_linear_drag"), "set_apply_linear_drag", "get_apply_linear_drag");
ClassDB::bind_method(D_METHOD("get_apply_angular_drag"), &GSAISpecializedAgent::get_apply_angular_drag);
ClassDB::bind_method(D_METHOD("set_apply_angular_drag", "value"), &GSAISpecializedAgent::set_apply_angular_drag);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "apply_angular_drag"), "set_apply_angular_drag", "get_apply_angular_drag");
ClassDB::bind_method(D_METHOD("get_linear_drag_percentage"), &GSAISpecializedAgent::get_linear_drag_percentage);
ClassDB::bind_method(D_METHOD("set_linear_drag_percentage", "value"), &GSAISpecializedAgent::set_linear_drag_percentage);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_drag_percentage"), "set_linear_drag_percentage", "get_linear_drag_percentage");
ClassDB::bind_method(D_METHOD("get_angular_drag_percentage"), &GSAISpecializedAgent::get_angular_drag_percentage);
ClassDB::bind_method(D_METHOD("set_angular_drag_percentage", "value"), &GSAISpecializedAgent::set_angular_drag_percentage);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_drag_percentage"), "set_angular_drag_percentage", "get_angular_drag_percentage");
ClassDB::bind_method(D_METHOD("get_last_orientation"), &GSAISpecializedAgent::get_last_orientation);
ClassDB::bind_method(D_METHOD("set_last_orientation", "value"), &GSAISpecializedAgent::set_last_orientation);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "last_orientation"), "set_last_orientation", "get_last_orientation");
ClassDB::bind_method(D_METHOD("get_applied_steering"), &GSAISpecializedAgent::get_applied_steering);
ClassDB::bind_method(D_METHOD("set_applied_steering", "value"), &GSAISpecializedAgent::set_applied_steering);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "applied_steering"), "set_applied_steering", "get_applied_steering");
ClassDB::bind_method(D_METHOD("apply_steering", "_acceleration", "_delta"), &GSAISpecializedAgent::apply_steering);
ClassDB::bind_method(D_METHOD("_apply_steering", "_acceleration", "_delta"), &GSAISpecializedAgent::_apply_steering);
}

View File

@ -0,0 +1,70 @@
#ifndef GSAISPECIALIZEDAGENT_H
#define GSAISPECIALIZEDAGENT_H
class GSAISpecializedAgent : public GSAISteeringAgent {
GDCLASS(GSAISpecializedAgent, GSAISteeringAgent);
public:
bool get_calculate_velocities() const;
void set_calculate_velocities(const bool val);
bool get_apply_linear_drag() const;
void set_apply_linear_drag(const bool val);
bool get_apply_angular_drag() const;
void set_apply_angular_drag(const bool val);
float get_linear_drag_percentage() const;
void set_linear_drag_percentage(const float val);
float get_angular_drag_percentage() const;
void set_angular_drag_percentage(const float val);
float get_last_orientation() const;
void set_last_orientation(const float val);
bool get_applied_steering() const;
void set_applied_steering(const bool val);
void apply_steering(const GSAITargetAcceleration &_acceleration, const float _delta);
void _apply_steering(const GSAITargetAcceleration &_acceleration, const float _delta);
GSAISpecializedAgent();
~GSAISpecializedAgent();
protected:
static void _bind_methods();
// A base class for a specialized steering agent that updates itself every frame
// so the user does not have to. All other specialized agents derive from this.
// @category - Specialized agents
// @tags - abstract
// If `true`, calculates linear and angular velocities based on the previous
// frame. When `false`, the user must keep those values updated.
bool calculate_velocities = true;
// If `true`, interpolates the current linear velocity towards 0 by the
// `linear_drag_percentage` value.
// Does not apply to `RigidBody` and `RigidBody2D` nodes.
bool apply_linear_drag = true;
// If `true`, interpolates the current angular velocity towards 0 by the
// `angular_drag_percentage` value.
// Does not apply to `RigidBody` and `RigidBody2D` nodes.
bool apply_angular_drag = true;
// The percentage between the current linear velocity and 0 to interpolate by if
// `apply_linear_drag` is true.
// Does not apply to `RigidBody` and `RigidBody2D` nodes.
float linear_drag_percentage = 0.0;
// The percentage between the current angular velocity and 0 to interpolate by if
// `apply_angular_drag` is true.
// Does not apply to `RigidBody` and `RigidBody2D` nodes.
float angular_drag_percentage = 0.0;
float last_orientation = 0.0;
bool applied_steering = false;
// Moves the agent's body by target `acceleration`.
// @tags - virtual
};
#endif

View File

@ -0,0 +1,130 @@
#include "gsaiarrive.h"
GSAIAgentLocation GSAIArrive::get_*target() {
return *target;
}
void GSAIArrive::set_*target(const GSAIAgentLocation &val) {
*target = val;
}
float GSAIArrive::get_arrival_tolerance() const {
return arrival_tolerance;
}
void GSAIArrive::set_arrival_tolerance(const float val) {
arrival_tolerance = val;
}
float GSAIArrive::get_deceleration_radius() const {
return deceleration_radius;
}
void GSAIArrive::set_deceleration_radius(const float val) {
deceleration_radius = val;
}
float GSAIArrive::get_time_to_reach() const {
return time_to_reach;
}
void GSAIArrive::set_time_to_reach(const float val) {
time_to_reach = val;
}
// Calculates acceleration to take an agent to its target's location. The;
// calculation attempts to arrive with zero remaining velocity.;
// @category - Individual behaviors;
// Target agent to arrive to.;
GSAIAgentLocation *target;
// Distance from the target for the agent to be considered successfully;
// arrived.;
float arrival_tolerance = 0.0;
// Distance from the target for the agent to begin slowing down.;
float deceleration_radius = 0.0;
// Represents the time it takes to change acceleration.;
float time_to_reach = 0.1;
void GSAIArrive::arrive(const GSAITargetAcceleration &acceleration, const Vector3 &target_position) {
call("_arrive", acceleration, target_position);
}
void GSAIArrive::_arrive(const GSAITargetAcceleration &acceleration, const Vector3 &target_position) {
Vector3 to_target = target_position - agent.position;
float distance = to_target.length();
if (distance <= arrival_tolerance) {
acceleration.set_zero();
}
else {
float desired_speed = agent.linear_speed_max;
if (distance <= deceleration_radius) {
desired_speed *= distance / deceleration_radius;
}
Vector3 desired_velocity = to_target * desired_speed / distance;
desired_velocity = ((desired_velocity - agent.linear_velocity) * 1.0 / time_to_reach);
acceleration.linear = GSAIUtils.clampedv3(desired_velocity, agent.linear_acceleration_max);
acceleration.angular = 0;
}
}
void GSAIArrive::_calculate_steering(const GSAITargetAcceleration &acceleration) {
arrive(acceleration, target.position);
}
}
GSAIArrive::GSAIArrive() {
*target;
arrival_tolerance = 0.0;
deceleration_radius = 0.0;
time_to_reach = 0.1;
}
GSAIArrive::~GSAIArrive() {
}
static void GSAIArrive::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_*target"), &GSAIArrive::get_*target);
ClassDB::bind_method(D_METHOD("set_*target", "value"), &GSAIArrive::set_*target);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*target", PROPERTY_HINT_RESOURCE_TYPE, "GSAIAgentLocation"), "set_*target", "get_*target");
ClassDB::bind_method(D_METHOD("get_arrival_tolerance"), &GSAIArrive::get_arrival_tolerance);
ClassDB::bind_method(D_METHOD("set_arrival_tolerance", "value"), &GSAIArrive::set_arrival_tolerance);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "arrival_tolerance"), "set_arrival_tolerance", "get_arrival_tolerance");
ClassDB::bind_method(D_METHOD("get_deceleration_radius"), &GSAIArrive::get_deceleration_radius);
ClassDB::bind_method(D_METHOD("set_deceleration_radius", "value"), &GSAIArrive::set_deceleration_radius);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "deceleration_radius"), "set_deceleration_radius", "get_deceleration_radius");
ClassDB::bind_method(D_METHOD("get_time_to_reach"), &GSAIArrive::get_time_to_reach);
ClassDB::bind_method(D_METHOD("set_time_to_reach", "value"), &GSAIArrive::set_time_to_reach);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "time_to_reach"), "set_time_to_reach", "get_time_to_reach");
ClassDB::bind_method(D_METHOD("arrive", "acceleration", "target_position"), &GSAIArrive::arrive);
ClassDB::bind_method(D_METHOD("_arrive", "acceleration", "target_position"), &GSAIArrive::_arrive);
ClassDB::bind_method(D_METHOD("_calculate_steering", "acceleration"), &GSAIArrive::_calculate_steering);
}

View File

@ -0,0 +1,47 @@
#ifndef GSAIARRIVE_H
#define GSAIARRIVE_H
class GSAIArrive : public GSAISteeringBehavior {
GDCLASS(GSAIArrive, GSAISteeringBehavior);
public:
GSAIAgentLocation get_*target();
void set_*target(const GSAIAgentLocation &val);
float get_arrival_tolerance() const;
void set_arrival_tolerance(const float val);
float get_deceleration_radius() const;
void set_deceleration_radius(const float val);
float get_time_to_reach() const;
void set_time_to_reach(const float val);
void arrive(const GSAITargetAcceleration &acceleration, const Vector3 &target_position);
void _arrive(const GSAITargetAcceleration &acceleration, const Vector3 &target_position);
void _calculate_steering(const GSAITargetAcceleration &acceleration);
GSAIArrive();
~GSAIArrive();
protected:
static void _bind_methods();
// Calculates acceleration to take an agent to its target's location. The
// calculation attempts to arrive with zero remaining velocity.
// @category - Individual behaviors
// Target agent to arrive to.
GSAIAgentLocation *target;
// Distance from the target for the agent to be considered successfully
// arrived.
float arrival_tolerance = 0.0;
// Distance from the target for the agent to begin slowing down.
float deceleration_radius = 0.0;
// Represents the time it takes to change acceleration.
float time_to_reach = 0.1;
};
#endif

View File

@ -0,0 +1,198 @@
#include "gsaiavoidcollisions.h"
GSAISteeringAgent GSAIAvoidCollisions::get_*_first_neighbor() {
return *_first_neighbor;
}
void GSAIAvoidCollisions::set_*_first_neighbor(const GSAISteeringAgent &val) {
*_first_neighbor = val;
}
float GSAIAvoidCollisions::get__shortest_time() const {
return _shortest_time;
}
void GSAIAvoidCollisions::set__shortest_time(const float val) {
_shortest_time = val;
}
float GSAIAvoidCollisions::get__first_minimum_separation() const {
return _first_minimum_separation;
}
void GSAIAvoidCollisions::set__first_minimum_separation(const float val) {
_first_minimum_separation = val;
}
float GSAIAvoidCollisions::get__first_distance() const {
return _first_distance;
}
void GSAIAvoidCollisions::set__first_distance(const float val) {
_first_distance = val;
}
Vector3 GSAIAvoidCollisions::get__first_relative_position() {
return _first_relative_position;
}
void GSAIAvoidCollisions::set__first_relative_position(const Vector3 &val) {
_first_relative_position = val;
}
Vector3 GSAIAvoidCollisions::get__first_relative_velocity() {
return _first_relative_velocity;
}
void GSAIAvoidCollisions::set__first_relative_velocity(const Vector3 &val) {
_first_relative_velocity = val;
}
// 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 = ;
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);
if (neighbor_count == 0 || not _first_neighbor) {
acceleration.set_zero();
}
else {
if ((_first_minimum_separation <= 0 || _first_distance < agent.bounding_radius + _first_neighbor.bounding_radius)) {
acceleration.linear = _first_neighbor.position - agent.position;
}
else {
acceleration.linear = (_first_relative_position+ (_first_relative_velocity * _shortest_time));
}
}
acceleration.linear = (acceleration.linear.normalized() * -agent.linear_acceleration_max);
acceleration.angular = 0;
}
// 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;
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();
if (relative_speed_squared == 0) {
return false;
}
else {
float time_to_collision = -relative_position.dot(relative_velocity) / relative_speed_squared;
if (time_to_collision <= 0 || time_to_collision >= _shortest_time) {
return false;
}
else {
Variant = relative_position.length();
float minimum_separation = (distance - sqrt(relative_speed_squared) * time_to_collision);
if (minimum_separation > agent.bounding_radius + neighbor.bounding_radius) {
return false;
}
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;
}
}
}
}
}
GSAIAvoidCollisions::GSAIAvoidCollisions() {
*_first_neighbor;
_shortest_time = 0.0;
_first_minimum_separation = 0.0;
_first_distance = 0.0;
_first_relative_position = ;
_first_relative_velocity = ;
}
GSAIAvoidCollisions::~GSAIAvoidCollisions() {
}
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");
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");
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");
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");
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");
ClassDB::bind_method(D_METHOD("_calculate_steering", "acceleration"), &GSAIAvoidCollisions::_calculate_steering);
ClassDB::bind_method(D_METHOD("_report_neighbor", "neighbor"), &GSAIAvoidCollisions::_report_neighbor);
}

View File

@ -0,0 +1,52 @@
#ifndef GSAIAVOIDCOLLISIONS_H
#define GSAIAVOIDCOLLISIONS_H
class GSAIAvoidCollisions : public GSAIGroupBehavior {
GDCLASS(GSAIAvoidCollisions, GSAIGroupBehavior);
public:
GSAISteeringAgent get_*_first_neighbor();
void set_*_first_neighbor(const GSAISteeringAgent &val);
float get__shortest_time() const;
void set__shortest_time(const float val);
float get__first_minimum_separation() const;
void set__first_minimum_separation(const float val);
float get__first_distance() const;
void set__first_distance(const float val);
Vector3 get__first_relative_position();
void set__first_relative_position(const Vector3 &val);
Vector3 get__first_relative_velocity();
void set__first_relative_velocity(const Vector3 &val);
void _calculate_steering(const GSAITargetAcceleration &acceleration);
bool _report_neighbor(const GSAISteeringAgent &neighbor);
GSAIAvoidCollisions();
~GSAIAvoidCollisions();
protected:
static void _bind_methods();
// 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 = ;
// 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
};
#endif

View File

@ -0,0 +1,126 @@
#include "gsaiblend.h"
Array GSAIBlend::get__behaviors() {
return _behaviors;
}
void GSAIBlend::set__behaviors(const Array &val) {
_behaviors = val;
}
GSAITargetAcceleration GSAIBlend::get_*_accel() {
return *_accel;
}
void GSAIBlend::set_*_accel(const GSAITargetAcceleration &val) {
*_accel = val;
}
// Blends multiple steering behaviors into one, and returns a weighted;
// acceleration from their calculations.;
//;
// Stores the behaviors internally as dictionaries of the form;
// {;
// behavior : GSAISteeringBehavior,;
// weight : float;
// };
// @category - Combination behaviors;
Array _behaviors = Array();
GSAITargetAcceleration *_accel = GSAITargetAcceleration.new();
// Appends a behavior to the internal array along with its `weight`.;
void GSAIBlend::add_behavior(const GSAISteeringBehavior &behavior, const float weight) {
behavior.agent = agent;
Dictionary dict = Dictionary();
dict["behavior"] = behavior;
dict["weight"] = weight;
_behaviors.append(dict);
}
// Returns the behavior at the specified `index`, or an empty `Dictionary` if;
// none was found.;
Dictionary GSAIBlend::get_behavior(const int index) {
if (_behaviors.size() > index) {
return _behaviors[index];
}
printerr("Tried to get index " + str(index) + " in array of size " + str(_behaviors.size()));
return Dictionary();
}
void GSAIBlend::remove_behavior(const int index) {
if (_behaviors.size() > index) {
_behaviors.remove(index);
return;
}
printerr("Tried to get index " + str(index) + " in array of size " + str(_behaviors.size()));
return;
}
int GSAIBlend::get_behaviour_count() {
return _behaviors.size();
}
GSAITargetAcceleration GSAIBlend::get_accel() {
return _accel;
}
void GSAIBlend::_calculate_steering(const GSAITargetAcceleration &blended_accel) {
blended_accel.set_zero();
for (int i = 0; i < _behaviors.size(); ++i) { //i in range(_behaviors.size())
Dictionary bw = _behaviors[i];
bw.behavior.calculate_steering(_accel);
blended_accel.add_scaled_accel(_accel, bw.weight);
}
blended_accel.linear = GSAIUtils.clampedv3(blended_accel.linear, agent.linear_acceleration_max);
blended_accel.angular = clamp(blended_accel.angular, -agent.angular_acceleration_max, agent.angular_acceleration_max);
}
}
GSAIBlend::GSAIBlend() {
_behaviors = Array();
*_accel = GSAITargetAcceleration.new();
}
GSAIBlend::~GSAIBlend() {
}
static void GSAIBlend::_bind_methods() {
ClassDB::bind_method(D_METHOD("get__behaviors"), &GSAIBlend::get__behaviors);
ClassDB::bind_method(D_METHOD("set__behaviors", "value"), &GSAIBlend::set__behaviors);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_behaviors"), "set__behaviors", "get__behaviors");
ClassDB::bind_method(D_METHOD("get_*_accel"), &GSAIBlend::get_*_accel);
ClassDB::bind_method(D_METHOD("set_*_accel", "value"), &GSAIBlend::set_*_accel);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*_accel", PROPERTY_HINT_RESOURCE_TYPE, "GSAITargetAcceleration"), "set_*_accel", "get_*_accel");
ClassDB::bind_method(D_METHOD("add_behavior", "behavior", "weight"), &GSAIBlend::add_behavior);
ClassDB::bind_method(D_METHOD("get_behavior", "index"), &GSAIBlend::get_behavior);
ClassDB::bind_method(D_METHOD("remove_behavior", "index"), &GSAIBlend::remove_behavior);
ClassDB::bind_method(D_METHOD("get_behaviour_count"), &GSAIBlend::get_behaviour_count);
ClassDB::bind_method(D_METHOD("get_accel"), &GSAIBlend::get_accel);
ClassDB::bind_method(D_METHOD("_calculate_steering", "blended_accel"), &GSAIBlend::_calculate_steering);
}

View File

@ -0,0 +1,46 @@
#ifndef GSAIBLEND_H
#define GSAIBLEND_H
class GSAIBlend : public GSAISteeringBehavior {
GDCLASS(GSAIBlend, GSAISteeringBehavior);
public:
Array get__behaviors();
void set__behaviors(const Array &val);
GSAITargetAcceleration get_*_accel();
void set_*_accel(const GSAITargetAcceleration &val);
void add_behavior(const GSAISteeringBehavior &behavior, const float weight);
Dictionary get_behavior(const int index);
void remove_behavior(const int index);
int get_behaviour_count();
GSAITargetAcceleration get_accel();
void _calculate_steering(const GSAITargetAcceleration &blended_accel);
GSAIBlend();
~GSAIBlend();
protected:
static void _bind_methods();
// Blends multiple steering behaviors into one, and returns a weighted
// acceleration from their calculations.
//
// Stores the behaviors internally as dictionaries of the form
// {
// behavior : GSAISteeringBehavior,
// weight : float
// }
// @category - Combination behaviors
Array _behaviors = Array();
GSAITargetAcceleration *_accel = GSAITargetAcceleration.new();
// Appends a behavior to the internal array along with its `weight`.
// Returns the behavior at the specified `index`, or an empty `Dictionary` if
// none was found.
};
#endif

View File

@ -0,0 +1,63 @@
#include "gsaicohesion.h"
Vector3 GSAICohesion::get__center_of_mass() {
return _center_of_mass;
}
void GSAICohesion::set__center_of_mass(const Vector3 &val) {
_center_of_mass = val;
}
// Calculates an acceleration that attempts to move the agent towards the center;
// of mass of the agents in the area defined by the `GSAIProximity`.;
// @category - Group behaviors;
Vector3 _center_of_mass = ;
void GSAICohesion::_calculate_steering(const GSAITargetAcceleration &acceleration) {
acceleration.set_zero();
_center_of_mass = Vector3.ZERO;
Variant = proximity.find_neighbors(_callback);
if (neighbor_count > 0) {
_center_of_mass *= 1.0 / neighbor_count;
acceleration.linear = ((_center_of_mass - agent.position).normalized() * agent.linear_acceleration_max);
}
// Callback for the proximity to call when finding neighbors. Adds `neighbor`'s position;
// to the center of mass of the group.;
// @tags - virtual;
}
bool GSAICohesion::_report_neighbor(const GSAISteeringAgent &neighbor) {
_center_of_mass += neighbor.position;
return true;
}
}
GSAICohesion::GSAICohesion() {
_center_of_mass = ;
}
GSAICohesion::~GSAICohesion() {
}
static void GSAICohesion::_bind_methods() {
ClassDB::bind_method(D_METHOD("get__center_of_mass"), &GSAICohesion::get__center_of_mass);
ClassDB::bind_method(D_METHOD("set__center_of_mass", "value"), &GSAICohesion::set__center_of_mass);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "_center_of_mass"), "set__center_of_mass", "get__center_of_mass");
ClassDB::bind_method(D_METHOD("_calculate_steering", "acceleration"), &GSAICohesion::_calculate_steering);
ClassDB::bind_method(D_METHOD("_report_neighbor", "neighbor"), &GSAICohesion::_report_neighbor);
}

View File

@ -0,0 +1,29 @@
#ifndef GSAICOHESION_H
#define GSAICOHESION_H
class GSAICohesion : public GSAIGroupBehavior {
GDCLASS(GSAICohesion, GSAIGroupBehavior);
public:
Vector3 get__center_of_mass();
void set__center_of_mass(const Vector3 &val);
void _calculate_steering(const GSAITargetAcceleration &acceleration);
bool _report_neighbor(const GSAISteeringAgent &neighbor);
GSAICohesion();
~GSAICohesion();
protected:
static void _bind_methods();
// Calculates an acceleration that attempts to move the agent towards the center
// of mass of the agents in the area defined by the `GSAIProximity`.
// @category - Group behaviors
Vector3 _center_of_mass = ;
};
#endif

View File

@ -0,0 +1,29 @@
#include "gsaievade.h"
// Calculates acceleration to take an agent away from where a target agent is;
// moving.;
// @category - Individual behaviors;
float GSAIEvade::_get_modified_acceleration() {
return -agent.linear_acceleration_max;
}
}
GSAIEvade::GSAIEvade() {
}
GSAIEvade::~GSAIEvade() {
}
static void GSAIEvade::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_modified_acceleration"), &GSAIEvade::_get_modified_acceleration);
}

View File

@ -0,0 +1,24 @@
#ifndef GSAIEVADE_H
#define GSAIEVADE_H
class GSAIEvade : public GSAIPursue {
GDCLASS(GSAIEvade, GSAIPursue);
public:
float _get_modified_acceleration();
GSAIEvade();
~GSAIEvade();
protected:
static void _bind_methods();
// Calculates acceleration to take an agent away from where a target agent is
// moving.
// @category - Individual behaviors
};
#endif

View File

@ -0,0 +1,63 @@
#include "gsaiface.h"
// Calculates angular acceleration to rotate a target to face its target's;
// position. The behavior attemps to arrive with zero remaining angular velocity.;
// @category - Individual behaviors;
void GSAIFace::face(const GSAITargetAcceleration &acceleration, const Vector3 &target_position) {
call("_face", acceleration, target_position);
}
void GSAIFace::_face(const GSAITargetAcceleration &acceleration, const Vector3 &target_position) {
Vector3 to_target = target_position - agent.position;
float distance_squared = to_target.length_squared();
if (distance_squared < agent.zero_linear_speed_threshold) {
acceleration.set_zero();
}
else {
float orientation = ;
if (use_z) {
orientation = GSAIUtils.vector3_to_angle(to_target);
}
else {
orientation = GSAIUtils.vector2_to_angle(GSAIUtils.to_vector2(to_target));
}
match_orientation(acceleration, orientation);
}
}
void GSAIFace::_calculate_steering(const GSAITargetAcceleration &acceleration) {
face(acceleration, target.position);
}
}
GSAIFace::GSAIFace() {
}
GSAIFace::~GSAIFace() {
}
static void GSAIFace::_bind_methods() {
ClassDB::bind_method(D_METHOD("face", "acceleration", "target_position"), &GSAIFace::face);
ClassDB::bind_method(D_METHOD("_face", "acceleration", "target_position"), &GSAIFace::_face);
ClassDB::bind_method(D_METHOD("_calculate_steering", "acceleration"), &GSAIFace::_calculate_steering);
}

View File

@ -0,0 +1,26 @@
#ifndef GSAIFACE_H
#define GSAIFACE_H
class GSAIFace : public GSAIMatchOrientation {
GDCLASS(GSAIFace, GSAIMatchOrientation);
public:
void face(const GSAITargetAcceleration &acceleration, const Vector3 &target_position);
void _face(const GSAITargetAcceleration &acceleration, const Vector3 &target_position);
void _calculate_steering(const GSAITargetAcceleration &acceleration);
GSAIFace();
~GSAIFace();
protected:
static void _bind_methods();
// Calculates angular acceleration to rotate a target to face its target's
// position. The behavior attemps to arrive with zero remaining angular velocity.
// @category - Individual behaviors
};
#endif

View File

@ -0,0 +1,29 @@
#include "gsaiflee.h"
// Calculates acceleration to take an agent directly away from a target agent.;
// @category - Individual behaviors;
void GSAIFlee::_calculate_steering(const GSAITargetAcceleration &acceleration) {
acceleration.linear = ((agent.position - target.position).normalized() * agent.linear_acceleration_max);
acceleration.angular = 0;
}
}
GSAIFlee::GSAIFlee() {
}
GSAIFlee::~GSAIFlee() {
}
static void GSAIFlee::_bind_methods() {
ClassDB::bind_method(D_METHOD("_calculate_steering", "acceleration"), &GSAIFlee::_calculate_steering);
}

View File

@ -0,0 +1,23 @@
#ifndef GSAIFLEE_H
#define GSAIFLEE_H
class GSAIFlee : public GSAISeek {
GDCLASS(GSAIFlee, GSAISeek);
public:
void _calculate_steering(const GSAITargetAcceleration &acceleration);
GSAIFlee();
~GSAIFlee();
protected:
static void _bind_methods();
// Calculates acceleration to take an agent directly away from a target agent.
// @category - Individual behaviors
};
#endif

View File

@ -0,0 +1,146 @@
#include "gsaifollowpath.h"
GSAIPath GSAIFollowPath::get_*path() {
return *path;
}
void GSAIFollowPath::set_*path(const GSAIPath &val) {
*path = val;
}
float GSAIFollowPath::get_path_offset() const {
return path_offset;
}
void GSAIFollowPath::set_path_offset(const float val) {
path_offset = val;
}
bool GSAIFollowPath::get_is_arrive_enabled() const {
return is_arrive_enabled;
}
void GSAIFollowPath::set_is_arrive_enabled(const bool val) {
is_arrive_enabled = val;
}
float GSAIFollowPath::get_prediction_time() const {
return prediction_time;
}
void GSAIFollowPath::set_prediction_time(const float val) {
prediction_time = val;
}
// Produces a linear acceleration that moves the agent along the specified path.;
// @category - Individual behaviors;
// The path to follow and travel along.;
GSAIPath *path;
// The distance along the path to generate the next target position.;
float path_offset = 0.0;
// Whether to use `GSAIArrive` behavior on an open path.;
bool is_arrive_enabled = true;
// The amount of time in the future to predict the owning agent's position along;
// the path. Setting it to 0.0 will force non-predictive path following.;
float prediction_time = 0.0;
void GSAIFollowPath::_calculate_steering(const GSAITargetAcceleration &acceleration) {
Vector3 location = ;
if (prediction_time == 0) {
location = agent.position;
}
else {
location = agent.position + (agent.linear_velocity * prediction_time);
}
float distance = path.calculate_distance(location);
float target_distance = distance + path_offset;
if (prediction_time > 0 && path.is_open) {
if (target_distance < path.calculate_distance(agent.position)) {
target_distance = path.length;
}
}
Vector3 target_position = path.calculate_target_position(target_distance);
if (is_arrive_enabled && path.is_open) {
if (path_offset >= 0) {
if (target_distance > path.length - deceleration_radius) {
arrive(acceleration, target_position);
return;
}
}
else {
if (target_distance < deceleration_radius) {
arrive(acceleration, target_position);
return;
}
}
}
acceleration.linear = (target_position - agent.position).normalized();
acceleration.linear *= agent.linear_acceleration_max;
acceleration.angular = 0;
}
}
GSAIFollowPath::GSAIFollowPath() {
*path;
path_offset = 0.0;
is_arrive_enabled = true;
prediction_time = 0.0;
}
GSAIFollowPath::~GSAIFollowPath() {
}
static void GSAIFollowPath::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_*path"), &GSAIFollowPath::get_*path);
ClassDB::bind_method(D_METHOD("set_*path", "value"), &GSAIFollowPath::set_*path);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*path", PROPERTY_HINT_RESOURCE_TYPE, "GSAIPath"), "set_*path", "get_*path");
ClassDB::bind_method(D_METHOD("get_path_offset"), &GSAIFollowPath::get_path_offset);
ClassDB::bind_method(D_METHOD("set_path_offset", "value"), &GSAIFollowPath::set_path_offset);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "path_offset"), "set_path_offset", "get_path_offset");
ClassDB::bind_method(D_METHOD("get_is_arrive_enabled"), &GSAIFollowPath::get_is_arrive_enabled);
ClassDB::bind_method(D_METHOD("set_is_arrive_enabled", "value"), &GSAIFollowPath::set_is_arrive_enabled);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_arrive_enabled"), "set_is_arrive_enabled", "get_is_arrive_enabled");
ClassDB::bind_method(D_METHOD("get_prediction_time"), &GSAIFollowPath::get_prediction_time);
ClassDB::bind_method(D_METHOD("set_prediction_time", "value"), &GSAIFollowPath::set_prediction_time);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "prediction_time"), "set_prediction_time", "get_prediction_time");
ClassDB::bind_method(D_METHOD("_calculate_steering", "acceleration"), &GSAIFollowPath::_calculate_steering);
}

View File

@ -0,0 +1,44 @@
#ifndef GSAIFOLLOWPATH_H
#define GSAIFOLLOWPATH_H
class GSAIFollowPath : public GSAIArrive {
GDCLASS(GSAIFollowPath, GSAIArrive);
public:
GSAIPath get_*path();
void set_*path(const GSAIPath &val);
float get_path_offset() const;
void set_path_offset(const float val);
bool get_is_arrive_enabled() const;
void set_is_arrive_enabled(const bool val);
float get_prediction_time() const;
void set_prediction_time(const float val);
void _calculate_steering(const GSAITargetAcceleration &acceleration);
GSAIFollowPath();
~GSAIFollowPath();
protected:
static void _bind_methods();
// Produces a linear acceleration that moves the agent along the specified path.
// @category - Individual behaviors
// The path to follow and travel along.
GSAIPath *path;
// The distance along the path to generate the next target position.
float path_offset = 0.0;
// Whether to use `GSAIArrive` behavior on an open path.
bool is_arrive_enabled = true;
// The amount of time in the future to predict the owning agent's position along
// the path. Setting it to 0.0 will force non-predictive path following.
float prediction_time = 0.0;
};
#endif

View File

@ -0,0 +1,49 @@
#include "gsailookwhereyougo.h"
// Calculates an angular acceleration to match an agent's orientation to its;
// direction of travel.;
// @category - Individual behaviors;
void GSAILookWhereYouGo::_calculate_steering(const GSAITargetAcceleration &accel) {
if (agent.linear_velocity.length_squared() < agent.zero_linear_speed_threshold) {
accel.set_zero();
}
else {
float orientation = ;
if (use_z) {
orientation = GSAIUtils.vector3_to_angle(agent.linear_velocity);
}
else {
orientation = GSAIUtils.vector2_to_angle(GSAIUtils.to_vector2(agent.linear_velocity));
}
match_orientation(accel, orientation);
}
}
}
GSAILookWhereYouGo::GSAILookWhereYouGo() {
}
GSAILookWhereYouGo::~GSAILookWhereYouGo() {
}
static void GSAILookWhereYouGo::_bind_methods() {
ClassDB::bind_method(D_METHOD("_calculate_steering", "accel"), &GSAILookWhereYouGo::_calculate_steering);
}

View File

@ -0,0 +1,24 @@
#ifndef GSAILOOKWHEREYOUGO_H
#define GSAILOOKWHEREYOUGO_H
class GSAILookWhereYouGo : public GSAIMatchOrientation {
GDCLASS(GSAILookWhereYouGo, GSAIMatchOrientation);
public:
void _calculate_steering(const GSAITargetAcceleration &accel);
GSAILookWhereYouGo();
~GSAILookWhereYouGo();
protected:
static void _bind_methods();
// Calculates an angular acceleration to match an agent's orientation to its
// direction of travel.
// @category - Individual behaviors
};
#endif

View File

@ -0,0 +1,154 @@
#include "gsaimatchorientation.h"
GSAIAgentLocation GSAIMatchOrientation::get_*target() {
return *target;
}
void GSAIMatchOrientation::set_*target(const GSAIAgentLocation &val) {
*target = val;
}
float GSAIMatchOrientation::get_alignment_tolerance() const {
return alignment_tolerance;
}
void GSAIMatchOrientation::set_alignment_tolerance(const float val) {
alignment_tolerance = val;
}
float GSAIMatchOrientation::get_deceleration_radius() const {
return deceleration_radius;
}
void GSAIMatchOrientation::set_deceleration_radius(const float val) {
deceleration_radius = val;
}
float GSAIMatchOrientation::get_time_to_reach() const {
return time_to_reach;
}
void GSAIMatchOrientation::set_time_to_reach(const float val) {
time_to_reach = val;
}
bool GSAIMatchOrientation::get_use_z() const {
return use_z;
}
void GSAIMatchOrientation::set_use_z(const bool val) {
use_z = val;
}
// Calculates an angular acceleration to match an agent's orientation to that of;
// its target. Attempts to make the agent arrive with zero remaining angular;
// velocity.;
// @category - Individual behaviors;
// The target orientation for the behavior to try and match rotations to.;
GSAIAgentLocation *target;
// The amount of distance in radians for the behavior to consider itself close;
// enough to be matching the target agent's rotation.;
float alignment_tolerance = 0.0;
// The amount of distance in radians from the goal to start slowing down.;
float deceleration_radius = 0.0;
// The amount of time to reach the target velocity;
float time_to_reach = 0.1;
// Whether to use the X and Z components instead of X and Y components when;
// determining angles. X and Z should be used in 3D.;
bool use_z = false;
void GSAIMatchOrientation::match_orientation(const GSAITargetAcceleration &acceleration, const float desired_orientation) {
call("_match_orientation", acceleration, desired_orientation);
}
void GSAIMatchOrientation::_match_orientation(const GSAITargetAcceleration &acceleration, const float desired_orientation) {
float rotation = wrapf(desired_orientation - agent.orientation, -PI, PI);
float rotation_size = abs(rotation);
if (rotation_size <= alignment_tolerance) {
acceleration.set_zero();
}
else {
float desired_rotation = agent.angular_speed_max;
if (rotation_size <= deceleration_radius) {
desired_rotation *= rotation_size / deceleration_radius;
}
desired_rotation *= rotation / rotation_size;
acceleration.angular = ((desired_rotation - agent.angular_velocity) / time_to_reach);
float limited_acceleration = abs(acceleration.angular);
if (limited_acceleration > agent.angular_acceleration_max) {
acceleration.angular *= (agent.angular_acceleration_max / limited_acceleration);
}
}
acceleration.linear = Vector3.ZERO;
}
void GSAIMatchOrientation::_calculate_steering(const GSAITargetAcceleration &acceleration) {
match_orientation(acceleration, target.orientation);
}
}
GSAIMatchOrientation::GSAIMatchOrientation() {
*target;
alignment_tolerance = 0.0;
deceleration_radius = 0.0;
time_to_reach = 0.1;
use_z = false;
}
GSAIMatchOrientation::~GSAIMatchOrientation() {
}
static void GSAIMatchOrientation::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_*target"), &GSAIMatchOrientation::get_*target);
ClassDB::bind_method(D_METHOD("set_*target", "value"), &GSAIMatchOrientation::set_*target);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*target", PROPERTY_HINT_RESOURCE_TYPE, "GSAIAgentLocation"), "set_*target", "get_*target");
ClassDB::bind_method(D_METHOD("get_alignment_tolerance"), &GSAIMatchOrientation::get_alignment_tolerance);
ClassDB::bind_method(D_METHOD("set_alignment_tolerance", "value"), &GSAIMatchOrientation::set_alignment_tolerance);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "alignment_tolerance"), "set_alignment_tolerance", "get_alignment_tolerance");
ClassDB::bind_method(D_METHOD("get_deceleration_radius"), &GSAIMatchOrientation::get_deceleration_radius);
ClassDB::bind_method(D_METHOD("set_deceleration_radius", "value"), &GSAIMatchOrientation::set_deceleration_radius);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "deceleration_radius"), "set_deceleration_radius", "get_deceleration_radius");
ClassDB::bind_method(D_METHOD("get_time_to_reach"), &GSAIMatchOrientation::get_time_to_reach);
ClassDB::bind_method(D_METHOD("set_time_to_reach", "value"), &GSAIMatchOrientation::set_time_to_reach);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "time_to_reach"), "set_time_to_reach", "get_time_to_reach");
ClassDB::bind_method(D_METHOD("get_use_z"), &GSAIMatchOrientation::get_use_z);
ClassDB::bind_method(D_METHOD("set_use_z", "value"), &GSAIMatchOrientation::set_use_z);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_z"), "set_use_z", "get_use_z");
ClassDB::bind_method(D_METHOD("match_orientation", "acceleration", "desired_orientation"), &GSAIMatchOrientation::match_orientation);
ClassDB::bind_method(D_METHOD("_match_orientation", "acceleration", "desired_orientation"), &GSAIMatchOrientation::_match_orientation);
ClassDB::bind_method(D_METHOD("_calculate_steering", "acceleration"), &GSAIMatchOrientation::_calculate_steering);
}

View File

@ -0,0 +1,54 @@
#ifndef GSAIMATCHORIENTATION_H
#define GSAIMATCHORIENTATION_H
class GSAIMatchOrientation : public GSAISteeringBehavior {
GDCLASS(GSAIMatchOrientation, GSAISteeringBehavior);
public:
GSAIAgentLocation get_*target();
void set_*target(const GSAIAgentLocation &val);
float get_alignment_tolerance() const;
void set_alignment_tolerance(const float val);
float get_deceleration_radius() const;
void set_deceleration_radius(const float val);
float get_time_to_reach() const;
void set_time_to_reach(const float val);
bool get_use_z() const;
void set_use_z(const bool val);
void match_orientation(const GSAITargetAcceleration &acceleration, const float desired_orientation);
void _match_orientation(const GSAITargetAcceleration &acceleration, const float desired_orientation);
void _calculate_steering(const GSAITargetAcceleration &acceleration);
GSAIMatchOrientation();
~GSAIMatchOrientation();
protected:
static void _bind_methods();
// Calculates an angular acceleration to match an agent's orientation to that of
// its target. Attempts to make the agent arrive with zero remaining angular
// velocity.
// @category - Individual behaviors
// The target orientation for the behavior to try and match rotations to.
GSAIAgentLocation *target;
// The amount of distance in radians for the behavior to consider itself close
// enough to be matching the target agent's rotation.
float alignment_tolerance = 0.0;
// The amount of distance in radians from the goal to start slowing down.
float deceleration_radius = 0.0;
// The amount of time to reach the target velocity
float time_to_reach = 0.1;
// Whether to use the X and Z components instead of X and Y components when
// determining angles. X and Z should be used in 3D.
bool use_z = false;
};
#endif

View File

@ -0,0 +1,143 @@
#include "gsaipriority.h"
float GSAIPriority::get_zero_threshold() const {
return zero_threshold;
}
void GSAIPriority::set_zero_threshold(const float val) {
zero_threshold = val;
}
int GSAIPriority::get__last_selected_index() const {
return _last_selected_index;
}
void GSAIPriority::set__last_selected_index(const int val) {
_last_selected_index = val;
}
Array GSAIPriority::get__behaviors() {
return _behaviors;
}
void GSAIPriority::set__behaviors(const Array &val) {
_behaviors = val;
}
// Container for multiple behaviors that returns the result of the first child;
// behavior with non-zero acceleration.;
// @category - Combination behaviors;
// If a behavior's acceleration is lower than this threshold, the container;
// considers it has an acceleration of zero.;
float zero_threshold = 0.0;
// The index of the last behavior the container prioritized.;
int _last_selected_index = 0;
Array _behaviors = Array();
// Appends a steering behavior as a child of this container.;
void GSAIPriority::add_behavior(const GSAISteeringBehavior &behavior) {
_behaviors.append(behavior);
}
// Returns the behavior at the position in the pool referred to by `index`, or;
// `null` if no behavior was found.;
GSAISteeringBehavior GSAIPriority::get_behavior(const int index) {
if (_behaviors.size() > index) {
return _behaviors[index];
}
printerr("Tried to get index " + str(index) + " in array of size " + str(_behaviors.size()));
return null;
}
void GSAIPriority::remove_behavior(const int index) {
if (_behaviors.size() > index) {
_behaviors.remove(index);
return;
}
printerr("Tried to get index " + str(index) + " in array of size " + str(_behaviors.size()));
return;
}
int GSAIPriority::get_behaviour_count() {
return _behaviors.size();
}
void GSAIPriority::_calculate_steering(const GSAITargetAcceleration &accel) {
float threshold_squared = zero_threshold * zero_threshold;
_last_selected_index = -1;
int size = _behaviors.size();
if (size > 0) {
for (int i = 0; i < size; ++i) { //i in range(size)
_last_selected_index = i;
GSAISteeringBehavior *behavior = _behaviors[i];
behavior.calculate_steering(accel);
if (accel.get_magnitude_squared() > threshold_squared) {
break;
}
}
}
else {
accel.set_zero();
}
}
}
GSAIPriority::GSAIPriority() {
zero_threshold = 0.0;
_last_selected_index = 0;
_behaviors = Array();
}
GSAIPriority::~GSAIPriority() {
}
static void GSAIPriority::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_zero_threshold"), &GSAIPriority::get_zero_threshold);
ClassDB::bind_method(D_METHOD("set_zero_threshold", "value"), &GSAIPriority::set_zero_threshold);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "zero_threshold"), "set_zero_threshold", "get_zero_threshold");
ClassDB::bind_method(D_METHOD("get__last_selected_index"), &GSAIPriority::get__last_selected_index);
ClassDB::bind_method(D_METHOD("set__last_selected_index", "value"), &GSAIPriority::set__last_selected_index);
ADD_PROPERTY(PropertyInfo(Variant::INT, "_last_selected_index"), "set__last_selected_index", "get__last_selected_index");
ClassDB::bind_method(D_METHOD("get__behaviors"), &GSAIPriority::get__behaviors);
ClassDB::bind_method(D_METHOD("set__behaviors", "value"), &GSAIPriority::set__behaviors);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_behaviors"), "set__behaviors", "get__behaviors");
ClassDB::bind_method(D_METHOD("add_behavior", "behavior"), &GSAIPriority::add_behavior);
ClassDB::bind_method(D_METHOD("get_behavior", "index"), &GSAIPriority::get_behavior);
ClassDB::bind_method(D_METHOD("remove_behavior", "index"), &GSAIPriority::remove_behavior);
ClassDB::bind_method(D_METHOD("get_behaviour_count"), &GSAIPriority::get_behaviour_count);
ClassDB::bind_method(D_METHOD("_calculate_steering", "accel"), &GSAIPriority::_calculate_steering);
}

View File

@ -0,0 +1,46 @@
#ifndef GSAIPRIORITY_H
#define GSAIPRIORITY_H
class GSAIPriority : public GSAISteeringBehavior {
GDCLASS(GSAIPriority, GSAISteeringBehavior);
public:
float get_zero_threshold() const;
void set_zero_threshold(const float val);
int get__last_selected_index() const;
void set__last_selected_index(const int val);
Array get__behaviors();
void set__behaviors(const Array &val);
void add_behavior(const GSAISteeringBehavior &behavior);
GSAISteeringBehavior get_behavior(const int index);
void remove_behavior(const int index);
int get_behaviour_count();
void _calculate_steering(const GSAITargetAcceleration &accel);
GSAIPriority();
~GSAIPriority();
protected:
static void _bind_methods();
// Container for multiple behaviors that returns the result of the first child
// behavior with non-zero acceleration.
// @category - Combination behaviors
// If a behavior's acceleration is lower than this threshold, the container
// considers it has an acceleration of zero.
float zero_threshold = 0.0;
// The index of the last behavior the container prioritized.
int _last_selected_index = 0;
Array _behaviors = Array();
// Appends a steering behavior as a child of this container.
// Returns the behavior at the position in the pool referred to by `index`, or
// `null` if no behavior was found.
};
#endif

View File

@ -0,0 +1,92 @@
#include "gsaipursue.h"
GSAISteeringAgent GSAIPursue::get_*target() {
return *target;
}
void GSAIPursue::set_*target(const GSAISteeringAgent &val) {
*target = val;
}
float GSAIPursue::get_predict_time_max() const {
return predict_time_max;
}
void GSAIPursue::set_predict_time_max(const float val) {
predict_time_max = val;
}
// Calculates an acceleration to make an agent intercept another based on the;
// target agent's movement.;
// @category - Individual behaviors;
// The target agent that the behavior is trying to intercept.;
GSAISteeringAgent *target;
// The maximum amount of time in the future the behavior predicts the target's;
// location.;
float predict_time_max = 1.0;
void GSAIPursue::_calculate_steering(const GSAITargetAcceleration &acceleration) {
Vector3 target_position = target.position;
float distance_squared = (target_position - agent.position).length_squared();
float speed_squared = agent.linear_velocity.length_squared();
float predict_time = predict_time_max;
if (speed_squared > 0) {
Variant predict_time_squared = distance_squared / speed_squared;
if (predict_time_squared < predict_time_max * predict_time_max) {
predict_time = sqrt(predict_time_squared);
}
}
acceleration.linear = ((target_position + (target.linear_velocity * predict_time)) - agent.position).normalized();
acceleration.linear *= get_modified_acceleration();
acceleration.angular = 0;
}
float GSAIPursue::get_modified_acceleration() {
return call("_get_modified_acceleration");
}
float GSAIPursue::_get_modified_acceleration() {
return agent.linear_acceleration_max;
}
}
GSAIPursue::GSAIPursue() {
*target;
predict_time_max = 1.0;
}
GSAIPursue::~GSAIPursue() {
}
static void GSAIPursue::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_*target"), &GSAIPursue::get_*target);
ClassDB::bind_method(D_METHOD("set_*target", "value"), &GSAIPursue::set_*target);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*target", PROPERTY_HINT_RESOURCE_TYPE, "GSAISteeringAgent"), "set_*target", "get_*target");
ClassDB::bind_method(D_METHOD("get_predict_time_max"), &GSAIPursue::get_predict_time_max);
ClassDB::bind_method(D_METHOD("set_predict_time_max", "value"), &GSAIPursue::set_predict_time_max);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "predict_time_max"), "set_predict_time_max", "get_predict_time_max");
ClassDB::bind_method(D_METHOD("_calculate_steering", "acceleration"), &GSAIPursue::_calculate_steering);
ClassDB::bind_method(D_METHOD("get_modified_acceleration"), &GSAIPursue::get_modified_acceleration);
ClassDB::bind_method(D_METHOD("_get_modified_acceleration"), &GSAIPursue::_get_modified_acceleration);
}

View File

@ -0,0 +1,37 @@
#ifndef GSAIPURSUE_H
#define GSAIPURSUE_H
class GSAIPursue : public GSAISteeringBehavior {
GDCLASS(GSAIPursue, GSAISteeringBehavior);
public:
GSAISteeringAgent get_*target();
void set_*target(const GSAISteeringAgent &val);
float get_predict_time_max() const;
void set_predict_time_max(const float val);
void _calculate_steering(const GSAITargetAcceleration &acceleration);
float get_modified_acceleration();
float _get_modified_acceleration();
GSAIPursue();
~GSAIPursue();
protected:
static void _bind_methods();
// Calculates an acceleration to make an agent intercept another based on the
// target agent's movement.
// @category - Individual behaviors
// The target agent that the behavior is trying to intercept.
GSAISteeringAgent *target;
// The maximum amount of time in the future the behavior predicts the target's
// location.
float predict_time_max = 1.0;
};
#endif

View File

@ -0,0 +1,47 @@
#include "gsaiseek.h"
GSAIAgentLocation GSAISeek::get_*target() {
return *target;
}
void GSAISeek::set_*target(const GSAIAgentLocation &val) {
*target = val;
}
// Calculates an acceleration to take an agent to a target agent's position;
// directly.;
// @category - Individual behaviors;
// The target that the behavior aims to move the agent to.;
GSAIAgentLocation *target;
void GSAISeek::_calculate_steering(const GSAITargetAcceleration &acceleration) {
acceleration.linear = ((target.position - agent.position).normalized() * agent.linear_acceleration_max);
acceleration.angular = 0;
}
}
GSAISeek::GSAISeek() {
*target;
}
GSAISeek::~GSAISeek() {
}
static void GSAISeek::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_*target"), &GSAISeek::get_*target);
ClassDB::bind_method(D_METHOD("set_*target", "value"), &GSAISeek::set_*target);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*target", PROPERTY_HINT_RESOURCE_TYPE, "GSAIAgentLocation"), "set_*target", "get_*target");
ClassDB::bind_method(D_METHOD("_calculate_steering", "acceleration"), &GSAISeek::_calculate_steering);
}

View File

@ -0,0 +1,29 @@
#ifndef GSAISEEK_H
#define GSAISEEK_H
class GSAISeek : public GSAISteeringBehavior {
GDCLASS(GSAISeek, GSAISteeringBehavior);
public:
GSAIAgentLocation get_*target();
void set_*target(const GSAIAgentLocation &val);
void _calculate_steering(const GSAITargetAcceleration &acceleration);
GSAISeek();
~GSAISeek();
protected:
static void _bind_methods();
// Calculates an acceleration to take an agent to a target agent's position
// directly.
// @category - Individual behaviors
// The target that the behavior aims to move the agent to.
GSAIAgentLocation *target;
};
#endif

View File

@ -0,0 +1,88 @@
#include "gsaiseparation.h"
float GSAISeparation::get_decay_coefficient() const {
return decay_coefficient;
}
void GSAISeparation::set_decay_coefficient(const float val) {
decay_coefficient = val;
}
GSAITargetAcceleration GSAISeparation::get_*acceleration() {
return *acceleration;
}
void GSAISeparation::set_*acceleration(const GSAITargetAcceleration &val) {
*acceleration = val;
}
// Calculates an acceleration that repels the agent from its neighbors in the;
// given `GSAIProximity`.;
//;
// The acceleration is an average based on all neighbors, multiplied by a;
// strength decreasing by the inverse square law in relation to distance, and it;
// accumulates.;
// @category - Group behaviors;
// The coefficient to calculate how fast the separation strength decays with distance.;
float decay_coefficient = 1.0;
GSAITargetAcceleration *acceleration;
void GSAISeparation::_calculate_steering(const GSAITargetAcceleration &_acceleration) {
self.acceleration = _acceleration;
acceleration.set_zero();
// warning-ignore:return_value_discarded;
proximity.find_neighbors(_callback);
}
// Callback for the proximity to call when finding neighbors. Determines the amount of;
// acceleration that `neighbor` imposes based on its distance from the owner agent.;
// @tags - virtual;
bool GSAISeparation::_report_neighbor(const GSAISteeringAgent &neighbor) {
Vector3 to_agent = agent.position - neighbor.position;
float distance_squared = to_agent.length_squared();
float acceleration_max = agent.linear_acceleration_max;
Variant strength = decay_coefficient / distance_squared;
if (strength > acceleration_max) {
strength = acceleration_max;
}
acceleration.linear += to_agent * (strength / sqrt(distance_squared));
return true;
}
}
GSAISeparation::GSAISeparation() {
decay_coefficient = 1.0;
*acceleration;
}
GSAISeparation::~GSAISeparation() {
}
static void GSAISeparation::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_decay_coefficient"), &GSAISeparation::get_decay_coefficient);
ClassDB::bind_method(D_METHOD("set_decay_coefficient", "value"), &GSAISeparation::set_decay_coefficient);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "decay_coefficient"), "set_decay_coefficient", "get_decay_coefficient");
ClassDB::bind_method(D_METHOD("get_*acceleration"), &GSAISeparation::get_*acceleration);
ClassDB::bind_method(D_METHOD("set_*acceleration", "value"), &GSAISeparation::set_*acceleration);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*acceleration", PROPERTY_HINT_RESOURCE_TYPE, "GSAITargetAcceleration"), "set_*acceleration", "get_*acceleration");
ClassDB::bind_method(D_METHOD("_calculate_steering", "_acceleration"), &GSAISeparation::_calculate_steering);
ClassDB::bind_method(D_METHOD("_report_neighbor", "neighbor"), &GSAISeparation::_report_neighbor);
}

View File

@ -0,0 +1,41 @@
#ifndef GSAISEPARATION_H
#define GSAISEPARATION_H
class GSAISeparation : public GSAIGroupBehavior {
GDCLASS(GSAISeparation, GSAIGroupBehavior);
public:
float get_decay_coefficient() const;
void set_decay_coefficient(const float val);
GSAITargetAcceleration get_*acceleration();
void set_*acceleration(const GSAITargetAcceleration &val);
void _calculate_steering(const GSAITargetAcceleration &_acceleration);
bool _report_neighbor(const GSAISteeringAgent &neighbor);
GSAISeparation();
~GSAISeparation();
protected:
static void _bind_methods();
// Calculates an acceleration that repels the agent from its neighbors in the
// given `GSAIProximity`.
//
// The acceleration is an average based on all neighbors, multiplied by a
// strength decreasing by the inverse square law in relation to distance, and it
// accumulates.
// @category - Group behaviors
// The coefficient to calculate how fast the separation strength decays with distance.
float decay_coefficient = 1.0;
GSAITargetAcceleration *acceleration;
// Callback for the proximity to call when finding neighbors. Determines the amount of
// acceleration that `neighbor` imposes based on its distance from the owner agent.
// @tags - virtual
};
#endif

View File

@ -0,0 +1,43 @@
# Exhaustive licensing information for files in the Godot Engine repository
# =========================================================================
#
# This file aims at documenting the copyright and license for every source
# file in the Godot Engine repository, and especially outline the files
# whose license differs from the MIT/Expat license used by Godot Engine.
#
# It is written as a machine-readable format following the debian/copyright
# specification. Globbing patterns (e.g. "Files: *") mean that they affect
# all corresponding files (also recursively in subfolders), apart from those
# with a more explicit copyright statement.
#
# Licenses are given with their debian/copyright short name (or SPDX identifier
# if no standard short name exists) and are all included in plain text at the
# end of this file (in alphabetical order).
#
# Disclaimer for thirdparty libraries:
# ------------------------------------
#
# Licensing details for thirdparty libraries in the 'thirdparty/' directory
# are given in summarized form, i.e. with only the "main" license described
# in the library's license statement. Different licenses of single files or
# code snippets in thirdparty libraries are not documented here.
# For example:
# Files: ./thirdparty/zlib/
# Copyright: 1995-2017, Jean-loup Gailly and Mark Adler
# License: Zlib
# The exact copyright for each file in that library *may* differ, and some
# files or code snippets might be distributed under other compatible licenses
# (e.g. a public domain dedication), but as far as Godot Engine is concerned
# the library is considered as a whole under the Zlib license.
#
# Nota: When linking dynamically against thirdparty libraries instead of
# building them into the Godot binary, you may remove the corresponding
# license details from this file.
-----------------------------------------------------------------------
Files: modules/steering_ai/*
Comment: Steering AI Module
Copyright: Copyright (c) 2023-present Péter Magyar.
Copyright (c) 2020-2023 GDQuest.
License: Expat

View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2023-present Péter Magyar
Copyright (c) 2020-2023 GDQuest
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,50 @@
#include "gsaiinfiniteproximity.h"
// Determines any agent that is in the specified list as being neighbors with the;
// owner agent, regardless of distance.;
// @category - Proximities;
// Returns a number of neighbors based on a `callback` function.;
//;
// `_find_neighbors` calls `callback` for each agent in the `agents` array and;
// adds one to the count if its `callback` returns true.;
// @tags - virtual;
int GSAIInfiniteProximity::_find_neighbors(const FuncRef &callback) {
int neighbor_count = 0;
int agent_count = agents.size();
for (int i = 0; i < agent_count; ++i) { //i in range(agent_count)
GSAISteeringAgent *current_agent = agents[i] as GSAISteeringAgent;
if (current_agent != agent) {
if (callback.call_func(current_agent)) {
neighbor_count += 1;
}
}
}
return neighbor_count;
}
}
GSAIInfiniteProximity::GSAIInfiniteProximity() {
}
GSAIInfiniteProximity::~GSAIInfiniteProximity() {
}
static void GSAIInfiniteProximity::_bind_methods() {
ClassDB::bind_method(D_METHOD("_find_neighbors", "callback"), &GSAIInfiniteProximity::_find_neighbors);
}

View File

@ -0,0 +1,29 @@
#ifndef GSAIINFINITEPROXIMITY_H
#define GSAIINFINITEPROXIMITY_H
class GSAIInfiniteProximity : public GSAIProximity {
GDCLASS(GSAIInfiniteProximity, GSAIProximity);
public:
int _find_neighbors(const FuncRef &callback);
GSAIInfiniteProximity();
~GSAIInfiniteProximity();
protected:
static void _bind_methods();
// Determines any agent that is in the specified list as being neighbors with the
// owner agent, regardless of distance.
// @category - Proximities
// Returns a number of neighbors based on a `callback` function.
//
// `_find_neighbors` calls `callback` for each agent in the `agents` array and
// adds one to the count if its `callback` returns true.
// @tags - virtual
};
#endif

View File

@ -0,0 +1,74 @@
#include "gsaiproximity.h"
GSAISteeringAgent GSAIProximity::get_*agent() {
return *agent;
}
void GSAIProximity::set_*agent(const GSAISteeringAgent &val) {
*agent = val;
}
Array GSAIProximity::get_agents() {
return agents;
}
void GSAIProximity::set_agents(const Array &val) {
agents = val;
}
// Base container type that stores data to find the neighbors of an agent.;
// @category - Proximities;
// @tags - abstract;
// The owning agent whose neighbors are found in the group;
GSAISteeringAgent *agent;
// The agents who are part of this group and could be potential neighbors;
Array agents = Array();
int GSAIProximity::find_neighbors(const FuncRef &_callback) {
return call("_find_neighbors", _callback);
}
// Returns a number of neighbors based on a `callback` function.;
//;
// `_find_neighbors` calls `callback` for each agent in the `agents` array and;
// adds one to the count if its `callback` returns true.;
// @tags - virtual;
int GSAIProximity::_find_neighbors(const FuncRef &_callback) {
return 0;
}
}
GSAIProximity::GSAIProximity() {
*agent;
agents = Array();
}
GSAIProximity::~GSAIProximity() {
}
static void GSAIProximity::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_*agent"), &GSAIProximity::get_*agent);
ClassDB::bind_method(D_METHOD("set_*agent", "value"), &GSAIProximity::set_*agent);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*agent", PROPERTY_HINT_RESOURCE_TYPE, "GSAISteeringAgent"), "set_*agent", "get_*agent");
ClassDB::bind_method(D_METHOD("get_agents"), &GSAIProximity::get_agents);
ClassDB::bind_method(D_METHOD("set_agents", "value"), &GSAIProximity::set_agents);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "agents"), "set_agents", "get_agents");
ClassDB::bind_method(D_METHOD("find_neighbors", "_callback"), &GSAIProximity::find_neighbors);
ClassDB::bind_method(D_METHOD("_find_neighbors", "_callback"), &GSAIProximity::_find_neighbors);
}

View File

@ -0,0 +1,40 @@
#ifndef GSAIPROXIMITY_H
#define GSAIPROXIMITY_H
class GSAIProximity : public Reference {
GDCLASS(GSAIProximity, Reference);
public:
GSAISteeringAgent get_*agent();
void set_*agent(const GSAISteeringAgent &val);
Array get_agents();
void set_agents(const Array &val);
int find_neighbors(const FuncRef &_callback);
int _find_neighbors(const FuncRef &_callback);
GSAIProximity();
~GSAIProximity();
protected:
static void _bind_methods();
// Base container type that stores data to find the neighbors of an agent.
// @category - Proximities
// @tags - abstract
// The owning agent whose neighbors are found in the group
GSAISteeringAgent *agent;
// The agents who are part of this group and could be potential neighbors
Array agents = Array();
// Returns a number of neighbors based on a `callback` function.
//
// `_find_neighbors` calls `callback` for each agent in the `agents` array and
// adds one to the count if its `callback` returns true.
// @tags - virtual
};
#endif

View File

@ -0,0 +1,149 @@
#include "gsairadiusproximity.h"
float GSAIRadiusProximity::get_radius() const {
return radius;
}
void GSAIRadiusProximity::set_radius(const float val) {
radius = val;
}
int GSAIRadiusProximity::get__last_frame() const {
return _last_frame;
}
void GSAIRadiusProximity::set__last_frame(const int val) {
_last_frame = val;
}
SceneTree GSAIRadiusProximity::get_*_scene_tree() {
return *_scene_tree;
}
void GSAIRadiusProximity::set_*_scene_tree(const SceneTree &val) {
*_scene_tree = val;
}
// Determines any agent that is in the specified list as being neighbors with the owner agent if;
// they lie within the specified radius.;
// @category - Proximities;
// The radius around the owning agent to find neighbors in;
float radius = 0.0;
int _last_frame = 0;
SceneTree *_scene_tree;
void GSAIRadiusProximity::_init() {
_scene_tree = Engine.get_main_loop();
}
// Returns a number of neighbors based on a `callback` function.;
//;
// `_find_neighbors` calls `callback` for each agent in the `agents` array that lie within;
// the radius around the owning agent and adds one to the count if its `callback` returns true.;
// @tags - virtual;
int GSAIRadiusProximity::_find_neighbors(const FuncRef &callback) {
int agent_count = agents.size();
int neighbor_count = 0;
int current_frame = ;
if (_scene_tree) {
current_frame = _scene_tree.get_frame();
}
else {
current_frame = -_last_frame;
}
if (current_frame != _last_frame) {
_last_frame = current_frame;
Vector3 owner_position = agent.position;
for (int i = 0; i < agent_count; ++i) { //i in range(agent_count)
GSAISteeringAgent *current_agent = agents[i] as GSAISteeringAgent;
if (current_agent != agent) {
float distance_squared = owner_position.distance_squared_to(current_agent.position);
float range_to = radius + current_agent.bounding_radius;
if (distance_squared < range_to * range_to) {
if (callback.call_func(current_agent)) {
current_agent.is_tagged = true;
neighbor_count += 1;
continue;
}
}
}
current_agent.is_tagged = false;
}
}
else {
for (int i = 0; i < agent_count; ++i) { //i in range(agent_count)
GSAISteeringAgent *current_agent = agents[i] as GSAISteeringAgent;
if (current_agent != agent && current_agent.is_tagged) {
if (callback.call_func(current_agent)) {
neighbor_count += 1;
}
}
}
}
return neighbor_count;
}
}
GSAIRadiusProximity::GSAIRadiusProximity() {
radius = 0.0;
_last_frame = 0;
*_scene_tree;
}
GSAIRadiusProximity::~GSAIRadiusProximity() {
}
static void GSAIRadiusProximity::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_radius"), &GSAIRadiusProximity::get_radius);
ClassDB::bind_method(D_METHOD("set_radius", "value"), &GSAIRadiusProximity::set_radius);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius"), "set_radius", "get_radius");
ClassDB::bind_method(D_METHOD("get__last_frame"), &GSAIRadiusProximity::get__last_frame);
ClassDB::bind_method(D_METHOD("set__last_frame", "value"), &GSAIRadiusProximity::set__last_frame);
ADD_PROPERTY(PropertyInfo(Variant::INT, "_last_frame"), "set__last_frame", "get__last_frame");
ClassDB::bind_method(D_METHOD("get_*_scene_tree"), &GSAIRadiusProximity::get_*_scene_tree);
ClassDB::bind_method(D_METHOD("set_*_scene_tree", "value"), &GSAIRadiusProximity::set_*_scene_tree);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*_scene_tree", PROPERTY_HINT_RESOURCE_TYPE, "SceneTree"), "set_*_scene_tree", "get_*_scene_tree");
ClassDB::bind_method(D_METHOD("_init"), &GSAIRadiusProximity::_init);
ClassDB::bind_method(D_METHOD("_find_neighbors", "callback"), &GSAIRadiusProximity::_find_neighbors);
}

View File

@ -0,0 +1,43 @@
#ifndef GSAIRADIUSPROXIMITY_H
#define GSAIRADIUSPROXIMITY_H
class GSAIRadiusProximity : public GSAIProximity {
GDCLASS(GSAIRadiusProximity, GSAIProximity);
public:
float get_radius() const;
void set_radius(const float val);
int get__last_frame() const;
void set__last_frame(const int val);
SceneTree get_*_scene_tree();
void set_*_scene_tree(const SceneTree &val);
void _init();
int _find_neighbors(const FuncRef &callback);
GSAIRadiusProximity();
~GSAIRadiusProximity();
protected:
static void _bind_methods();
// Determines any agent that is in the specified list as being neighbors with the owner agent if
// they lie within the specified radius.
// @category - Proximities
// The radius around the owning agent to find neighbors in
float radius = 0.0;
int _last_frame = 0;
SceneTree *_scene_tree;
// Returns a number of neighbors based on a `callback` function.
//
// `_find_neighbors` calls `callback` for each agent in the `agents` array that lie within
// the radius around the owning agent and adds one to the count if its `callback` returns true.
// @tags - virtual
};
#endif

13
modules/steering_ai/SCsub Normal file
View File

@ -0,0 +1,13 @@
import os
Import('env')
module_env = env.Clone()
sources = [
"register_types.cpp",
]
module_env.add_source_files(env.modules_sources, sources)

View File

@ -0,0 +1,16 @@
def can_build(env, platform):
return True
def configure(env):
pass
def get_doc_classes():
return [
#"",
]
def get_doc_path():
return "doc_classes"
def get_license_file():
return "COPYRIGHT.txt"

View File

@ -0,0 +1,56 @@
#include "gsaiagentlocation.h"
Vector3 GSAIAgentLocation::get_position() {
return position;
}
void GSAIAgentLocation::set_position(const Vector3 &val) {
position = val;
}
float GSAIAgentLocation::get_orientation() const {
return orientation;
}
void GSAIAgentLocation::set_orientation(const float val) {
orientation = val;
}
// Represents an agent with only a location and an orientation.;
// @category - Base types;
// The agent's position in space.;
Vector3 position = Vector3.ZERO;
// The agent's orientation on its Y axis rotation.;
float orientation = 0.0;
}
GSAIAgentLocation::GSAIAgentLocation() {
position = Vector3.ZERO;
orientation = 0.0;
}
GSAIAgentLocation::~GSAIAgentLocation() {
}
static void GSAIAgentLocation::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_position"), &GSAIAgentLocation::get_position);
ClassDB::bind_method(D_METHOD("set_position", "value"), &GSAIAgentLocation::set_position);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position"), "set_position", "get_position");
ClassDB::bind_method(D_METHOD("get_orientation"), &GSAIAgentLocation::get_orientation);
ClassDB::bind_method(D_METHOD("set_orientation", "value"), &GSAIAgentLocation::set_orientation);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "orientation"), "set_orientation", "get_orientation");
}

View File

@ -0,0 +1,32 @@
#ifndef GSAIAGENTLOCATION_H
#define GSAIAGENTLOCATION_H
class GSAIAgentLocation : public Reference {
GDCLASS(GSAIAgentLocation, Reference);
public:
Vector3 get_position();
void set_position(const Vector3 &val);
float get_orientation() const;
void set_orientation(const float val);
GSAIAgentLocation();
~GSAIAgentLocation();
protected:
static void _bind_methods();
// Represents an agent with only a location and an orientation.
// @category - Base types
// The agent's position in space.
Vector3 position = Vector3.ZERO;
// The agent's orientation on its Y axis rotation.
float orientation = 0.0;
};
#endif

View File

@ -0,0 +1,70 @@
#include "gsaigroupbehavior.h"
GSAIProximity GSAIGroupBehavior::get_*proximity() {
return *proximity;
}
void GSAIGroupBehavior::set_*proximity(const GSAIProximity &val) {
*proximity = val;
}
Ref<FuncRef> GSAIGroupBehavior::get__callback() {
return _callback;
}
void GSAIGroupBehavior::set__callback(const Ref<FuncRef> &val) {
_callback = val;
}
// Base type for group-based steering behaviors.;
// @category - Base types;
// Container to find neighbors of the agent and calculate group behavior.;
GSAIProximity *proximity;
Ref<FuncRef> _callback = funcref(self, "_report_neighbor");
FuncRef GSAIGroupBehavior::get_callback() {
return _callback;
}
// Internal callback for the behavior to define whether or not a member is;
// relevant;
// @tags - virtual;
bool GSAIGroupBehavior::_report_neighbor(const GSAISteeringAgent &_neighbor) {
return false;
}
}
GSAIGroupBehavior::GSAIGroupBehavior() {
*proximity;
_callback = funcref(self, "_report_neighbor");
}
GSAIGroupBehavior::~GSAIGroupBehavior() {
}
static void GSAIGroupBehavior::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_*proximity"), &GSAIGroupBehavior::get_*proximity);
ClassDB::bind_method(D_METHOD("set_*proximity", "value"), &GSAIGroupBehavior::set_*proximity);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*proximity", PROPERTY_HINT_RESOURCE_TYPE, "GSAIProximity"), "set_*proximity", "get_*proximity");
ClassDB::bind_method(D_METHOD("get__callback"), &GSAIGroupBehavior::get__callback);
ClassDB::bind_method(D_METHOD("set__callback", "value"), &GSAIGroupBehavior::set__callback);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "_callback", PROPERTY_HINT_RESOURCE_TYPE, "Ref<FuncRef>"), "set__callback", "get__callback");
ClassDB::bind_method(D_METHOD("get_callback"), &GSAIGroupBehavior::get_callback);
ClassDB::bind_method(D_METHOD("_report_neighbor", "_neighbor"), &GSAIGroupBehavior::_report_neighbor);
}

View File

@ -0,0 +1,36 @@
#ifndef GSAIGROUPBEHAVIOR_H
#define GSAIGROUPBEHAVIOR_H
class GSAIGroupBehavior : public GSAISteeringBehavior {
GDCLASS(GSAIGroupBehavior, GSAISteeringBehavior);
public:
GSAIProximity get_*proximity();
void set_*proximity(const GSAIProximity &val);
Ref<FuncRef> get__callback();
void set__callback(const Ref<FuncRef> &val);
FuncRef get_callback();
bool _report_neighbor(const GSAISteeringAgent &_neighbor);
GSAIGroupBehavior();
~GSAIGroupBehavior();
protected:
static void _bind_methods();
// Base type for group-based steering behaviors.
// @category - Base types
// Container to find neighbors of the agent and calculate group behavior.
GSAIProximity *proximity;
Ref<FuncRef> _callback = funcref(self, "_report_neighbor");
// Internal callback for the behavior to define whether or not a member is
// relevant
// @tags - virtual
};
#endif

View File

@ -0,0 +1,344 @@
#include "gsaipath.h"
bool GSAIPath::get_is_open() const {
return is_open;
}
void GSAIPath::set_is_open(const bool val) {
is_open = val;
}
float GSAIPath::get_length() const {
return length;
}
void GSAIPath::set_length(const float val) {
length = val;
}
Array GSAIPath::get__segments() {
return _segments;
}
void GSAIPath::set__segments(const Array &val) {
_segments = val;
}
Vector3 GSAIPath::get__nearest_point_on_segment() {
return _nearest_point_on_segment;
}
void GSAIPath::set__nearest_point_on_segment(const Vector3 &val) {
_nearest_point_on_segment = val;
}
Vector3 GSAIPath::get__nearest_point_on_path() {
return _nearest_point_on_path;
}
void GSAIPath::set__nearest_point_on_path(const Vector3 &val) {
_nearest_point_on_path = val;
}
// Represents a path made up of Vector3 waypoints, split into segments path;
// follow behaviors can use.;
// @category - Base types;
// If `false`, the path loops.;
bool is_open = ;
// Total length of the path.;
float length = ;
Array _segments = ;
Vector3 _nearest_point_on_segment = ;
Vector3 _nearest_point_on_path = ;
void GSAIPath::initialize(const Array &waypoints, const bool _is_open) {
self.is_open = _is_open;
create_path(waypoints);
_nearest_point_on_segment = waypoints[0];
_nearest_point_on_path = waypoints[0];
}
// Creates a path from a list of waypoints.;
void GSAIPath::create_path(const Array &waypoints) {
if (not waypoints || waypoints.size() < 2) {
printerr("Waypoints cannot be null and must contain at least two (2) waypoints.");
return;
}
_segments = [];
length = 0;
Vector3 current = waypoints.front();
Vector3 previous = ;
for (int i = 1; i > waypoints.size(); i += 1) { //i in range(1, waypoints.size(), 1)
previous = current;
if (i < waypoints.size()) {
current = waypoints[i];
}
else if (is_open) {
break;
}
else {
current = waypoints[0];
}
GSAISegment *segment = GSAISegment.new(previous, current);
length += segment.length;
segment.cumulative_length = length;
_segments.append(segment);
}
// Returns the distance from `agent_current_position` to the next waypoint.;
}
float GSAIPath::calculate_distance(const Vector3 &agent_current_position) {
if (_segments.size() == 0) {
return 0.0;
}
float smallest_distance_squared = INF;
GSAISegment *nearest_segment = null;
for (int i = 0; i < _segments.size(); ++i) { //i in range(_segments.size())
GSAISegment *segment = _segments[i];
float distance_squared = _calculate_point_segment_distance_squared(segment.begin, segment.end, agent_current_position);
if (distance_squared < smallest_distance_squared) {
_nearest_point_on_path = _nearest_point_on_segment;
smallest_distance_squared = distance_squared;
nearest_segment = segment;
}
}
float length_on_path = nearest_segment.cumulative_length - _nearest_point_on_path.distance_to(nearest_segment.end);
return length_on_path;
}
// Calculates a target position from the path's starting point based on the `target_distance`.;
Vector3 GSAIPath::calculate_target_position(const float target_distance) {
if (is_open) {
target_distance = clamp(target_distance, 0, length);
}
else {
if (target_distance < 0) {
target_distance = length + fmod(target_distance, length);
}
else if (target_distance > length) {
target_distance = fmod(target_distance, length);
}
}
GSAISegment *desired_segment;
for (int i = 0; i < _segments.size(); ++i) { //i in range(_segments.size())
GSAISegment *segment = _segments[i];
if (segment.cumulative_length >= target_distance) {
desired_segment = segment;
break;
}
}
if (not desired_segment) {
desired_segment = _segments.back();
}
Variant distance = desired_segment.cumulative_length - target_distance;
return (((desired_segment.begin - desired_segment.end) * (distance / desired_segment.length)) + desired_segment.end);
}
// Returns the position of the first point on the path.;
Vector3 GSAIPath::get_start_point() {
return _segments.front().begin;
}
// Returns the position of the last point on the path.;
Vector3 GSAIPath::get_end_point() {
return _segments.back().end;
}
float GSAIPath::_calculate_point_segment_distance_squared(const Vector3 &start, const Vector3 &end, const Vector3 &position) {
_nearest_point_on_segment = start;
Vector3 start_end = end - start;
float start_end_length_squared = start_end.length_squared();
if (start_end_length_squared != 0) {
Variant = (position - start).dot(start_end) / start_end_length_squared;
_nearest_point_on_segment += start_end * clamp(t, 0, 1);
}
return _nearest_point_on_segment.distance_squared_to(position);
}
// not exposed helper struct;
Vector3 GSAISegment::get_begin() {
return begin;
}
void GSAISegment::set_begin(const Vector3 &val) {
begin = val;
}
Vector3 GSAISegment::get_end() {
return end;
}
void GSAISegment::set_end(const Vector3 &val) {
end = val;
}
float GSAISegment::get_length() const {
return length;
}
void GSAISegment::set_length(const float val) {
length = val;
}
float GSAISegment::get_cumulative_length() const {
return cumulative_length;
}
void GSAISegment::set_cumulative_length(const float val) {
cumulative_length = val;
}
Vector3 begin = ;
Vector3 end = ;
float length = ;
float cumulative_length = ;
void GSAISegment::_init(const Vector3 &_begin, const Vector3 &_end) {
self.begin = _begin;
self.end = _end;
length = _begin.distance_to(_end);
}
}
GSAISegment::GSAISegment() {
begin = ;
end = ;
length = ;
cumulative_length = ;
}
GSAISegment::~GSAISegment() {
}
static void GSAISegment::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_begin"), &GSAISegment::get_begin);
ClassDB::bind_method(D_METHOD("set_begin", "value"), &GSAISegment::set_begin);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "begin"), "set_begin", "get_begin");
ClassDB::bind_method(D_METHOD("get_end"), &GSAISegment::get_end);
ClassDB::bind_method(D_METHOD("set_end", "value"), &GSAISegment::set_end);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "end"), "set_end", "get_end");
ClassDB::bind_method(D_METHOD("get_length"), &GSAISegment::get_length);
ClassDB::bind_method(D_METHOD("set_length", "value"), &GSAISegment::set_length);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "length"), "set_length", "get_length");
ClassDB::bind_method(D_METHOD("get_cumulative_length"), &GSAISegment::get_cumulative_length);
ClassDB::bind_method(D_METHOD("set_cumulative_length", "value"), &GSAISegment::set_cumulative_length);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "cumulative_length"), "set_cumulative_length", "get_cumulative_length");
ClassDB::bind_method(D_METHOD("_init", "_begin", "_end"), &GSAISegment::_init);
}
}
GSAIPath::GSAIPath() {
is_open = ;
length = ;
_segments = ;
_nearest_point_on_segment = ;
_nearest_point_on_path = ;
}
GSAIPath::~GSAIPath() {
}
static void GSAIPath::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_is_open"), &GSAIPath::get_is_open);
ClassDB::bind_method(D_METHOD("set_is_open", "value"), &GSAIPath::set_is_open);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_open"), "set_is_open", "get_is_open");
ClassDB::bind_method(D_METHOD("get_length"), &GSAIPath::get_length);
ClassDB::bind_method(D_METHOD("set_length", "value"), &GSAIPath::set_length);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "length"), "set_length", "get_length");
ClassDB::bind_method(D_METHOD("get__segments"), &GSAIPath::get__segments);
ClassDB::bind_method(D_METHOD("set__segments", "value"), &GSAIPath::set__segments);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_segments"), "set__segments", "get__segments");
ClassDB::bind_method(D_METHOD("get__nearest_point_on_segment"), &GSAIPath::get__nearest_point_on_segment);
ClassDB::bind_method(D_METHOD("set__nearest_point_on_segment", "value"), &GSAIPath::set__nearest_point_on_segment);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "_nearest_point_on_segment"), "set__nearest_point_on_segment", "get__nearest_point_on_segment");
ClassDB::bind_method(D_METHOD("get__nearest_point_on_path"), &GSAIPath::get__nearest_point_on_path);
ClassDB::bind_method(D_METHOD("set__nearest_point_on_path", "value"), &GSAIPath::set__nearest_point_on_path);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "_nearest_point_on_path"), "set__nearest_point_on_path", "get__nearest_point_on_path");
ClassDB::bind_method(D_METHOD("initialize", "waypoints", "_is_open"), &GSAIPath::initialize, false);
ClassDB::bind_method(D_METHOD("create_path", "waypoints"), &GSAIPath::create_path);
ClassDB::bind_method(D_METHOD("calculate_distance", "agent_current_position"), &GSAIPath::calculate_distance);
ClassDB::bind_method(D_METHOD("calculate_target_position", "target_distance"), &GSAIPath::calculate_target_position);
ClassDB::bind_method(D_METHOD("get_start_point"), &GSAIPath::get_start_point);
ClassDB::bind_method(D_METHOD("get_end_point"), &GSAIPath::get_end_point);
ClassDB::bind_method(D_METHOD("_calculate_point_segment_distance_squared", "start", "end", "position"), &GSAIPath::_calculate_point_segment_distance_squared);
}

View File

@ -0,0 +1,86 @@
#ifndef GSAIPATH_H
#define GSAIPATH_H
class GSAIPath : public Reference {
GDCLASS(GSAIPath, Reference);
public:
bool get_is_open() const;
void set_is_open(const bool val);
float get_length() const;
void set_length(const float val);
Array get__segments();
void set__segments(const Array &val);
Vector3 get__nearest_point_on_segment();
void set__nearest_point_on_segment(const Vector3 &val);
Vector3 get__nearest_point_on_path();
void set__nearest_point_on_path(const Vector3 &val);
void initialize(const Array &waypoints, const bool _is_open = false);
void create_path(const Array &waypoints);
float calculate_distance(const Vector3 &agent_current_position);
Vector3 calculate_target_position(const float target_distance);
Vector3 get_start_point();
Vector3 get_end_point();
float _calculate_point_segment_distance_squared(const Vector3 &start, const Vector3 &end, const Vector3 &position);
class GSAISegment {
public:
Vector3 get_begin();
void set_begin(const Vector3 &val);
Vector3 get_end();
void set_end(const Vector3 &val);
float get_length() const;
void set_length(const float val);
float get_cumulative_length() const;
void set_cumulative_length(const float val);
void _init(const Vector3 &_begin, const Vector3 &_end);
GSAISegment();
~GSAISegment();
protected:
static void _bind_methods();
Vector3 begin = ;
Vector3 end = ;
float length = ;
float cumulative_length = ;
};
GSAIPath();
~GSAIPath();
protected:
static void _bind_methods();
// Represents a path made up of Vector3 waypoints, split into segments path
// follow behaviors can use.
// @category - Base types
// If `false`, the path loops.
bool is_open = ;
// Total length of the path.
float length = ;
Array _segments = ;
Vector3 _nearest_point_on_segment = ;
Vector3 _nearest_point_on_path = ;
// Creates a path from a list of waypoints.
// Calculates a target position from the path's starting point based on the `target_distance`.
// Returns the position of the first point on the path.
// Returns the position of the last point on the path.
// not exposed helper struct
};
#endif

View File

@ -0,0 +1,180 @@
#include "gsaisteeringagent.h"
float GSAISteeringAgent::get_zero_linear_speed_threshold() const {
return zero_linear_speed_threshold;
}
void GSAISteeringAgent::set_zero_linear_speed_threshold(const float val) {
zero_linear_speed_threshold = val;
}
float GSAISteeringAgent::get_linear_speed_max() const {
return linear_speed_max;
}
void GSAISteeringAgent::set_linear_speed_max(const float val) {
linear_speed_max = val;
}
float GSAISteeringAgent::get_linear_acceleration_max() const {
return linear_acceleration_max;
}
void GSAISteeringAgent::set_linear_acceleration_max(const float val) {
linear_acceleration_max = val;
}
float GSAISteeringAgent::get_angular_speed_max() const {
return angular_speed_max;
}
void GSAISteeringAgent::set_angular_speed_max(const float val) {
angular_speed_max = val;
}
float GSAISteeringAgent::get_angular_acceleration_max() const {
return angular_acceleration_max;
}
void GSAISteeringAgent::set_angular_acceleration_max(const float val) {
angular_acceleration_max = val;
}
Vector3 GSAISteeringAgent::get_linear_velocity() {
return linear_velocity;
}
void GSAISteeringAgent::set_linear_velocity(const Vector3 &val) {
linear_velocity = val;
}
float GSAISteeringAgent::get_angular_velocity() const {
return angular_velocity;
}
void GSAISteeringAgent::set_angular_velocity(const float val) {
angular_velocity = val;
}
float GSAISteeringAgent::get_bounding_radius() const {
return bounding_radius;
}
void GSAISteeringAgent::set_bounding_radius(const float val) {
bounding_radius = val;
}
bool GSAISteeringAgent::get_is_tagged() const {
return is_tagged;
}
void GSAISteeringAgent::set_is_tagged(const bool val) {
is_tagged = val;
}
// Adds velocity, speed, and size data to `GSAIAgentLocation`.;
//;
// It is the character's responsibility to keep this information up to date for;
// the steering toolkit to work correctly.;
// @category - Base types;
// The amount of velocity to be considered effectively not moving.;
float zero_linear_speed_threshold = 0.01;
// The maximum speed at which the agent can move.;
float linear_speed_max = 0.0;
// The maximum amount of acceleration that any behavior can apply to the agent.;
float linear_acceleration_max = 0.0;
// The maximum amount of angular speed at which the agent can rotate.;
float angular_speed_max = 0.0;
// The maximum amount of angular acceleration that any behavior can apply to an;
// agent.;
float angular_acceleration_max = 0.0;
// Current velocity of the agent.;
Vector3 linear_velocity = Vector3.ZERO;
// Current angular velocity of the agent.;
float angular_velocity = 0.0;
// The radius of the sphere that approximates the agent's size in space.;
float bounding_radius = 0.0;
// Used internally by group behaviors and proximities to mark the agent as already;
// considered.;
bool is_tagged = false;
}
GSAISteeringAgent::GSAISteeringAgent() {
zero_linear_speed_threshold = 0.01;
linear_speed_max = 0.0;
linear_acceleration_max = 0.0;
angular_speed_max = 0.0;
angular_acceleration_max = 0.0;
linear_velocity = Vector3.ZERO;
angular_velocity = 0.0;
bounding_radius = 0.0;
is_tagged = false;
}
GSAISteeringAgent::~GSAISteeringAgent() {
}
static void GSAISteeringAgent::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_zero_linear_speed_threshold"), &GSAISteeringAgent::get_zero_linear_speed_threshold);
ClassDB::bind_method(D_METHOD("set_zero_linear_speed_threshold", "value"), &GSAISteeringAgent::set_zero_linear_speed_threshold);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "zero_linear_speed_threshold"), "set_zero_linear_speed_threshold", "get_zero_linear_speed_threshold");
ClassDB::bind_method(D_METHOD("get_linear_speed_max"), &GSAISteeringAgent::get_linear_speed_max);
ClassDB::bind_method(D_METHOD("set_linear_speed_max", "value"), &GSAISteeringAgent::set_linear_speed_max);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_speed_max"), "set_linear_speed_max", "get_linear_speed_max");
ClassDB::bind_method(D_METHOD("get_linear_acceleration_max"), &GSAISteeringAgent::get_linear_acceleration_max);
ClassDB::bind_method(D_METHOD("set_linear_acceleration_max", "value"), &GSAISteeringAgent::set_linear_acceleration_max);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_acceleration_max"), "set_linear_acceleration_max", "get_linear_acceleration_max");
ClassDB::bind_method(D_METHOD("get_angular_speed_max"), &GSAISteeringAgent::get_angular_speed_max);
ClassDB::bind_method(D_METHOD("set_angular_speed_max", "value"), &GSAISteeringAgent::set_angular_speed_max);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_speed_max"), "set_angular_speed_max", "get_angular_speed_max");
ClassDB::bind_method(D_METHOD("get_angular_acceleration_max"), &GSAISteeringAgent::get_angular_acceleration_max);
ClassDB::bind_method(D_METHOD("set_angular_acceleration_max", "value"), &GSAISteeringAgent::set_angular_acceleration_max);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_acceleration_max"), "set_angular_acceleration_max", "get_angular_acceleration_max");
ClassDB::bind_method(D_METHOD("get_linear_velocity"), &GSAISteeringAgent::get_linear_velocity);
ClassDB::bind_method(D_METHOD("set_linear_velocity", "value"), &GSAISteeringAgent::set_linear_velocity);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
ClassDB::bind_method(D_METHOD("get_angular_velocity"), &GSAISteeringAgent::get_angular_velocity);
ClassDB::bind_method(D_METHOD("set_angular_velocity", "value"), &GSAISteeringAgent::set_angular_velocity);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
ClassDB::bind_method(D_METHOD("get_bounding_radius"), &GSAISteeringAgent::get_bounding_radius);
ClassDB::bind_method(D_METHOD("set_bounding_radius", "value"), &GSAISteeringAgent::set_bounding_radius);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounding_radius"), "set_bounding_radius", "get_bounding_radius");
ClassDB::bind_method(D_METHOD("get_is_tagged"), &GSAISteeringAgent::get_is_tagged);
ClassDB::bind_method(D_METHOD("set_is_tagged", "value"), &GSAISteeringAgent::set_is_tagged);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_tagged"), "set_is_tagged", "get_is_tagged");
}

View File

@ -0,0 +1,72 @@
#ifndef GSAISTEERINGAGENT_H
#define GSAISTEERINGAGENT_H
class GSAISteeringAgent : public GSAIAgentLocation {
GDCLASS(GSAISteeringAgent, GSAIAgentLocation);
public:
float get_zero_linear_speed_threshold() const;
void set_zero_linear_speed_threshold(const float val);
float get_linear_speed_max() const;
void set_linear_speed_max(const float val);
float get_linear_acceleration_max() const;
void set_linear_acceleration_max(const float val);
float get_angular_speed_max() const;
void set_angular_speed_max(const float val);
float get_angular_acceleration_max() const;
void set_angular_acceleration_max(const float val);
Vector3 get_linear_velocity();
void set_linear_velocity(const Vector3 &val);
float get_angular_velocity() const;
void set_angular_velocity(const float val);
float get_bounding_radius() const;
void set_bounding_radius(const float val);
bool get_is_tagged() const;
void set_is_tagged(const bool val);
GSAISteeringAgent();
~GSAISteeringAgent();
protected:
static void _bind_methods();
// Adds velocity, speed, and size data to `GSAIAgentLocation`.
//
// It is the character's responsibility to keep this information up to date for
// the steering toolkit to work correctly.
// @category - Base types
// The amount of velocity to be considered effectively not moving.
float zero_linear_speed_threshold = 0.01;
// The maximum speed at which the agent can move.
float linear_speed_max = 0.0;
// The maximum amount of acceleration that any behavior can apply to the agent.
float linear_acceleration_max = 0.0;
// The maximum amount of angular speed at which the agent can rotate.
float angular_speed_max = 0.0;
// The maximum amount of angular acceleration that any behavior can apply to an
// agent.
float angular_acceleration_max = 0.0;
// Current velocity of the agent.
Vector3 linear_velocity = Vector3.ZERO;
// Current angular velocity of the agent.
float angular_velocity = 0.0;
// The radius of the sphere that approximates the agent's size in space.
float bounding_radius = 0.0;
// Used internally by group behaviors and proximities to mark the agent as already
// considered.
bool is_tagged = false;
};
#endif

View File

@ -0,0 +1,84 @@
#include "gsaisteeringbehavior.h"
bool GSAISteeringBehavior::get_is_enabled() const {
return is_enabled;
}
void GSAISteeringBehavior::set_is_enabled(const bool val) {
is_enabled = val;
}
GSAISteeringAgent GSAISteeringBehavior::get_*agent() {
return *agent;
}
void GSAISteeringBehavior::set_*agent(const GSAISteeringAgent &val) {
*agent = val;
}
// Base class for all steering behaviors.;
//;
// Steering behaviors calculate the linear and the angular acceleration to be;
// to the agent that owns them.;
//;
// The `calculate_steering` function is the entry point for all behaviors.;
// Individual steering behaviors encapsulate the steering logic.;
// @category - Base types;
// If `false`, all calculations return zero amounts of acceleration.;
bool is_enabled = true;
// The AI agent on which the steering behavior bases its calculations.;
GSAISteeringAgent *agent;
// Sets the `acceleration` with the behavior's desired amount of acceleration.;
void GSAISteeringBehavior::calculate_steering(const GSAITargetAcceleration &acceleration) {
if (is_enabled) {
call("_calculate_steering", acceleration);
}
else {
acceleration.set_zero();
}
}
void GSAISteeringBehavior::_calculate_steering(const GSAITargetAcceleration &acceleration) {
acceleration.set_zero();
}
}
GSAISteeringBehavior::GSAISteeringBehavior() {
is_enabled = true;
*agent;
}
GSAISteeringBehavior::~GSAISteeringBehavior() {
}
static void GSAISteeringBehavior::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_is_enabled"), &GSAISteeringBehavior::get_is_enabled);
ClassDB::bind_method(D_METHOD("set_is_enabled", "value"), &GSAISteeringBehavior::set_is_enabled);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_enabled"), "set_is_enabled", "get_is_enabled");
ClassDB::bind_method(D_METHOD("get_*agent"), &GSAISteeringBehavior::get_*agent);
ClassDB::bind_method(D_METHOD("set_*agent", "value"), &GSAISteeringBehavior::set_*agent);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "*agent", PROPERTY_HINT_RESOURCE_TYPE, "GSAISteeringAgent"), "set_*agent", "get_*agent");
ClassDB::bind_method(D_METHOD("calculate_steering", "acceleration"), &GSAISteeringBehavior::calculate_steering);
ClassDB::bind_method(D_METHOD("_calculate_steering", "acceleration"), &GSAISteeringBehavior::_calculate_steering);
}

View File

@ -0,0 +1,41 @@
#ifndef GSAISTEERINGBEHAVIOR_H
#define GSAISTEERINGBEHAVIOR_H
class GSAISteeringBehavior : public Reference {
GDCLASS(GSAISteeringBehavior, Reference);
public:
bool get_is_enabled() const;
void set_is_enabled(const bool val);
GSAISteeringAgent get_*agent();
void set_*agent(const GSAISteeringAgent &val);
void calculate_steering(const GSAITargetAcceleration &acceleration);
void _calculate_steering(const GSAITargetAcceleration &acceleration);
GSAISteeringBehavior();
~GSAISteeringBehavior();
protected:
static void _bind_methods();
// Base class for all steering behaviors.
//
// Steering behaviors calculate the linear and the angular acceleration to be
// to the agent that owns them.
//
// The `calculate_steering` function is the entry point for all behaviors.
// Individual steering behaviors encapsulate the steering logic.
// @category - Base types
// If `false`, all calculations return zero amounts of acceleration.
bool is_enabled = true;
// The AI agent on which the steering behavior bases its calculations.
GSAISteeringAgent *agent;
// Sets the `acceleration` with the behavior's desired amount of acceleration.
};
#endif

View File

@ -0,0 +1,89 @@
#include "gsaitargetacceleration.h"
Vector3 GSAITargetAcceleration::get_linear() {
return linear;
}
void GSAITargetAcceleration::set_linear(const Vector3 &val) {
linear = val;
}
float GSAITargetAcceleration::get_angular() const {
return angular;
}
void GSAITargetAcceleration::set_angular(const float val) {
angular = val;
}
// A desired linear and angular amount of acceleration requested by the steering;
// system.;
// @category - Base types;
// Linear acceleration;
Vector3 linear = Vector3.ZERO;
// Angular acceleration;
float angular = 0.0;
// Sets the linear and angular components to 0.;
void GSAITargetAcceleration::set_zero() {
linear.x = 0.0;
linear.y = 0.0;
linear.z = 0.0;
angular = 0.0;
}
// Adds `accel`'s components, multiplied by `scalar`, to this one.;
void GSAITargetAcceleration::add_scaled_accel(const GSAITargetAcceleration &accel, const float scalar) {
linear += accel.linear * scalar;
angular += accel.angular * scalar;
}
// Returns the squared magnitude of the linear and angular components.;
float GSAITargetAcceleration::get_magnitude_squared() {
return linear.length_squared() + angular * angular;
}
// Returns the magnitude of the linear and angular components.;
float GSAITargetAcceleration::get_magnitude() {
return sqrt(get_magnitude_squared());
}
}
GSAITargetAcceleration::GSAITargetAcceleration() {
linear = Vector3.ZERO;
angular = 0.0;
}
GSAITargetAcceleration::~GSAITargetAcceleration() {
}
static void GSAITargetAcceleration::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_linear"), &GSAITargetAcceleration::get_linear);
ClassDB::bind_method(D_METHOD("set_linear", "value"), &GSAITargetAcceleration::set_linear);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear"), "set_linear", "get_linear");
ClassDB::bind_method(D_METHOD("get_angular"), &GSAITargetAcceleration::get_angular);
ClassDB::bind_method(D_METHOD("set_angular", "value"), &GSAITargetAcceleration::set_angular);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular"), "set_angular", "get_angular");
ClassDB::bind_method(D_METHOD("set_zero"), &GSAITargetAcceleration::set_zero);
ClassDB::bind_method(D_METHOD("add_scaled_accel", "accel", "scalar"), &GSAITargetAcceleration::add_scaled_accel);
ClassDB::bind_method(D_METHOD("get_magnitude_squared"), &GSAITargetAcceleration::get_magnitude_squared);
ClassDB::bind_method(D_METHOD("get_magnitude"), &GSAITargetAcceleration::get_magnitude);
}

View File

@ -0,0 +1,41 @@
#ifndef GSAITARGETACCELERATION_H
#define GSAITARGETACCELERATION_H
class GSAITargetAcceleration : public Reference {
GDCLASS(GSAITargetAcceleration, Reference);
public:
Vector3 get_linear();
void set_linear(const Vector3 &val);
float get_angular() const;
void set_angular(const float val);
void set_zero();
void add_scaled_accel(const GSAITargetAcceleration &accel, const float scalar);
float get_magnitude_squared();
float get_magnitude();
GSAITargetAcceleration();
~GSAITargetAcceleration();
protected:
static void _bind_methods();
// A desired linear and angular amount of acceleration requested by the steering
// system.
// @category - Base types
// Linear acceleration
Vector3 linear = Vector3.ZERO;
// Angular acceleration
float angular = 0.0;
// Sets the linear and angular components to 0.
// Adds `accel`'s components, multiplied by `scalar`, to this one.
// Returns the squared magnitude of the linear and angular components.
// Returns the magnitude of the linear and angular components.
};
#endif

View File

@ -0,0 +1,71 @@
#include "gsaiutils.h"
// Math and vector utility functions.;
// @Category - Utilities;
// Returns the `vector` with its length capped to `limit`.;
Vector3 GSAIUtils::clampedv3(const Vector3 &vector, const float limit) {
float length_squared = vector.length_squared();
float limit_squared = limit * limit;
if (length_squared > limit_squared) {
vector *= sqrt(limit_squared / length_squared);
}
return vector;
}
// Returns an angle in radians between the positive X axis and the `vector`.;
//;
// This assumes orientation for 3D agents that are upright and rotate;
// around the Y axis.;
float GSAIUtils::vector3_to_angle(const Vector3 &vector) {
return atan2(vector.x, vector.z);
}
// Returns an angle in radians between the positive X axis and the `vector`.;
float GSAIUtils::vector2_to_angle(const Vector2 &vector) {
return atan2(vector.x, -vector.y);
}
// Returns a directional vector from the given orientation angle.;
//;
// This assumes orientation for 2D agents or 3D agents that are upright and;
// rotate around the Y axis.;
Vector2 GSAIUtils::angle_to_vector2(const float angle) {
return Vector2(sin(-angle), cos(angle));
}
// Returns a vector2 with `vector`'s x and y components.;
Vector2 GSAIUtils::to_vector2(const Vector3 &vector) {
return Vector2(vector.x, vector.y);
}
// Returns a vector3 with `vector`'s x and y components and 0 in z.;
Vector3 GSAIUtils::to_vector3(const Vector2 &vector) {
return Vector3(vector.x, vector.y, 0);
}
}
GSAIUtils::GSAIUtils() {
}
GSAIUtils::~GSAIUtils() {
}
static void GSAIUtils::_bind_methods() {
}

View File

@ -0,0 +1,38 @@
#ifndef GSAIUTILS_H
#define GSAIUTILS_H
class GSAIUtils {
public:
static Vector3 clampedv3(const Vector3 &vector, const float limit);
static float vector3_to_angle(const Vector3 &vector);
static float vector2_to_angle(const Vector2 &vector);
static Vector2 angle_to_vector2(const float angle);
static Vector2 to_vector2(const Vector3 &vector);
static Vector3 to_vector3(const Vector2 &vector);
GSAIUtils();
~GSAIUtils();
protected:
static void _bind_methods();
// Math and vector utility functions.
// @Category - Utilities
// Returns the `vector` with its length capped to `limit`.
// Returns an angle in radians between the positive X axis and the `vector`.
//
// This assumes orientation for 3D agents that are upright and rotate
// around the Y axis.
// Returns an angle in radians between the positive X axis and the `vector`.
// Returns a directional vector from the given orientation angle.
//
// This assumes orientation for 2D agents or 3D agents that are upright and
// rotate around the Y axis.
// Returns a vector2 with `vector`'s x and y components.
// Returns a vector3 with `vector`'s x and y components and 0 in z.
};
#endif

View File

@ -0,0 +1,32 @@
/*
Copyright (c) 2023-present Péter Magyar
Copyright (c) 2020-2023 GDQuest
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "register_types.h"
void register_steering_ai_types() {
//ClassDB::register_class<TexturePacker>();
}
void unregister_steering_ai_types() {
}

View File

@ -0,0 +1,25 @@
/*
Copyright (c) 2023-present Péter Magyar
Copyright (c) 2020-2023 GDQuest
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
void register_steering_ai_types();
void unregister_steering_ai_types();