1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#![warn(missing_docs)]

//! # tahga::pursuit::boids
//!
//! The boids module implements a version of the boids flocking algorithm

use nannou::App;
use nannou::prelude::*;

use boid::Boid;

pub mod boid;

/// A struct holding a list of all boids
pub struct Boids {
    /// The list of boids
    pub boids: Vec<boid::Boid>,
    /// The range at which a boid can see other boids
    pub visual_range: f32,
    /// The max speed of this boid
    pub max_speed: f32,
    /// Not currently used
    max_affect: f32,
    /// Not currently used
    border: f32,
}

impl Boids {
    /// Create a new instance of [`Boids`], populated with default values and an empty list
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::prelude::*;
    /// use tahga::pursuit::boids::Boids;
    /// let b = Boids::new();
    /// assert_eq!(b.visual_range, 75.);
    /// assert_eq!(b.max_speed, 15.);
    /// ```
    ///
    pub fn new() -> Self {
        Boids {
            boids: Vec::new(),
            visual_range: 75.,
            max_speed: 15.,
            max_affect: 0.8,
            border: 15.,
        }
    }

    /// Create a new [`Boid`]
    ///
    /// This is just a wrapper around [`Boid`::new()]. It also sets the options using the current stored values.
    ///
    /// # Arguments
    ///
    /// `position` - The position of the new [`Boid`]
    ///
    /// `velocity` - The velocity of the new [`Boid`]
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::prelude::*;
    /// use tahga::pursuit::boids::Boids;
    /// let b = Boids::new();
    /// let nb = b.new_boid(vec2(0., 0.), vec2(10.,10.));
    /// assert_eq!(nb.visual_range, 75.);
    /// assert_eq!(nb.max_speed, 15.);
    /// ```
    ///
    pub fn new_boid(&self, position: Vec2, velocity: Vec2) -> Boid {
        Boid::new(self.boids.len() as u32, position, velocity)
            .visual_range(self.visual_range)
            .max_speed(self.max_speed)
            .max_affect(self.max_affect)
            .border(self.border)
    }

    /// Add a [`Boid`] to the list
    ///
    /// # Arguments
    ///
    /// `boid` - A [`Boid`] to add
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::prelude::*;
    /// use tahga::pursuit::boids::Boids;
    /// let mut b = Boids::new();
    /// let nb = b.new_boid(vec2(0., 0.), vec2(10.,10.));
    /// b.add_boid(nb);
    /// assert_eq!(b.boids[0].visual_range, 75.);
    /// assert_eq!(b.boids[0].max_speed, 15.);
    /// ```
    ///
    pub fn add_boid(&mut self, boid: Boid) {
        self.boids.push(boid);
    }

    /// Update all the boids in the list
    ///
    /// # Arguments
    ///
    /// `app` - The nannou app opject
    ///
    pub fn update(&mut self, app: &App) {
        let rect = app.window_rect();
        for i in 0..self.boids.len() {
            let mut boid = self.boids[i].clone();
            boid.update(&self.boids, &rect);
            self.boids[i] = boid;
        }
    }
}