The basic idea of "Move the tiles instead of rotating the shapes"

It is very buggy, but you get the just if what I'm going for.

I'll fix it up tomorrow.
main
Elijah Voigt 2 weeks ago
parent c62350e382
commit 7ae68f0e4c

@ -1,5 +1,12 @@
// Bevy basically forces "complex types" with Querys
#![allow(clippy::type_complexity)]
use games::*;
// TODO: Detect when piece is going to go out of bounds and restirct parent from moving there
// TODO: When shape touches the rest of the pieces, re-parent to line entity
// TODO: When line is "full" (has 10 children) clear line and add to score
fn main() {
App::new()
.add_plugins(BaseGamePlugin {
@ -13,11 +20,21 @@ fn main() {
.add_systems(
Update,
(
kb_movement.run_if(on_event::<KeyboardInput>),
kb_input.run_if(on_event::<KeyboardInput>),
update_position,
update_orientation,
toggle_falling.run_if(on_event::<KeyboardInput>),
falling.run_if(in_state(Falling::On)).run_if(clock_cycle(1.0))
falling
.run_if(in_state(Falling::On))
.run_if(clock_cycle(1.0)),
set_piece
.run_if(any_component_added::<Shape>
.or(any_component_changed::<Shape>)
.or(any_component_added::<Orientation>)
.or(any_component_changed::<Orientation>)
),
set_relative_piece_positions.run_if(
any_component_added::<RelativePosition>
.or(any_component_changed::<RelativePosition>),
),
),
)
.add_systems(Update, draw_grid)
@ -26,6 +43,34 @@ fn main() {
const SCALE: f32 = 30.0;
/// A shape, e.g., the long piece
#[derive(Component, Debug)]
enum Shape {
O,
T,
L,
J,
S,
Z,
I,
}
/// A part of a piece, i.e., a single square of a piece
#[derive(Component, Debug)]
struct ShapePiece;
#[derive(Component, Debug)]
struct RelativePosition {
x: i8,
y: i8,
}
impl From<(i8, i8)> for RelativePosition {
fn from((x, y): (i8, i8)) -> RelativePosition {
RelativePosition { x, y }
}
}
#[derive(Component, Debug, Clone, Copy, PartialEq)]
#[require(Transform, Visibility)]
struct GridPosition {
@ -36,39 +81,44 @@ struct GridPosition {
impl GridPosition {
fn move_up(&self) -> Self {
Self {
y: if self.y + 1 < 20 { self.y.saturating_add(1) } else { self.y },
x: self.x
y: if self.y + 1 < 20 {
self.y.saturating_add(1)
} else {
self.y
},
x: self.x,
}
}
fn move_down(&mut self) -> Self {
Self {
y: self.y.saturating_sub(1),
x: self.x
x: self.x,
}
}
fn move_left(&mut self) -> Self {
Self {
x: self.x.saturating_sub(1),
y: self.y
y: self.y,
}
}
fn move_right(&mut self) -> Self {
Self {
x: if self.x + 1 < 10 { self.x.saturating_add(1) } else { self.x },
y: self.y
x: if self.x + 1 < 10 {
self.x.saturating_add(1)
} else {
self.x
},
y: self.y,
}
}
}
impl Default for GridPosition {
fn default() -> Self {
GridPosition {
x: 5,
y: 20,
}
GridPosition { x: 5, y: 20 }
}
}
@ -77,6 +127,7 @@ impl From<&GridPosition> for Vec3 {
// Grid Positions start in the bottom left of the area
// So (0, 0) is the bottom left, (0, 9) is the bottom right, etc
// TODO: Custom offset allowing pieces like O and I to have correct center
let x_0 = -SCALE * 5.0 + (0.5 * SCALE);
let x = x_0 + ((*x as f32) * SCALE);
@ -138,23 +189,17 @@ impl Orientation {
}
}
impl From<&Orientation> for Quat {
fn from(other: &Orientation) -> Quat {
let z = match other {
Orientation::Up => 0.0,
Orientation::Left => -PI * 0.5,
Orientation::Down => -PI,
Orientation::Right => -PI * 1.5,
};
Quat::from_rotation_z(z)
}
}
#[derive(States, Clone, Eq, PartialEq, Debug, Hash, Default, Component)]
enum Falling {
#[default]
On,
Off
Off,
}
#[derive(Resource, Debug)]
struct Visuals {
material: Handle<ColorMaterial>,
mesh: Handle<Mesh>,
}
fn init_pieces(
@ -162,33 +207,149 @@ fn init_pieces(
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
commands
.spawn((Orientation::default(), GridPosition::default()))
.with_children(|parent| {
let mat = materials.add(ColorMaterial {
commands.insert_resource(Visuals {
material: materials.add(ColorMaterial {
color: WHITE.into(),
..default()
}),
mesh: meshes.add(Rectangle::new(SCALE, SCALE)),
});
let mesh = meshes.add(Rectangle::new(SCALE, SCALE));
parent.spawn((
Mesh2d(mesh.clone()),
MeshMaterial2d(mat.clone()),
Transform::from_xyz(0.0, 0.0, 0.0),
));
parent.spawn((
Mesh2d(mesh.clone()),
MeshMaterial2d(mat.clone()),
Transform::from_xyz(SCALE, 0.0, 0.0),
));
parent.spawn((
Mesh2d(mesh.clone()),
MeshMaterial2d(mat.clone()),
Transform::from_xyz(0.0, SCALE, 0.0),
));
parent.spawn((
Mesh2d(mesh.clone()),
MeshMaterial2d(mat.clone()),
Transform::from_xyz(-SCALE, 0.0, 0.0),
commands.spawn((Orientation::default(), GridPosition::default(), Shape::T));
}
fn set_piece(
query: Query<(Entity, &Shape, &Orientation), Or<(Added<Shape>, Changed<Shape>, Added<Orientation>, Changed<Orientation>)>>,
mut commands: Commands,
visuals: Res<Visuals>,
) {
query.iter().for_each(|(e, s, o)| {
info!("{e:?} {s:?} {o:?}");
commands
.entity(e)
.despawn_related::<Children>()
.with_children(|parent| {
let mesh = visuals.mesh.clone();
let mat = visuals.material.clone();
#[rustfmt::skip]
let piece_positions: [RelativePosition;4] = match s {
Shape::O => [
(0,1).into(),(1,1).into(),
(0,0).into(),(1,0).into()
],
Shape::T => match o {
Orientation::Up => [
(0,1).into(),
(-1,0).into(),(0,0).into(),(1,0).into(),
],
Orientation::Down => [
(-1,0).into(),(0,0).into(),(1,0).into(),
(0,-1).into(),
],
Orientation::Right => [
(0,1).into(),
(0,0).into(), (1,0).into(),
(0,-1).into(),
],
Orientation::Left => [
(0,1).into(),
(-1,0).into(),(0,0).into(),
(0,-1).into(),
]
},
Shape::L => match o {
Orientation::Up => [
(0,1).into(),
(0,0).into(),
(0,-1).into(),(1,-1).into(),
],
Orientation::Down => [
(-1,1).into(),(0,1).into(),
(0,0).into(),
(0,-1).into(),
],
Orientation::Right => [
(-1,0).into(),(0,0).into(),(0,1).into(),
(-1,-1).into(),
],
Orientation::Left => [
(1,1).into(),
(-1,0).into(),(0,0).into(),(0,1).into(),
],
},
Shape::J => match o {
Orientation::Up => [
(0,1).into(),
(0,0).into(),
(-1,-1).into(),(0,-1).into(),
],
Orientation::Down => [
(0,1).into(),(1,1).into(),
(0,0).into(),
(0,-1).into(),
],
Orientation::Left => [
(-1,0).into(),(0,0).into(),(1,0).into(),
(1,-1).into(),
],
Orientation::Right => [
(-1,-1).into(),
(-1,0).into(),(0,0).into(),(1,0).into()
],
},
Shape::S => match o {
Orientation::Up | Orientation::Down => [
(0,0).into(),(1,0).into(),
(-1,-1).into(),(0,-1).into(),
],
Orientation::Left | Orientation::Right => [
(0,1).into(),
(-1,0).into(),(0,0).into(),
(-1,-1).into(),
]
},
Shape::Z => match o {
Orientation::Up | Orientation::Down => [
(-1,0).into(),(0,0).into(),
(0,-1).into(),(1,-1).into(),
],
Orientation::Left | Orientation::Right => [
(0,1).into(),
(0,0).into(),(1,0).into(),
(1,-1).into(),
],
},
Shape::I => match o {
Orientation::Up | Orientation::Down => [
(0,2).into(),
(0,1).into(),
(0,0).into(),
(0,-1).into(),
],
Orientation::Left | Orientation::Right => todo!()
}
};
piece_positions.into_iter().for_each(|rp| {
parent.spawn((Mesh2d(mesh.clone()), MeshMaterial2d(mat.clone()), rp));
});
});
});
}
fn set_relative_piece_positions(
query: Query<
(Entity, &RelativePosition),
Or<(Added<RelativePosition>, Changed<RelativePosition>)>,
>,
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,
));
});
}
@ -200,14 +361,12 @@ fn update_position(mut query: Query<(&GridPosition, &mut Transform), Changed<Gri
});
}
fn update_orientation(mut query: Query<(&Orientation, &mut Transform), Changed<Orientation>>) {
query.iter_mut().for_each(|(o, mut t)| {
t.rotation = o.into();
debug!("Setting orientation to {:?}", o);
});
}
fn kb_movement(mut events: EventReader<KeyboardInput>, mut query: Query<(&mut GridPosition, &mut Orientation)>) {
fn kb_input(
mut events: EventReader<KeyboardInput>,
mut query: Query<(&mut GridPosition, &mut Orientation, &mut Shape)>,
curr: Res<State<Falling>>,
mut next: ResMut<NextState<Falling>>,
) {
events.read().for_each(
|KeyboardInput {
key_code, state, ..
@ -215,14 +374,26 @@ fn kb_movement(mut events: EventReader<KeyboardInput>, mut query: Query<(&mut Gr
if let ButtonState::Pressed = state {
// TODO: Restict movement based on size/orientation of piece
// Check if children would be outside play area...
query.iter_mut().for_each(|(mut gp, mut o)| {
query.iter_mut().for_each(|(mut gp, mut o, mut s)| {
match key_code {
KeyCode::ArrowUp => *gp = gp.move_up(),
// Up arrow should rotate if in falling mode
// Only move up if in falling::off mode
KeyCode::ArrowUp => *o = o.next(),
KeyCode::ArrowDown => *gp = gp.move_down(),
KeyCode::ArrowLeft => *gp = gp.move_left(),
KeyCode::ArrowRight => *gp = gp.move_right(),
KeyCode::Enter => *o = o.next(),
_ => ()
KeyCode::Space => next.set(match curr.get() {
Falling::On => Falling::Off,
Falling::Off => Falling::On,
}),
KeyCode::Digit1 => *s = Shape::T,
KeyCode::Digit2 => *s = Shape::O,
KeyCode::Digit3 => *s = Shape::L,
KeyCode::Digit4 => *s = Shape::J,
KeyCode::Digit5 => *s = Shape::S,
KeyCode::Digit6 => *s = Shape::Z,
KeyCode::Digit7 => *s = Shape::I,
_ => (),
}
});
}
@ -241,24 +412,7 @@ fn draw_grid(mut gizmos: Gizmos) {
.outer_edges();
}
fn toggle_falling(
mut events: EventReader<KeyboardInput>,
curr: Res<State<Falling>>,
mut next: ResMut<NextState<Falling>>,
) {
events.read().for_each(|KeyboardInput { state, key_code, .. }| {
if let ButtonState::Pressed = state && *key_code == KeyCode::Space {
next.set(match curr.get() {
Falling::On => Falling::Off,
Falling::Off => Falling::On,
});
}
})
}
fn falling(
mut query: Query<&mut GridPosition>
) {
fn falling(mut query: Query<&mut GridPosition, With<Shape>>) {
query.iter_mut().for_each(|mut gp| {
let next = gp.move_down();
if next != *gp {

Loading…
Cancel
Save