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::<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)
@ -45,6 +47,10 @@ fn main() {
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
#[derive(Component, Debug, Default)]
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
#[derive(Component, Debug)]
struct ShapePiece;
#[relationship(relationship_target = ShapeBlocks)]
struct BlockOf {
#[relationship]
parent: Entity,
}
#[derive(Component, Debug)]
#[require(GridPosition)]
struct RelativePosition {
x: i8,
y: i8,
@ -91,14 +107,14 @@ impl From<(i8, i8)> for RelativePosition {
#[derive(Component, Debug, Clone, Copy, PartialEq)]
#[require(Transform, Visibility)]
struct GridPosition {
x: usize,
y: usize,
x: u32,
y: u32,
}
impl GridPosition {
fn move_up(&self) -> Self {
Self {
y: if self.y + 1 < 20 {
y: if self.y + 1 < Y_MAX {
self.y.saturating_add(1)
} else {
self.y
@ -123,7 +139,7 @@ impl GridPosition {
fn move_right(&mut self) -> Self {
Self {
x: if self.x + 1 < 10 {
x: if self.x + 1 < X_MAX {
self.x.saturating_add(1)
} else {
self.x
@ -131,11 +147,23 @@ impl GridPosition {
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 {
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 {
fn from((x, y): (usize, usize)) -> GridPosition {
impl From<(u32, u32)> for GridPosition {
fn from((x, y): (u32, u32)) -> GridPosition {
GridPosition { x, y }
}
}
@ -242,8 +270,6 @@ fn init_pieces(
}),
mesh: meshes.add(Rectangle::new(SCALE, SCALE)),
});
commands.spawn((Orientation::default(), GridPosition::default(), Shape::T));
}
fn init_debug_ui(
@ -273,8 +299,9 @@ fn set_piece(
debug!("{e:?} {s:?} {o:?}");
commands
.entity(e)
.despawn_related::<Children>()
.with_children(|parent| {
// TODO: Just move entities, do not de/re-spawn
.despawn_related::<ShapeBlocks>()
.with_related_entities::<BlockOf>(|parent| {
let mesh = visuals.mesh.clone();
let mat = visuals.material.clone();
@ -416,17 +443,17 @@ fn set_piece(
fn set_relative_piece_positions(
query: Query<
(Entity, &RelativePosition),
(Entity, &RelativePosition, &BlockOf),
Or<(Added<RelativePosition>, Changed<RelativePosition>)>,
>,
gp: Query<&GridPosition>,
mut commands: Commands,
) {
query.iter().for_each(|(e, rp)| {
commands.entity(e).insert(Transform::from_xyz(
(rp.x as f32) * SCALE,
(rp.y as f32) * SCALE,
0.0,
));
query.iter().for_each(|(e, rp, co)| {
let parent_gp = gp.get(co.parent).unwrap();
let gp: GridPosition = parent_gp.add_offset(rp);
info!("Inserting {:?} for {:?} to {:?}", gp, rp, e);
commands.entity(e).insert(gp);
});
}
@ -481,14 +508,14 @@ fn draw_grid(mut gizmos: Gizmos) {
gizmos
.grid_2d(
Isometry2d::IDENTITY,
UVec2::new(10, 20),
UVec2::new(X_MAX, Y_MAX),
Vec2::new(SCALE, SCALE),
GREEN,
)
.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| {
let next = gp.move_down();
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