azalea_core/
hit_result.rs

1use crate::{
2    direction::Direction,
3    position::{BlockPos, Vec3},
4};
5
6/// The block or entity that our player is looking at and can interact with.
7///
8/// If there's nothing, it'll be a [`BlockHitResult`] with `miss` set to true.
9#[cfg(feature = "bevy_ecs")]
10#[derive(Clone, Debug, PartialEq)]
11pub enum HitResult {
12    Block(BlockHitResult),
13    Entity(EntityHitResult),
14}
15
16#[cfg(feature = "bevy_ecs")]
17impl HitResult {
18    pub fn miss(&self) -> bool {
19        match self {
20            HitResult::Block(r) => r.miss,
21            _ => false,
22        }
23    }
24    pub fn location(&self) -> Vec3 {
25        match self {
26            HitResult::Block(r) => r.location,
27            HitResult::Entity(r) => r.location,
28        }
29    }
30
31    pub fn new_miss(location: Vec3, direction: Direction, block_pos: BlockPos) -> Self {
32        HitResult::Block(BlockHitResult {
33            location,
34            miss: true,
35            direction,
36            block_pos,
37            inside: false,
38            world_border: false,
39        })
40    }
41
42    pub fn is_block_hit_and_not_miss(&self) -> bool {
43        matches!(self, HitResult::Block(r) if !r.miss)
44    }
45
46    /// Returns the [`BlockHitResult`], if we were looking at a block.
47    pub fn as_block_hit_result_if_not_miss(&self) -> Option<&BlockHitResult> {
48        if let HitResult::Block(r) = self
49            && !r.miss
50        {
51            Some(r)
52        } else {
53            None
54        }
55    }
56
57    /// Returns the [`EntityHitResult`], if we were looking at an entity and it
58    /// wasn't a miss.
59    pub fn as_entity_hit_result(&self) -> Option<&EntityHitResult> {
60        if let HitResult::Entity(r) = self {
61            Some(r)
62        } else {
63            None
64        }
65    }
66}
67
68/// The result of raycasting on the blocks in the world.
69///
70/// Also see [`HitResult`].
71#[derive(Clone, Debug, PartialEq)]
72pub struct BlockHitResult {
73    /// The exact position that the raycast ended at.
74    pub location: Vec3,
75    pub miss: bool,
76
77    pub direction: Direction,
78    /// The block position that was hit.
79    ///
80    /// If [`Self::miss`] is true, then this will be the position that the
81    /// raycast ended at.
82    pub block_pos: BlockPos,
83    pub inside: bool,
84    pub world_border: bool,
85}
86impl BlockHitResult {
87    /// Create a new [`BlockHitResult`] for when nothing was hit.
88    pub fn miss(location: Vec3, direction: Direction) -> Self {
89        Self {
90            location,
91            miss: true,
92
93            direction,
94            block_pos: BlockPos::from(location),
95            inside: false,
96            world_border: false,
97        }
98    }
99
100    pub fn with_direction(&self, direction: Direction) -> Self {
101        Self { direction, ..*self }
102    }
103    pub fn with_position(&self, block_pos: BlockPos) -> Self {
104        Self { block_pos, ..*self }
105    }
106}
107#[cfg(feature = "bevy_ecs")]
108impl From<BlockHitResult> for HitResult {
109    fn from(value: BlockHitResult) -> Self {
110        HitResult::Block(value)
111    }
112}
113
114#[cfg(feature = "bevy_ecs")]
115#[derive(Clone, Debug, PartialEq)]
116pub struct EntityHitResult {
117    pub location: Vec3,
118    pub entity: bevy_ecs::entity::Entity,
119}
120
121#[cfg(feature = "bevy_ecs")]
122impl From<EntityHitResult> for HitResult {
123    fn from(value: EntityHitResult) -> Self {
124        HitResult::Entity(value)
125    }
126}