1use glam::{Vec2, Vec3, Vec4};
4use super::entity_curves::{CurveEntity, EntityCurve, CurveType};
5use crate::math::MathFunction;
6use std::f32::consts::{PI, TAU, FRAC_PI_2};
7
8pub struct CurveTemplates;
9
10impl CurveTemplates {
11 pub fn mage(position: Vec3) -> CurveEntity {
13 let mut ent = CurveEntity::new("Mage", position);
14 let blue = Vec4::new(0.3, 0.5, 1.0, 0.9);
15 let light_blue = Vec4::new(0.5, 0.7, 1.0, 0.8);
16 let gold = Vec4::new(1.0, 0.8, 0.3, 0.9);
17
18 ent.add_curve(EntityCurve::new(CurveType::Bezier { degree: 3 }, vec![
20 Vec2::new(0.0, 0.8), Vec2::new(-0.4, 0.5), Vec2::new(-0.3, -0.2),
21 Vec2::new(0.0, -0.4), Vec2::new(0.3, -0.2), Vec2::new(0.4, 0.5), Vec2::new(0.0, 0.8),
22 ]).with_color(blue).with_emission(1.2).with_thickness(0.04).with_closed(true).with_stiffness(2.0));
23
24 ent.add_curve(EntityCurve::new(
26 CurveType::Circle { radius: 0.25, distortion: Some(MathFunction::Sine { amplitude: 0.05, frequency: 3.0, phase: 0.0 }) },
27 vec![Vec2::new(0.0, 1.1)],
28 ).with_color(light_blue).with_emission(1.5).with_thickness(0.035).with_stiffness(2.5));
29
30 ent.add_curve(EntityCurve::new(
32 CurveType::Lissajous { a: 2.0, b: 3.0, delta: FRAC_PI_2 },
33 vec![Vec2::new(-0.5, 0.5), Vec2::new(0.3, 0.4)],
34 ).with_color(light_blue).with_emission(0.8).with_thickness(0.025).with_segments(48));
35
36 ent.add_curve(EntityCurve::new(
38 CurveType::Lissajous { a: 2.0, b: 3.0, delta: -FRAC_PI_2 },
39 vec![Vec2::new(0.5, 0.5), Vec2::new(0.3, 0.4)],
40 ).with_color(light_blue).with_emission(0.8).with_thickness(0.025).with_segments(48));
41
42 ent.add_curve(EntityCurve::new(CurveType::Bezier { degree: 1 }, vec![
44 Vec2::new(0.6, 0.3), Vec2::new(0.7, 1.3),
45 ]).with_color(gold).with_emission(0.6).with_thickness(0.02).with_stiffness(3.0));
46
47 ent.add_curve(EntityCurve::new(
49 CurveType::Circle { radius: 0.1, distortion: Some(MathFunction::Breathing { rate: 2.0, depth: 0.3 }) },
50 vec![Vec2::new(0.7, 1.4)],
51 ).with_color(Vec4::new(0.8, 0.9, 1.0, 1.0)).with_emission(2.5).with_thickness(0.03).with_stiffness(1.5));
52
53 ent.add_curve(EntityCurve::new(CurveType::Bezier { degree: 2 }, vec![
55 Vec2::new(-0.1, -0.4), Vec2::new(-0.2, -0.8), Vec2::new(-0.3, -1.2),
56 ]).with_color(blue).with_emission(0.6).with_thickness(0.025));
57 ent.add_curve(EntityCurve::new(CurveType::Bezier { degree: 2 }, vec![
58 Vec2::new(0.1, -0.4), Vec2::new(0.2, -0.8), Vec2::new(0.3, -1.2),
59 ]).with_color(blue).with_emission(0.6).with_thickness(0.025));
60
61 ent
62 }
63
64 pub fn beast(position: Vec3) -> CurveEntity {
66 let mut ent = CurveEntity::new("Beast", position);
67 let red = Vec4::new(0.9, 0.2, 0.3, 0.9);
68 let dark_red = Vec4::new(0.7, 0.1, 0.2, 0.8);
69
70 ent.add_curve(EntityCurve::new(
72 CurveType::Hypotrochoid { big_r: 1.0, small_r: 0.4, d: 0.6 },
73 vec![Vec2::ZERO],
74 ).with_color(red).with_emission(1.0).with_thickness(0.04).with_stiffness(1.5));
75
76 ent.add_curve(EntityCurve::new(
78 CurveType::Superellipse { a: 0.3, b: 0.25, n: 3.0 },
79 vec![Vec2::new(0.0, 0.8)],
80 ).with_color(red).with_emission(1.3).with_thickness(0.035));
81
82 for i in 0..4 {
84 let x = (i as f32 - 1.5) * 0.4;
85 ent.add_curve(EntityCurve::new(CurveType::Bezier { degree: 2 }, vec![
86 Vec2::new(x, -0.3), Vec2::new(x - 0.1, -0.7), Vec2::new(x, -1.0),
87 ]).with_color(dark_red).with_emission(0.5).with_thickness(0.025));
88 }
89
90 ent.add_curve(EntityCurve::new(
92 CurveType::Spiral { rate: 0.15, decay: 0.3 },
93 vec![Vec2::new(-0.8, 0.0)],
94 ).with_color(dark_red).with_emission(0.7).with_thickness(0.02).with_segments(80));
95
96 ent
97 }
98
99 pub fn elemental(position: Vec3) -> CurveEntity {
101 let mut ent = CurveEntity::new("Elemental", position);
102 ent.breath_amplitude = 0.06; let colors = [
105 Vec4::new(1.0, 0.4, 0.1, 0.85), Vec4::new(1.0, 0.6, 0.2, 0.8),
107 Vec4::new(1.0, 0.8, 0.3, 0.7),
108 ];
109
110 for i in 0..3 {
112 let k = (i + 3) as f32;
113 ent.add_curve(EntityCurve::new(
114 CurveType::Rose { k, amplitude: 0.8 - i as f32 * 0.15 },
115 vec![Vec2::ZERO],
116 ).with_color(colors[i]).with_emission(1.5 - i as f32 * 0.3)
117 .with_thickness(0.035 - i as f32 * 0.005).with_segments(96).with_stiffness(1.0));
118 }
119
120 ent.add_curve(EntityCurve::new(
122 CurveType::Circle { radius: 0.15, distortion: Some(MathFunction::Breathing { rate: 3.0, depth: 0.5 }) },
123 vec![Vec2::ZERO],
124 ).with_color(Vec4::new(1.0, 0.9, 0.5, 1.0)).with_emission(3.0).with_thickness(0.04));
125
126 ent
127 }
128
129 pub fn boss(position: Vec3) -> CurveEntity {
131 let mut ent = CurveEntity::new("Boss", position);
132 ent.breath_rate = 0.25;
133 ent.breath_amplitude = 0.04;
134
135 let purple = Vec4::new(0.7, 0.2, 1.0, 0.9);
136 let dark_purple = Vec4::new(0.5, 0.1, 0.8, 0.8);
137 let gold = Vec4::new(1.0, 0.8, 0.2, 0.85);
138
139 for i in 0..4 {
141 let phase = i as f32 * PI * 0.5;
142 ent.add_curve(EntityCurve::new(
143 CurveType::Lissajous { a: 3.0 + i as f32 * 0.5, b: 2.0 + i as f32 * 0.3, delta: phase },
144 vec![Vec2::ZERO, Vec2::splat(1.2 - i as f32 * 0.15)],
145 ).with_color(if i % 2 == 0 { purple } else { dark_purple })
146 .with_emission(1.2).with_thickness(0.03).with_segments(128));
147 }
148
149 ent.add_curve(EntityCurve::new(
151 CurveType::Hypotrochoid { big_r: 0.8, small_r: 0.3, d: 0.5 },
152 vec![Vec2::ZERO],
153 ).with_color(gold).with_emission(2.0).with_thickness(0.04).with_segments(96));
154
155 ent.add_curve(EntityCurve::new(
157 CurveType::Rose { k: 6.0, amplitude: 1.5 },
158 vec![Vec2::ZERO],
159 ).with_color(purple).with_emission(0.8).with_thickness(0.02).with_segments(128)
160 .with_dash(0.1, 0.05));
161
162 ent.add_curve(EntityCurve::new(
164 CurveType::Circle { radius: 0.08, distortion: None },
165 vec![Vec2::new(-0.2, 0.3)],
166 ).with_color(Vec4::new(1.0, 0.9, 0.1, 1.0)).with_emission(2.5).with_thickness(0.03));
167 ent.add_curve(EntityCurve::new(
168 CurveType::Circle { radius: 0.08, distortion: None },
169 vec![Vec2::new(0.2, 0.3)],
170 ).with_color(Vec4::new(1.0, 0.9, 0.1, 1.0)).with_emission(2.5).with_thickness(0.03));
171
172 ent
173 }
174
175 pub fn simple_circle(position: Vec3, radius: f32, color: Vec4) -> CurveEntity {
177 let mut ent = CurveEntity::new("Circle", position);
178 ent.add_curve(EntityCurve::new(
179 CurveType::Circle { radius, distortion: None },
180 vec![Vec2::ZERO],
181 ).with_color(color).with_emission(1.0).with_thickness(0.03));
182 ent
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn test_mage_template() {
192 let mage = CurveTemplates::mage(Vec3::ZERO);
193 assert!(mage.curves.len() >= 7, "mage should have multiple curves");
194 assert!(mage.alive);
195 }
196
197 #[test]
198 fn test_boss_template() {
199 let boss = CurveTemplates::boss(Vec3::ZERO);
200 assert!(boss.curves.len() >= 7, "boss should be complex");
201 }
202
203 #[test]
204 fn test_elemental_template() {
205 let elem = CurveTemplates::elemental(Vec3::ZERO);
206 assert!(elem.curves.len() >= 3);
207 }
208}