@ -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 : u size ,
x : u 32 ,
y : u size ,
y : u 32 ,
}
}
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 < ( u size, usize ) > for GridPosition {
impl From < ( u 32, u32 ) > for GridPosition {
fn from ( ( x , y ) : ( u size, usize ) ) -> GridPosition {
fn from ( ( x , y ) : ( u 32, 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 ) ) ;
}