Moved away from childof relationship!

Instead of using ChildOf, which has Transform implications, we created
our own relationship:

    ShapeBlocks(Vec<Entity>) <-> BlockOf { parent: Entity }

This relationship just informs how to place blocks with a
RelativePosition near their GridPosition parents without having to deal
with the Transform of the parent.
main
Elijah Voigt 2 weeks ago
parent fb535106ca
commit b51884ac69

@ -37,6 +37,8 @@ fn main() {
), ),
sync_singleton_to_ui::<Shape>.run_if(any_component_changed::<Shape>), sync_singleton_to_ui::<Shape>.run_if(any_component_changed::<Shape>),
sync_singleton_to_ui::<Orientation>.run_if(any_component_changed::<Orientation>), sync_singleton_to_ui::<Orientation>.run_if(any_component_changed::<Orientation>),
check_collision.run_if(any_component_changed::<GridPosition>),
add_piece.run_if(not(any_with_component::<Shape>)),
), ),
) )
.add_systems(Update, draw_grid) .add_systems(Update, draw_grid)
@ -45,6 +47,10 @@ fn main() {
const SCALE: f32 = 30.0; const SCALE: f32 = 30.0;
// Declare the size of the play area
const X_MAX: u32 = 10;
const Y_MAX: u32 = 20;
/// A shape, e.g., the long piece /// A shape, e.g., the long piece
#[derive(Component, Debug, Default)] #[derive(Component, Debug, Default)]
enum Shape { enum Shape {
@ -72,11 +78,21 @@ impl Display for Shape {
} }
} }
// The blocks making up this shape
#[derive(Component)]
#[relationship_target(relationship = BlockOf)]
struct ShapeBlocks(Vec<Entity>);
/// A part of a piece, i.e., a single square of a piece /// A part of a piece, i.e., a single square of a piece
#[derive(Component, Debug)] #[derive(Component, Debug)]
struct ShapePiece; #[relationship(relationship_target = ShapeBlocks)]
struct BlockOf {
#[relationship]
parent: Entity,
}
#[derive(Component, Debug)] #[derive(Component, Debug)]
#[require(GridPosition)]
struct RelativePosition { struct RelativePosition {
x: i8, x: i8,
y: i8, y: i8,
@ -91,14 +107,14 @@ impl From<(i8, i8)> for RelativePosition {
#[derive(Component, Debug, Clone, Copy, PartialEq)] #[derive(Component, Debug, Clone, Copy, PartialEq)]
#[require(Transform, Visibility)] #[require(Transform, Visibility)]
struct GridPosition { struct GridPosition {
x: usize, x: u32,
y: usize, y: u32,
} }
impl GridPosition { impl GridPosition {
fn move_up(&self) -> Self { fn move_up(&self) -> Self {
Self { Self {
y: if self.y + 1 < 20 { y: if self.y + 1 < Y_MAX {
self.y.saturating_add(1) self.y.saturating_add(1)
} else { } else {
self.y self.y
@ -123,7 +139,7 @@ impl GridPosition {
fn move_right(&mut self) -> Self { fn move_right(&mut self) -> Self {
Self { Self {
x: if self.x + 1 < 10 { x: if self.x + 1 < X_MAX {
self.x.saturating_add(1) self.x.saturating_add(1)
} else { } else {
self.x self.x
@ -131,11 +147,23 @@ impl GridPosition {
y: self.y, y: self.y,
} }
} }
fn is_colliding_with(&self, other: &Self) -> bool {
self.x == other.x && self.y + 1 == other.y
}
fn add_offset(&self, RelativePosition { x: x1, y: y1 }: &RelativePosition) -> Self {
info!("{} + {}, {} + {}", self.x, *x1 as i32, self.y, *y1 as i32);
GridPosition {
x: self.x.checked_add_signed(*x1 as i32).unwrap(),
y: self.y.checked_add_signed(*y1 as i32).unwrap(),
}
}
} }
impl Default for GridPosition { impl Default for GridPosition {
fn default() -> Self { fn default() -> Self {
GridPosition { x: 5, y: 20 } GridPosition { x: 5, y: Y_MAX }
} }
} }
@ -154,8 +182,8 @@ impl From<&GridPosition> for Vec3 {
} }
} }
impl From<(usize, usize)> for GridPosition { impl From<(u32, u32)> for GridPosition {
fn from((x, y): (usize, usize)) -> GridPosition { fn from((x, y): (u32, u32)) -> GridPosition {
GridPosition { x, y } GridPosition { x, y }
} }
} }
@ -242,8 +270,6 @@ fn init_pieces(
}), }),
mesh: meshes.add(Rectangle::new(SCALE, SCALE)), mesh: meshes.add(Rectangle::new(SCALE, SCALE)),
}); });
commands.spawn((Orientation::default(), GridPosition::default(), Shape::T));
} }
fn init_debug_ui( fn init_debug_ui(
@ -273,8 +299,9 @@ fn set_piece(
debug!("{e:?} {s:?} {o:?}"); debug!("{e:?} {s:?} {o:?}");
commands commands
.entity(e) .entity(e)
.despawn_related::<Children>() // TODO: Just move entities, do not de/re-spawn
.with_children(|parent| { .despawn_related::<ShapeBlocks>()
.with_related_entities::<BlockOf>(|parent| {
let mesh = visuals.mesh.clone(); let mesh = visuals.mesh.clone();
let mat = visuals.material.clone(); let mat = visuals.material.clone();
@ -416,17 +443,17 @@ fn set_piece(
fn set_relative_piece_positions( fn set_relative_piece_positions(
query: Query< query: Query<
(Entity, &RelativePosition), (Entity, &RelativePosition, &BlockOf),
Or<(Added<RelativePosition>, Changed<RelativePosition>)>, Or<(Added<RelativePosition>, Changed<RelativePosition>)>,
>, >,
gp: Query<&GridPosition>,
mut commands: Commands, mut commands: Commands,
) { ) {
query.iter().for_each(|(e, rp)| { query.iter().for_each(|(e, rp, co)| {
commands.entity(e).insert(Transform::from_xyz( let parent_gp = gp.get(co.parent).unwrap();
(rp.x as f32) * SCALE, let gp: GridPosition = parent_gp.add_offset(rp);
(rp.y as f32) * SCALE, info!("Inserting {:?} for {:?} to {:?}", gp, rp, e);
0.0, commands.entity(e).insert(gp);
));
}); });
} }
@ -481,14 +508,14 @@ fn draw_grid(mut gizmos: Gizmos) {
gizmos gizmos
.grid_2d( .grid_2d(
Isometry2d::IDENTITY, Isometry2d::IDENTITY,
UVec2::new(10, 20), UVec2::new(X_MAX, Y_MAX),
Vec2::new(SCALE, SCALE), Vec2::new(SCALE, SCALE),
GREEN, GREEN,
) )
.outer_edges(); .outer_edges();
} }
fn falling(mut query: Query<&mut GridPosition, With<Shape>>) { fn falling(mut query: Query<&mut GridPosition>) {
query.iter_mut().for_each(|mut gp| { query.iter_mut().for_each(|mut gp| {
let next = gp.move_down(); let next = gp.move_down();
if next != *gp { if next != *gp {
@ -511,3 +538,35 @@ fn clock_cycle(n: f32) -> impl FnMut(Res<Time>, Local<f32>) -> bool {
} }
} }
} }
/// Check if the active piece is about to collide with the ground
fn check_collision(
active: Query<&GridPosition, With<RelativePosition>>,
inactive: Query<&GridPosition, Without<RelativePosition>>,
) {
// TODO: Easy optimizations
let hit = active.iter().any(|a| {
debug!("Checking: {:?}", a);
// Check if active piece is at floor
let hit_floor = a.y == 0;
// Check if active peice is near other pieces
let hit_piece = inactive.iter().any(|b| {
debug!("Checking against: {:?}", b);
a.is_colliding_with(b)
});
hit_floor || hit_piece
});
if hit {
info!("hit!")
// todo!("Do the thing!");
}
}
fn add_piece(
mut commands: Commands,
) {
// TODO: Choose a different piece
commands.spawn((Orientation::default(), GridPosition::default(), Shape::T));
}

Loading…
Cancel
Save