feat: add some docs
This commit is contained in:
parent
07405168e8
commit
ac91b9a53e
@ -3,8 +3,8 @@ extends EditorPlugin
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_autoload_singleton("BoidsProcess_2D", "res://addons/boids/boids_process_2d.tscn")
|
||||
add_autoload_singleton("ProcessBoids", "res://addons/boids/process_boids.tscn")
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_autoload_singleton("BoidsProcess_2D")
|
||||
remove_autoload_singleton("ProcessBoids")
|
||||
|
@ -1,4 +1,3 @@
|
||||
[gd_scene format=3 uid="uid://c84c62urmhxbm"]
|
||||
|
||||
[node name="BoidsProcess" type="BoidsProcess"]
|
||||
process_2d = true
|
||||
|
@ -2,7 +2,7 @@ extends Node2D
|
||||
|
||||
func _ready() -> void:
|
||||
for flock in get_children():
|
||||
for i in 1000: spawnBoid(flock)
|
||||
for i in 100: spawnBoid(flock)
|
||||
|
||||
func spawnBoid(flock: Flock2D) -> void:
|
||||
var boid: Boid2D = preload("../example_boid.tscn").instantiate()
|
||||
|
@ -7,6 +7,8 @@ use crate::{BoidProperties, Flock2D};
|
||||
#[class(init, base=Node2D)]
|
||||
pub struct Boid2D {
|
||||
#[export]
|
||||
/// The properties of this boid.
|
||||
/// Note: this cannot be changed in runtime, aside from removing and readding the node.
|
||||
properties: Gd<BoidProperties>,
|
||||
props: BoidProperties,
|
||||
vel: Vec2,
|
||||
@ -18,18 +20,21 @@ pub struct Boid2D {
|
||||
impl Boid2D {
|
||||
#[func]
|
||||
#[inline(always)]
|
||||
/// Get the current velocity of this boid.
|
||||
fn get_velocity(&self) -> Vector2 {
|
||||
Vector2::new(self.vel.x, self.vel.y)
|
||||
}
|
||||
|
||||
#[func]
|
||||
#[inline(always)]
|
||||
/// Get the ID of this boid.
|
||||
pub fn get_id(&self) -> i64 {
|
||||
self.base().instance_id().to_i64()
|
||||
}
|
||||
|
||||
#[func]
|
||||
#[inline(always)]
|
||||
/// Get the flock ID of this boid.
|
||||
pub fn get_flock_id(&self) -> i64 {
|
||||
self.flock_id
|
||||
}
|
||||
|
@ -5,20 +5,26 @@ use godot::prelude::*;
|
||||
pub struct BoidProperties {
|
||||
#[export]
|
||||
#[init(val = 4.0)]
|
||||
/// Max speed of this boid.
|
||||
pub max_speed: f32,
|
||||
#[export]
|
||||
#[init(val = 1.0)]
|
||||
/// Max force that will be applied to this boid at once.
|
||||
pub max_force: f32,
|
||||
#[export]
|
||||
#[init(val = 1.5)]
|
||||
/// How much to align with other boids.
|
||||
pub alignment: f32,
|
||||
#[export]
|
||||
#[init(val = 1.0)]
|
||||
/// How much to cohere to other boids.
|
||||
pub cohesion: f32,
|
||||
#[export]
|
||||
#[init(val = 1.2)]
|
||||
/// How much to seperate from other boids.
|
||||
pub seperation: f32,
|
||||
#[export]
|
||||
#[init(val = 0.8)]
|
||||
/// How much to follow a flock target (if there is one).
|
||||
pub targeting: f32,
|
||||
}
|
@ -9,9 +9,12 @@ use super::Flock;
|
||||
#[class(init, base=Node2D)]
|
||||
pub struct Flock2D {
|
||||
#[export]
|
||||
/// Properties of this flock.
|
||||
/// Note: this cannot be changed in runtime, aside from removing and readding the node.
|
||||
properties: Gd<FlockProperties>,
|
||||
props: FlockProperties,
|
||||
#[export]
|
||||
/// A target node for the flock to follow.
|
||||
target: Option<Gd<Node2D>>,
|
||||
pub boids: FxIndexMap<i64, Gd<Boid2D>>,
|
||||
base: Base<Node2D>,
|
||||
|
@ -5,14 +5,14 @@ use godot::prelude::*;
|
||||
pub struct FlockProperties {
|
||||
#[export]
|
||||
#[init(val = 625.0)]
|
||||
/// squared
|
||||
/// Distance (squared) to apply seperation force between boids in a flock.
|
||||
pub goal_seperation: f32,
|
||||
#[export]
|
||||
#[init(val = 2500.0)]
|
||||
/// squared
|
||||
/// Distance (squared) to apply alignment force between boids in a flock.
|
||||
pub goal_alignment: f32,
|
||||
#[export]
|
||||
#[init(val = 2500.0)]
|
||||
/// squared
|
||||
/// Distance (squared) to apply cohesion force between boids in a flock.
|
||||
pub goal_cohesion: f32,
|
||||
}
|
@ -73,13 +73,20 @@ unsafe impl ExtensionLibrary for BoidsExtension {
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(init, base=Node)]
|
||||
/// Node that will make calls automatically to process 2D/3D boids, providing some configuration options.
|
||||
/// It's best to use this as an autoload singleton.
|
||||
pub struct BoidsProcess {
|
||||
#[export]
|
||||
#[init(val = true)]
|
||||
/// Whether to process 2D boids or not.
|
||||
process_2d: bool,
|
||||
#[export]
|
||||
#[init(val = true)]
|
||||
/// Whether to process 3D boids or not.
|
||||
process_3d: bool,
|
||||
#[export]
|
||||
#[init(val = 1)]
|
||||
/// Process boids per N physics ticks.
|
||||
process_per_tick: i64,
|
||||
boids: Option<Gd<Boids>>,
|
||||
engine: Option<Gd<Engine>>,
|
||||
@ -117,6 +124,7 @@ impl INode for BoidsProcess {
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(init, base=Object)]
|
||||
/// Singleton that holds all boids and flocks and manages them.
|
||||
struct Boids {
|
||||
flocks2d: FxIndexMap<i64, Gd<Flock2D>>,
|
||||
boids2d: FxIndexMap<i64, Gd<Boid2D>>,
|
||||
@ -150,15 +158,25 @@ impl Boids {
|
||||
impl Boids {
|
||||
#[func]
|
||||
#[inline(always)]
|
||||
/// Process all 2D boids once.
|
||||
/// NOTE: This function is not intended to be manually called. Prefer using `BoidsProcess` as an autoload singleton where possible.
|
||||
fn process_boids_2d(&mut self) {
|
||||
process_boids(&mut self.boids2d, &self.flocks2d)
|
||||
}
|
||||
|
||||
#[func]
|
||||
#[inline(always)]
|
||||
fn get_total_boid_count(&self) -> i64 {
|
||||
/// Gets the total 2D boid count.
|
||||
fn get_total_boid_2d_count(&self) -> i64 {
|
||||
self.boids2d.len() as i64
|
||||
}
|
||||
|
||||
#[func]
|
||||
#[inline(always)]
|
||||
/// Gets the total 2D flock count.
|
||||
fn get_total_flock_2d_count(&self) -> i64 {
|
||||
self.flocks2d.len() as i64
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@ -202,8 +220,8 @@ where
|
||||
}
|
||||
#[cfg(feature = "stats")]
|
||||
godot_print!(
|
||||
"[Boids] preparing all calculations took {} ms",
|
||||
time.elapsed().as_millis()
|
||||
"[Boids] preparing all calculations took {} micros",
|
||||
time.elapsed().as_micros()
|
||||
);
|
||||
|
||||
#[cfg(feature = "stats")]
|
||||
@ -211,7 +229,7 @@ where
|
||||
let forces: Vec<(i64, Vec3)> = calc_funcs
|
||||
.into_par_iter()
|
||||
.fold(
|
||||
|| Vec::<(i64, Vec3)>::with_capacity(total_boid_count / 10),
|
||||
|| Vec::<(i64, Vec3)>::with_capacity(total_boid_count),
|
||||
|mut acc, (boid_id, calc_fn)| {
|
||||
let force = calc_fn();
|
||||
acc.push((boid_id, force));
|
||||
@ -219,7 +237,7 @@ where
|
||||
},
|
||||
)
|
||||
.reduce(
|
||||
|| Vec::<(i64, Vec3)>::with_capacity(total_boid_count / 10),
|
||||
|| Vec::<(i64, Vec3)>::with_capacity(total_boid_count),
|
||||
|mut left, mut right| {
|
||||
left.append(&mut right);
|
||||
left
|
||||
@ -227,19 +245,19 @@ where
|
||||
);
|
||||
#[cfg(feature = "stats")]
|
||||
godot_print!(
|
||||
"[Boids] calculating all boids took {} ms",
|
||||
time.elapsed().as_millis()
|
||||
"[Boids] calculating all boids took {} micros",
|
||||
time.elapsed().as_micros()
|
||||
);
|
||||
|
||||
#[cfg(feature = "stats")]
|
||||
let time = std::time::Instant::now();
|
||||
for (boid_id, force) in forces {
|
||||
let boid = boids.get_mut(&boid_id).unwrap();
|
||||
let boid = unsafe { boids.get_mut(&boid_id).unwrap_unchecked() };
|
||||
boid.bind_mut().apply_force(force);
|
||||
}
|
||||
#[cfg(feature = "stats")]
|
||||
godot_print!(
|
||||
"[Boids] applying forces took {} ms",
|
||||
time.elapsed().as_millis()
|
||||
"[Boids] applying forces took {} micros",
|
||||
time.elapsed().as_micros()
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user