feat: add 3d nodes
This commit is contained in:
parent
2d11c9c9ec
commit
6b602b5731
@ -0,0 +1,101 @@
|
|||||||
|
use super::*;
|
||||||
|
use godot::prelude::*;
|
||||||
|
|
||||||
|
use crate::{to_glam_vec, BoidProperties, Flock3D};
|
||||||
|
|
||||||
|
#[derive(GodotClass)]
|
||||||
|
#[class(init, base=Node3D)]
|
||||||
|
pub struct Boid3D {
|
||||||
|
#[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: Vec3,
|
||||||
|
flock_id: i64,
|
||||||
|
base: Base<Node3D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[godot_api]
|
||||||
|
impl Boid3D {
|
||||||
|
#[func]
|
||||||
|
#[inline(always)]
|
||||||
|
/// Get the current velocity of this boid.
|
||||||
|
fn get_velocity(&self) -> Vector3 {
|
||||||
|
Vector3::new(self.vel.x, self.vel.y, self.vel.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[godot_api]
|
||||||
|
impl INode3D for Boid3D {
|
||||||
|
fn enter_tree(&mut self) {
|
||||||
|
let Some(mut flock) = self
|
||||||
|
.to_gd()
|
||||||
|
.get_parent()
|
||||||
|
.and_then(|gd| gd.try_cast::<Flock3D>().ok())
|
||||||
|
else {
|
||||||
|
let boid_id = self.get_id();
|
||||||
|
godot_error!("[Boid3D:{boid_id}] boids parent isn't a Flock3D, or has no parent");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let mut flock = flock.bind_mut();
|
||||||
|
flock.register_boid(self.get_id());
|
||||||
|
self.flock_id = flock.get_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ready(&mut self) {
|
||||||
|
self.props = self.properties.bind().clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exit_tree(&mut self) {
|
||||||
|
let mut flock = godot::global::instance_from_id(self.get_flock_id())
|
||||||
|
.unwrap()
|
||||||
|
.cast::<Flock3D>();
|
||||||
|
flock.bind_mut().unregister_boid(self.get_id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Boid for Boid3D {
|
||||||
|
#[inline(always)]
|
||||||
|
fn apply_force(&mut self, force: Vec3) {
|
||||||
|
self.vel += force;
|
||||||
|
let new_vel = self.vel.clamp_length_max(self.props.max_speed);
|
||||||
|
self.vel = new_vel;
|
||||||
|
self.base_mut()
|
||||||
|
.translate(Vector3::new(new_vel.x, new_vel.y, new_vel.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_boid_position(&self) -> Vec3 {
|
||||||
|
to_glam_vec(self.base().get_position())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_boid_velocity(&self) -> Vec3 {
|
||||||
|
self.vel
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_boid_properties(&self) -> &BoidProperties {
|
||||||
|
&self.props
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_flock_id(&self) -> i64 {
|
||||||
|
self.get_flock_id()
|
||||||
|
}
|
||||||
|
}
|
104
rust/src/flock/flock_3d.rs
Normal file
104
rust/src/flock/flock_3d.rs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
use glam::*;
|
||||||
|
use godot::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
get_singleton, to_glam_vec, Boid, Boid3D, BoidProperties, FlockProperties, FxIndexMap,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::Flock;
|
||||||
|
|
||||||
|
#[derive(GodotClass)]
|
||||||
|
#[class(init, base=Node3D)]
|
||||||
|
pub struct Flock3D {
|
||||||
|
#[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<Node3D>>,
|
||||||
|
pub boids: FxIndexMap<i64, Gd<Boid3D>>,
|
||||||
|
base: Base<Node3D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Flock3D {
|
||||||
|
pub fn register_boid(&mut self, boid_id: i64) {
|
||||||
|
let boid: Gd<Boid3D> = godot::global::instance_from_id(boid_id).unwrap().cast();
|
||||||
|
self.boids.insert(boid_id, boid.clone());
|
||||||
|
get_singleton().bind_mut().register_boid_3d(boid_id, boid);
|
||||||
|
let flock_id = self.get_id();
|
||||||
|
godot_print!("[Flock3D:{flock_id}] boid {boid_id} registered");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unregister_boid(&mut self, boid_id: i64) {
|
||||||
|
self.boids.shift_remove(&boid_id);
|
||||||
|
get_singleton().bind_mut().unregister_boid_3d(boid_id);
|
||||||
|
let flock_id = self.get_id();
|
||||||
|
godot_print!("[Flock3D:{flock_id}] boid {boid_id} unregistered");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[godot_api]
|
||||||
|
impl INode3D for Flock3D {
|
||||||
|
fn enter_tree(&mut self) {
|
||||||
|
get_singleton().bind_mut().register_flock_3d(self.get_id())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ready(&mut self) {
|
||||||
|
self.props = self.properties.bind().clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exit_tree(&mut self) {
|
||||||
|
get_singleton()
|
||||||
|
.bind_mut()
|
||||||
|
.unregister_flock_3d(self.get_id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[godot_api]
|
||||||
|
impl Flock3D {
|
||||||
|
#[func]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_id(&self) -> i64 {
|
||||||
|
self.base().instance_id().to_i64()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Flock for Flock3D {
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_flock_properties(&self) -> &FlockProperties {
|
||||||
|
&self.props
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_target_position(&self) -> Option<Vec3> {
|
||||||
|
self.target.as_ref().map(|t| to_glam_vec(t.get_position()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_boids_posvel(&self) -> Vec<(Vec3, Vec3)> {
|
||||||
|
let boid_count = self.boids.len();
|
||||||
|
let mut result = Vec::with_capacity(boid_count);
|
||||||
|
result.extend(self.boids.values().map(|b| {
|
||||||
|
let b = b.bind();
|
||||||
|
(b.get_boid_position(), b.get_boid_velocity())
|
||||||
|
}));
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_boids(&self) -> impl Iterator<Item = (&i64, (Vec3, Vec3, BoidProperties))> {
|
||||||
|
self.boids.iter().map(|(id, boid)| {
|
||||||
|
let boid = boid.bind();
|
||||||
|
(
|
||||||
|
id,
|
||||||
|
(
|
||||||
|
boid.get_boid_position(),
|
||||||
|
boid.get_boid_velocity(),
|
||||||
|
boid.get_boid_properties().clone(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ use crate::{BoidProperties, FlockProperties};
|
|||||||
use glam::*;
|
use glam::*;
|
||||||
|
|
||||||
pub mod flock_2d;
|
pub mod flock_2d;
|
||||||
|
pub mod flock_3d;
|
||||||
|
|
||||||
pub trait Flock {
|
pub trait Flock {
|
||||||
fn get_flock_properties(&self) -> &FlockProperties;
|
fn get_flock_properties(&self) -> &FlockProperties;
|
||||||
|
@ -16,7 +16,7 @@ mod flock_properties;
|
|||||||
|
|
||||||
pub use boid::{boid_2d::*, boid_3d::*, Boid};
|
pub use boid::{boid_2d::*, boid_3d::*, Boid};
|
||||||
pub use boid_properties::BoidProperties;
|
pub use boid_properties::BoidProperties;
|
||||||
pub use flock::{flock_2d::*, Flock};
|
pub use flock::{flock_2d::*, flock_3d::*, Flock};
|
||||||
pub use flock_properties::FlockProperties;
|
pub use flock_properties::FlockProperties;
|
||||||
|
|
||||||
use rustc_hash::FxBuildHasher;
|
use rustc_hash::FxBuildHasher;
|
||||||
@ -115,8 +115,13 @@ impl INode for BoidsProcess {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn physics_process(&mut self, _: f64) {
|
fn physics_process(&mut self, _: f64) {
|
||||||
if self.get_engine_singleton().get_physics_frames() % (self.process_per_tick as u64) == 0 {
|
if self.get_engine_singleton().get_physics_frames() % (self.process_per_tick as u64) == 0 {
|
||||||
if self.process_2d {
|
let (process_2d, process_3d) = (self.process_2d, self.process_3d);
|
||||||
self.get_boids_singleton().bind_mut().process_boids_2d();
|
let mut s = self.get_boids_singleton().bind_mut();
|
||||||
|
if process_2d {
|
||||||
|
s.process_boids_2d();
|
||||||
|
}
|
||||||
|
if process_3d {
|
||||||
|
s.process_boids_3d();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,6 +133,8 @@ impl INode for BoidsProcess {
|
|||||||
struct Boids {
|
struct Boids {
|
||||||
flocks2d: FxIndexMap<i64, Gd<Flock2D>>,
|
flocks2d: FxIndexMap<i64, Gd<Flock2D>>,
|
||||||
boids2d: FxIndexMap<i64, Gd<Boid2D>>,
|
boids2d: FxIndexMap<i64, Gd<Boid2D>>,
|
||||||
|
flocks3d: FxIndexMap<i64, Gd<Flock3D>>,
|
||||||
|
boids3d: FxIndexMap<i64, Gd<Boid3D>>,
|
||||||
base: Base<Object>,
|
base: Base<Object>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,6 +159,27 @@ impl Boids {
|
|||||||
fn unregister_boid_2d(&mut self, boid_id: i64) {
|
fn unregister_boid_2d(&mut self, boid_id: i64) {
|
||||||
self.boids2d.shift_remove(&boid_id);
|
self.boids2d.shift_remove(&boid_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_flock_3d(&mut self, flock_id: i64) {
|
||||||
|
let flock = godot::global::instance_from_id(flock_id).unwrap().cast();
|
||||||
|
self.flocks3d.insert(flock_id, flock);
|
||||||
|
godot_print!("[Boids] flock {flock_id} registered");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unregister_flock_3d(&mut self, flock_id: i64) {
|
||||||
|
self.flocks3d.shift_remove(&flock_id);
|
||||||
|
godot_print!("[Boids] flock {flock_id} unregistered");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn register_boid_3d(&mut self, boid_id: i64, boid: Gd<Boid3D>) {
|
||||||
|
self.boids3d.insert(boid_id, boid);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn unregister_boid_3d(&mut self, boid_id: i64) {
|
||||||
|
self.boids3d.shift_remove(&boid_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[godot_api]
|
#[godot_api]
|
||||||
@ -164,6 +192,14 @@ impl Boids {
|
|||||||
process_boids(&mut self.boids2d, &self.flocks2d)
|
process_boids(&mut self.boids2d, &self.flocks2d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[func]
|
||||||
|
#[inline(always)]
|
||||||
|
/// Process all 3D boids once.
|
||||||
|
/// NOTE: This function is not intended to be manually called. Prefer using `BoidsProcess` as an autoload singleton where possible.
|
||||||
|
fn process_boids_3d(&mut self) {
|
||||||
|
process_boids(&mut self.boids3d, &self.flocks3d)
|
||||||
|
}
|
||||||
|
|
||||||
#[func]
|
#[func]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
/// Gets the total 2D boid count.
|
/// Gets the total 2D boid count.
|
||||||
@ -177,6 +213,20 @@ impl Boids {
|
|||||||
fn get_total_flock_2d_count(&self) -> i64 {
|
fn get_total_flock_2d_count(&self) -> i64 {
|
||||||
self.flocks2d.len() as i64
|
self.flocks2d.len() as i64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[func]
|
||||||
|
#[inline(always)]
|
||||||
|
/// Gets the total 3D boid count.
|
||||||
|
fn get_total_boid_3d_count(&self) -> i64 {
|
||||||
|
self.boids3d.len() as i64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[func]
|
||||||
|
#[inline(always)]
|
||||||
|
/// Gets the total 3D flock count.
|
||||||
|
fn get_total_flock_3d_count(&self) -> i64 {
|
||||||
|
self.flocks3d.len() as i64
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
Loading…
Reference in New Issue
Block a user