Skip to content

Arrow Head Generalization #10661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 75 additions & 5 deletions crates/bevy_gizmos/src/arrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,29 @@ pub struct ArrowBuilder<'a, 's> {
gizmos: &'a mut Gizmos<'s>,
start: Vec3,
end: Vec3,
front: ArrowHead,
back: ArrowHead,
color: Color,
tip_length: f32,
double_ended: bool,
}

/// Represents how the end of an arrow should be drawn.
/// See also [`Gizmos::arrow`] and [`Gizmos::arrow_2d`].
#[derive(Default, Debug, Copy, Clone)]
pub enum ArrowHead {
/// No head. Putting this on both ends causes the arrow to just be a line.
None,
/// General-purpose arrow head with four tips for viewing from any angle. Default
#[default]
Normal,
/// Two-tip arrow head, facing as close to `towards` as possible while still being inline with the arrow body
Billboarded(
/// Will attempt to be most visible from this direction.
/// - in 3d applications, this would typically be the camera position.
/// - in 2d applications, this would typically be [`Vec3::Y`] or [`Vec3::Z`]
Vec3,
),
}

impl ArrowBuilder<'_, '_> {
Expand All @@ -32,8 +53,47 @@ impl ArrowBuilder<'_, '_> {
/// # bevy_ecs::system::assert_is_system(system);
/// ```
#[doc(alias = "arrow_head_length")]
pub fn with_tip_length(&mut self, length: f32) {
pub fn with_tip_length(&mut self, length: f32) -> &mut Self {
self.tip_length = length;
self
}

/// Make the arrow double-ended.
/// sets both ends of the arrow to [`ArrowHead::Normal`]
/// if you want to use a different head, use [`ArrowBuilder::???`]
///
/// # Example
/// ```
/// # use bevy_gizmos::prelude::*;
/// # use bevy_render::prelude::*;
/// # use bevy_math::prelude::*;
/// fn system(mut gizmos: Gizmos) {
/// gizmos.arrow(Vec3::ZERO, Vec3::ONE, Color::GREEN)
/// .double_ended();
/// }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
pub fn double_ended(&mut self) -> &mut Self {
self.double_ended = true;
return self;
}

/// Make the arrow single-ended (the default).
///
/// # Example
/// ```
/// # use bevy_gizmos::prelude::*;
/// # use bevy_render::prelude::*;
/// # use bevy_math::prelude::*;
/// fn system(mut gizmos: Gizmos) {
/// gizmos.arrow(Vec3::ZERO, Vec3::ONE, Color::GREEN)
/// .with_double_ended();
/// }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
pub fn with_single_ended(&mut self) -> &mut Self {
self.double_ended = false;
return self;
}
}

Expand All @@ -53,12 +113,21 @@ impl Drop for ArrowBuilder<'_, '_> {
Vec3::new(-1., 0., -1.),
];
// - extend the vectors so their length is `tip_length`
// - rotate the world so +x is facing in the same direction as the arrow
// - translate over to the tip of the arrow
let tips = tips.map(|v| rotation * (v.normalize() * self.tip_length) + self.end);
let tips = tips.map(|v| (v.normalize() * self.tip_length));
for v in tips {
// - rotate the world so +x is facing in the same direction as the arrow
// - translate over to the tip of the arrow
// then actually draw the tips
self.gizmos.line(self.end, v, self.color);
self.gizmos
.line(self.end, self.end + (rotation * v), self.color);
}
if self.double_ended {
// same thing but draw starting from the start and use the inverse rotation
let rotation = Quat::from_rotation_arc(Vec3::NEG_X, pointing);
for v in tips {
self.gizmos
.line(self.start, self.start + (rotation * v), self.color);
}
}
}
}
Expand Down Expand Up @@ -86,6 +155,7 @@ impl<'s> Gizmos<'s> {
end,
color,
tip_length: length / 10.,
double_ended: false,
}
}

Expand Down