Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_gizmos/src/arrows.rs
6595 views
1
//! Additional [`GizmoBuffer`] Functions -- Arrows
2
//!
3
//! Includes the implementation of [`GizmoBuffer::arrow`] and [`GizmoBuffer::arrow_2d`],
4
//! and assorted support items.
5
6
use crate::{gizmos::GizmoBuffer, prelude::GizmoConfigGroup};
7
use bevy_color::{
8
palettes::basic::{BLUE, GREEN, RED},
9
Color,
10
};
11
use bevy_math::{Quat, Vec2, Vec3, Vec3Swizzles};
12
use bevy_transform::TransformPoint;
13
14
/// A builder returned by [`GizmoBuffer::arrow`] and [`GizmoBuffer::arrow_2d`]
15
pub struct ArrowBuilder<'a, Config, Clear>
16
where
17
Config: GizmoConfigGroup,
18
Clear: 'static + Send + Sync,
19
{
20
gizmos: &'a mut GizmoBuffer<Config, Clear>,
21
start: Vec3,
22
end: Vec3,
23
color: Color,
24
double_ended: bool,
25
tip_length: f32,
26
}
27
28
impl<Config, Clear> ArrowBuilder<'_, Config, Clear>
29
where
30
Config: GizmoConfigGroup,
31
Clear: 'static + Send + Sync,
32
{
33
/// Change the length of the tips to be `length`.
34
/// The default tip length is [length of the arrow]/10.
35
///
36
/// # Example
37
/// ```
38
/// # use bevy_gizmos::prelude::*;
39
/// # use bevy_math::prelude::*;
40
/// # use bevy_color::palettes::basic::GREEN;
41
/// fn system(mut gizmos: Gizmos) {
42
/// gizmos.arrow(Vec3::ZERO, Vec3::ONE, GREEN)
43
/// .with_tip_length(3.);
44
/// }
45
/// # bevy_ecs::system::assert_is_system(system);
46
/// ```
47
#[doc(alias = "arrow_head_length")]
48
pub fn with_tip_length(mut self, length: f32) -> Self {
49
self.tip_length = length;
50
self
51
}
52
53
/// Adds another tip to the arrow, appended in the start point.
54
/// the default is only one tip at the end point.
55
pub fn with_double_end(mut self) -> Self {
56
self.double_ended = true;
57
self
58
}
59
}
60
61
impl<Config, Clear> Drop for ArrowBuilder<'_, Config, Clear>
62
where
63
Config: GizmoConfigGroup,
64
Clear: 'static + Send + Sync,
65
{
66
/// Draws the arrow, by drawing lines with the stored [`GizmoBuffer`]
67
fn drop(&mut self) {
68
if !self.gizmos.enabled {
69
return;
70
}
71
// first, draw the body of the arrow
72
self.gizmos.line(self.start, self.end, self.color);
73
// now the hard part is to draw the head in a sensible way
74
// put us in a coordinate system where the arrow is pointing towards +x and ends at the origin
75
let pointing_end = (self.end - self.start).normalize();
76
let rotation_end = Quat::from_rotation_arc(Vec3::X, pointing_end);
77
let tips = [
78
Vec3::new(-1., 1., 0.),
79
Vec3::new(-1., 0., 1.),
80
Vec3::new(-1., -1., 0.),
81
Vec3::new(-1., 0., -1.),
82
];
83
// - extend the vectors so their length is `tip_length`
84
// - rotate the world so +x is facing in the same direction as the arrow
85
// - translate over to the tip of the arrow
86
let tips_end = tips.map(|v| rotation_end * (v.normalize() * self.tip_length) + self.end);
87
for v in tips_end {
88
// then actually draw the tips
89
self.gizmos.line(self.end, v, self.color);
90
}
91
if self.double_ended {
92
let pointing_start = (self.start - self.end).normalize();
93
let rotation_start = Quat::from_rotation_arc(Vec3::X, pointing_start);
94
let tips_start =
95
tips.map(|v| rotation_start * (v.normalize() * self.tip_length) + self.start);
96
for v in tips_start {
97
// draw the start points tips
98
self.gizmos.line(self.start, v, self.color);
99
}
100
}
101
}
102
}
103
104
impl<Config, Clear> GizmoBuffer<Config, Clear>
105
where
106
Config: GizmoConfigGroup,
107
Clear: 'static + Send + Sync,
108
{
109
/// Draw an arrow in 3D, from `start` to `end`. Has four tips for convenient viewing from any direction.
110
///
111
/// This should be called for each frame the arrow needs to be rendered.
112
///
113
/// # Example
114
/// ```
115
/// # use bevy_gizmos::prelude::*;
116
/// # use bevy_math::prelude::*;
117
/// # use bevy_color::palettes::basic::GREEN;
118
/// fn system(mut gizmos: Gizmos) {
119
/// gizmos.arrow(Vec3::ZERO, Vec3::ONE, GREEN);
120
/// }
121
/// # bevy_ecs::system::assert_is_system(system);
122
/// ```
123
pub fn arrow(
124
&mut self,
125
start: Vec3,
126
end: Vec3,
127
color: impl Into<Color>,
128
) -> ArrowBuilder<'_, Config, Clear> {
129
let length = (end - start).length();
130
ArrowBuilder {
131
gizmos: self,
132
start,
133
end,
134
color: color.into(),
135
double_ended: false,
136
tip_length: length / 10.,
137
}
138
}
139
140
/// Draw an arrow in 2D (on the xy plane), from `start` to `end`.
141
///
142
/// This should be called for each frame the arrow needs to be rendered.
143
///
144
/// # Example
145
/// ```
146
/// # use bevy_gizmos::prelude::*;
147
/// # use bevy_math::prelude::*;
148
/// # use bevy_color::palettes::basic::GREEN;
149
/// fn system(mut gizmos: Gizmos) {
150
/// gizmos.arrow_2d(Vec2::ZERO, Vec2::X, GREEN);
151
/// }
152
/// # bevy_ecs::system::assert_is_system(system);
153
/// ```
154
pub fn arrow_2d(
155
&mut self,
156
start: Vec2,
157
end: Vec2,
158
color: impl Into<Color>,
159
) -> ArrowBuilder<'_, Config, Clear> {
160
self.arrow(start.extend(0.), end.extend(0.), color)
161
}
162
}
163
164
impl<Config, Clear> GizmoBuffer<Config, Clear>
165
where
166
Config: GizmoConfigGroup,
167
Clear: 'static + Send + Sync,
168
{
169
/// Draw a set of axes local to the given transform (`transform`), with length scaled by a factor
170
/// of `base_length`.
171
///
172
/// This should be called for each frame the axes need to be rendered.
173
///
174
/// # Example
175
/// ```
176
/// # use bevy_gizmos::prelude::*;
177
/// # use bevy_ecs::prelude::*;
178
/// # use bevy_transform::components::Transform;
179
/// # #[derive(Component)]
180
/// # struct MyComponent;
181
/// fn draw_axes(
182
/// mut gizmos: Gizmos,
183
/// query: Query<&Transform, With<MyComponent>>,
184
/// ) {
185
/// for &transform in &query {
186
/// gizmos.axes(transform, 1.);
187
/// }
188
/// }
189
/// # bevy_ecs::system::assert_is_system(draw_axes);
190
/// ```
191
pub fn axes(&mut self, transform: impl TransformPoint, base_length: f32) {
192
let start = transform.transform_point(Vec3::ZERO);
193
let end_x = transform.transform_point(base_length * Vec3::X);
194
let end_y = transform.transform_point(base_length * Vec3::Y);
195
let end_z = transform.transform_point(base_length * Vec3::Z);
196
197
self.arrow(start, end_x, RED);
198
self.arrow(start, end_y, GREEN);
199
self.arrow(start, end_z, BLUE);
200
}
201
202
/// Draw a set of axes local to the given transform (`transform`), with length scaled by a factor
203
/// of `base_length`.
204
///
205
/// This should be called for each frame the axes need to be rendered.
206
///
207
/// # Example
208
/// ```
209
/// # use bevy_gizmos::prelude::*;
210
/// # use bevy_ecs::prelude::*;
211
/// # use bevy_transform::components::Transform;
212
/// # #[derive(Component)]
213
/// # struct AxesComponent;
214
/// fn draw_axes_2d(
215
/// mut gizmos: Gizmos,
216
/// query: Query<&Transform, With<AxesComponent>>,
217
/// ) {
218
/// for &transform in &query {
219
/// gizmos.axes_2d(transform, 1.);
220
/// }
221
/// }
222
/// # bevy_ecs::system::assert_is_system(draw_axes_2d);
223
/// ```
224
pub fn axes_2d(&mut self, transform: impl TransformPoint, base_length: f32) {
225
let start = transform.transform_point(Vec3::ZERO);
226
let end_x = transform.transform_point(base_length * Vec3::X);
227
let end_y = transform.transform_point(base_length * Vec3::Y);
228
229
self.arrow_2d(start.xy(), end_x.xy(), RED);
230
self.arrow_2d(start.xy(), end_y.xy(), GREEN);
231
}
232
}
233
234