Tighten up tetrino grid movement

main
Elijah Voigt 2 months ago
parent b51884ac69
commit 2cab218e5c

@ -25,15 +25,16 @@ fn main() {
falling falling
.run_if(in_state(Falling::On)) .run_if(in_state(Falling::On))
.run_if(clock_cycle(1.0)), .run_if(clock_cycle(1.0)),
set_piece set_piece.run_if(
.run_if(any_component_added::<Shape> any_component_added::<Shape>
.or(any_component_changed::<Shape>) .or(any_component_changed::<Shape>)
.or(any_component_added::<Orientation>) .or(any_component_added::<Orientation>)
.or(any_component_changed::<Orientation>) .or(any_component_changed::<Orientation>),
), ),
set_relative_piece_positions.run_if( shape_block_movement.run_if(
any_component_added::<RelativePosition> any_component_added::<RelativePosition>
.or(any_component_changed::<RelativePosition>), .or(any_component_changed::<RelativePosition>)
.or(any_component_changed::<GridPosition>),
), ),
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>),
@ -153,7 +154,7 @@ impl GridPosition {
} }
fn add_offset(&self, RelativePosition { x: x1, y: y1 }: &RelativePosition) -> Self { fn add_offset(&self, RelativePosition { x: x1, y: y1 }: &RelativePosition) -> Self {
info!("{} + {}, {} + {}", self.x, *x1 as i32, self.y, *y1 as i32); debug!("{} + {}, {} + {}", self.x, *x1 as i32, self.y, *y1 as i32);
GridPosition { GridPosition {
x: self.x.checked_add_signed(*x1 as i32).unwrap(), x: self.x.checked_add_signed(*x1 as i32).unwrap(),
y: self.y.checked_add_signed(*y1 as i32).unwrap(), y: self.y.checked_add_signed(*y1 as i32).unwrap(),
@ -272,41 +273,33 @@ fn init_pieces(
}); });
} }
fn init_debug_ui( fn init_debug_ui(mut commands: Commands) {
mut commands: Commands, commands
) { .spawn((
commands.spawn((Node { Node {
top: Val::Px(0.0), top: Val::Px(0.0),
left: Val::Px(0.0), left: Val::Px(0.0),
..default() ..default()
}, DebuggingState::On)).with_children(|parent| { },
DebuggingState::On,
))
.with_children(|parent| {
parent.spawn(( parent.spawn((
Node::default(), Node::default(),
children![ children![
(Text::new("SHAPE"), SyncSingleton::<Shape>::default()), (Text::new("SHAPE"), SyncSingleton::<Shape>::default()),
(Text::new("ORIENTATION"), SyncSingleton::<Orientation>::default()), (
] Text::new("ORIENTATION"),
SyncSingleton::<Orientation>::default()
),
],
)); ));
}); });
} }
fn set_piece( #[rustfmt::skip]
query: Query<(Entity, &Shape, &Orientation), Or<(Added<Shape>, Changed<Shape>, Added<Orientation>, Changed<Orientation>)>>, fn block_positions(s: &Shape, o: &Orientation) -> [RelativePosition;4] {
mut commands: Commands, match s {
visuals: Res<Visuals>,
) {
query.iter().for_each(|(e, s, o)| {
debug!("{e:?} {s:?} {o:?}");
commands
.entity(e)
// 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();
#[rustfmt::skip]
let piece_positions: [RelativePosition;4] = match s {
Shape::O => [ Shape::O => [
(0,1).into(),(1,1).into(), (0,1).into(),(1,1).into(),
(0,0).into(),(1,0).into() (0,0).into(),(1,0).into()
@ -432,28 +425,44 @@ fn set_piece(
(-2,1).into(),(-1,1).into(),(0,1).into(),(1,1).into(), (-2,1).into(),(-1,1).into(),(0,1).into(),(1,1).into(),
] ]
} }
}; }
piece_positions.into_iter().for_each(|rp| {
parent.spawn((Mesh2d(mesh.clone()), MeshMaterial2d(mat.clone()), rp));
});
});
});
} }
fn set_relative_piece_positions( fn set_piece(
query: Query< query: Query<
(Entity, &RelativePosition, &BlockOf), (Entity, &Shape, &Orientation),
Or<(Added<RelativePosition>, Changed<RelativePosition>)>, Or<(
Added<Shape>,
Changed<Shape>,
Added<Orientation>,
Changed<Orientation>,
)>,
>, >,
gp: Query<&GridPosition>, mut blocks: Query<&mut RelativePosition, With<BlockOf>>,
mut commands: Commands, mut commands: Commands,
visuals: Res<Visuals>,
) { ) {
query.iter().for_each(|(e, rp, co)| { query.iter().for_each(|(e, s, o)| {
let parent_gp = gp.get(co.parent).unwrap(); debug!("{e:?} {s:?} {o:?}");
let gp: GridPosition = parent_gp.add_offset(rp);
info!("Inserting {:?} for {:?} to {:?}", gp, rp, e); let mesh = visuals.mesh.clone();
commands.entity(e).insert(gp); let mat = visuals.material.clone();
let positions = block_positions(s, o);
if blocks.is_empty() {
commands
.entity(e)
.with_related_entities::<BlockOf>(|parent| {
positions.into_iter().for_each(|rp| {
parent.spawn((Mesh2d(mesh.clone()), MeshMaterial2d(mat.clone()), rp));
});
});
} else {
let mut p = positions.into_iter();
blocks.iter_mut().for_each(|mut rp| {
*rp = p.next().unwrap();
});
}
}); });
} }
@ -515,18 +524,37 @@ fn draw_grid(mut gizmos: Gizmos) {
.outer_edges(); .outer_edges();
} }
fn falling(mut query: Query<&mut GridPosition>) { fn falling(mut shape: Query<&mut GridPosition, With<Shape>>) {
query.iter_mut().for_each(|mut gp| { shape.iter_mut().for_each(|mut gp| {
let next = gp.move_down(); let next = gp.move_down();
if next != *gp { if next != *gp {
*gp = next; *gp = next;
} else { } else {
// Remove the falling component from this entity // TODO: What to do here??
} }
}); });
} }
// Re-implement parenting for movement, but on the grid structure
fn shape_block_movement(
shape: Query<
&GridPosition,
(
With<ShapeBlocks>,
Without<RelativePosition>,
),
>,
mut blocks: Query<(&mut GridPosition, &RelativePosition), With<BlockOf>>,
) {
shape.iter().for_each(|shape_gp| {
blocks.iter_mut().for_each(|(mut block_gp, block_rp)| {
*block_gp = shape_gp.add_offset(block_rp);
});
});
}
// Run condition that returns `true` every `n` seconds // Run condition that returns `true` every `n` seconds
// TODO: Update a resource with the current tick
fn clock_cycle(n: f32) -> impl FnMut(Res<Time>, Local<f32>) -> bool { fn clock_cycle(n: f32) -> impl FnMut(Res<Time>, Local<f32>) -> bool {
move |t: Res<Time>, mut buf: Local<f32>| -> bool { move |t: Res<Time>, mut buf: Local<f32>| -> bool {
*buf += t.delta_secs(); *buf += t.delta_secs();
@ -541,32 +569,44 @@ fn clock_cycle(n: f32) -> impl FnMut(Res<Time>, Local<f32>) -> bool {
/// Check if the active piece is about to collide with the ground /// Check if the active piece is about to collide with the ground
fn check_collision( fn check_collision(
active: Query<&GridPosition, With<RelativePosition>>, active: Query<(&GridPosition, Entity), With<RelativePosition>>,
shape: Single<Entity, With<Shape>>,
inactive: Query<&GridPosition, Without<RelativePosition>>, inactive: Query<&GridPosition, Without<RelativePosition>>,
mut commands: Commands,
) { ) {
// TODO: Easy optimizations // TODO: Easy optimizations
let hit = active.iter().any(|a| { let hit = active.iter().any(|(a, _e)| {
debug!("Checking: {:?}", a); debug!("Checking: {:?}", a);
// Check if active piece is at floor // Check if active shape is at floor
let hit_floor = a.y == 0; let hit_floor = a.y == 0;
// Check if active peice is near other pieces // Check if active peice is near other blocks
let hit_piece = inactive.iter().any(|b| { let hit_block = inactive.iter().any(|b| {
debug!("Checking against: {:?}", b); debug!("Checking against: {:?}", b);
a.is_colliding_with(b) a.is_colliding_with(b)
}); });
hit_floor || hit_piece hit_floor || hit_block
}); });
if hit { if false {
info!("hit!") info!("hit detected!");
// todo!("Do the thing!");
let blocks: Vec<Entity> = active
.iter()
.map(|(_, e)| commands.entity(e).remove::<RelativePosition>().id())
.collect();
debug_assert_eq!(blocks.len(), 4, "Shapes should have 4 blocks");
info!("De-relating blocks {:?} and shape {:?}", blocks, *shape);
commands
.entity(*shape)
.remove_related::<BlockOf>(blocks.as_slice())
.despawn();
} }
} }
fn add_piece( fn add_piece(mut commands: Commands) {
mut commands: Commands,
) {
// TODO: Choose a different piece // TODO: Choose a different piece
commands.spawn((Orientation::default(), GridPosition::default(), Shape::T)); commands.spawn((Orientation::default(), GridPosition::default(), Shape::T));
} }

Loading…
Cancel
Save