forked from bevyengine/bevy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## Objective - Add an arrow gizmo as suggested by bevyengine#9400 ## Solution (excuse my Protomen music) https://github.com/bevyengine/bevy/assets/14184826/192adf24-079f-4a4b-a17b-091e892974ec Wasn't horribly hard when i remembered i can change coordinate systems whenever I want. Gave them four tips (as suggested by @alice-i-cecile in discord) instead of trying to decide what direction the tips should point. Made the tip length default to 1/10 of the arrow's length, which looked good enough to me. Hard-coded the angle from the body to the tips to 45 degrees. ## Still TODO - [x] actual doc comments - [x] doctests - [x] `ArrowBuilder.with_tip_length()` --- ## Changelog - Added `gizmos.arrow()` and `gizmos.arrow_2d()` - Added arrows to `2d_gizmos` and `3d_gizmos` examples ## Migration Guide N/A --------- Co-authored-by: Nicola Papale <[email protected]>
- Loading branch information
1 parent
0689f4c
commit 183e39c
Showing
4 changed files
with
115 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
//! Additional Gizmo Functions -- Arrows | ||
|
||
use crate::prelude::Gizmos; | ||
use bevy_math::{Quat, Vec2, Vec3}; | ||
use bevy_render::color::Color; | ||
|
||
pub struct ArrowBuilder<'a, 's> { | ||
gizmos: &'a mut Gizmos<'s>, | ||
start: Vec3, | ||
end: Vec3, | ||
color: Color, | ||
tip_length: f32, | ||
} | ||
|
||
/// A builder returned by [`Gizmos::arrow`] and [`Gizmos::arrow_2d`] | ||
impl ArrowBuilder<'_, '_> { | ||
/// Change the length of the tips to be `length`. | ||
/// The default tip length is [length of the arrow]/10. | ||
/// | ||
/// # 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_tip_length(3.); | ||
/// } | ||
/// # bevy_ecs::system::assert_is_system(system); | ||
/// ``` | ||
#[doc(alias = "arrow_head_length")] | ||
pub fn with_tip_length(&mut self, length: f32) { | ||
self.tip_length = length; | ||
} | ||
} | ||
|
||
impl Drop for ArrowBuilder<'_, '_> { | ||
/// Draws the arrow, by drawing lines with the stored [`Gizmos`] | ||
fn drop(&mut self) { | ||
// first, draw the body of the arrow | ||
self.gizmos.line(self.start, self.end, self.color); | ||
// now the hard part is to draw the head in a sensible way | ||
// put us in a coordinate system where the arrow is pointing towards +x and ends at the origin | ||
let pointing = (self.end - self.start).normalize(); | ||
let rotation = Quat::from_rotation_arc(Vec3::X, pointing); | ||
let tips = [ | ||
Vec3::new(-1., 1., 0.), | ||
Vec3::new(-1., 0., 1.), | ||
Vec3::new(-1., -1., 0.), | ||
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); | ||
for v in tips { | ||
// then actually draw the tips | ||
self.gizmos.line(self.end, v, self.color); | ||
} | ||
} | ||
} | ||
|
||
impl<'s> Gizmos<'s> { | ||
/// Draw an arrow in 3D, from `start` to `end`. Has four tips for convienent viewing from any direction. | ||
/// | ||
/// This should be called for each frame the arrow needs to be rendered. | ||
/// | ||
/// # 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); | ||
/// } | ||
/// # bevy_ecs::system::assert_is_system(system); | ||
/// ``` | ||
pub fn arrow(&mut self, start: Vec3, end: Vec3, color: Color) -> ArrowBuilder<'_, 's> { | ||
let length = (end - start).length(); | ||
ArrowBuilder { | ||
gizmos: self, | ||
start, | ||
end, | ||
color, | ||
tip_length: length / 10., | ||
} | ||
} | ||
|
||
/// Draw an arrow in 2D (on the xy plane), from `start` to `end`. | ||
/// | ||
/// This should be called for each frame the arrow needs to be rendered. | ||
/// | ||
/// # Example | ||
/// ``` | ||
/// # use bevy_gizmos::prelude::*; | ||
/// # use bevy_render::prelude::*; | ||
/// # use bevy_math::prelude::*; | ||
/// fn system(mut gizmos: Gizmos) { | ||
/// gizmos.arrow_2d(Vec2::ZERO, Vec2::X, Color::GREEN); | ||
/// } | ||
/// # bevy_ecs::system::assert_is_system(system); | ||
/// ``` | ||
pub fn arrow_2d(&mut self, start: Vec2, end: Vec2, color: Color) -> ArrowBuilder<'_, 's> { | ||
self.arrow(start.extend(0.), end.extend(0.), color) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters