Parcourir la source

piece moving is working, only to legal destinations

jmelesky il y a 3 ans
Parent
commit
e4383d0dda
3 fichiers modifiés avec 399 ajouts et 58 suppressions
  1. 59 26
      src/board.rs
  2. 3 1
      src/main.rs
  3. 337 31
      src/pieces.rs

+ 59 - 26
src/board.rs

@@ -2,6 +2,7 @@ use bevy::{
     prelude::*,
 };
 use bevy_mod_picking::*;
+use crate::pieces::*;
 
 
 pub struct Square {
@@ -20,13 +21,19 @@ struct SelectedSquare {
     entity: Option<Entity>,
 }
 
+#[derive(Default)]
+struct SelectedPiece {
+    entity: Option<Entity>,
+}
+
 
 pub struct BoardPlugin;
 impl Plugin for BoardPlugin {
     fn build(&self, app: &mut AppBuilder) {
         app.init_resource::<SelectedSquare>()
-            .add_startup_system(create_board.system())
-            .add_system(color_squares.system());
+            .init_resource::<SelectedPiece>()
+            .add_system(select_square.system())
+            .add_startup_system(create_board.system());
     }
 }
 
@@ -36,6 +43,7 @@ fn create_board(
     mut commands: Commands,
     mut meshes: ResMut<Assets<Mesh>>,
     mut materials: ResMut<Assets<StandardMaterial>>,
+    mut highlight_colors: ResMut<MeshButtonMaterials>,
 ) {
     // add meshes and materials
     let mesh = meshes.add(Mesh::from(shape::Plane {size: 1.0}));
@@ -60,35 +68,57 @@ fn create_board(
                 });
         }
     }
+
+    highlight_colors.hovered  = materials.add(Color::rgb(0.8, 0.3, 0.3).into());
+    highlight_colors.pressed  = materials.add(Color::rgb(0.9, 0.5, 0.5).into());
+    highlight_colors.selected = materials.add(Color::rgb(0.9, 0.1, 0.1).into());
 }
 
 
-fn color_squares(
-    selected_square: Res<SelectedSquare>,
-    camera: Res<PickingCamera>,
-    mut materials: ResMut<Assets<StandardMaterial>>,
-    query: Query<(Entity, &Square, &Handle<StandardMaterial>)>,
+fn select_square(
+    mouse_button_inputs: Res<Input<MouseButton>>,
+    mut selected_square: ResMut<SelectedSquare>,
+    mut selected_piece: ResMut<SelectedPiece>,
+    camera_query: Query<&PickingCamera>,
+    squares_query: Query<&Square>,
+    mut pieces_query: Query<(Entity, &mut Piece)>,
 ) {
-    let top_entity = if let Some((entity, _intersection)) = camera.intersect_top() {
-        Some(entity)
-    } else {
-        None
-    };
-
-    for (entity, square, material_handle) in query.iter() {
-        // get the material
-        let material = materials.get_mut(material_handle).unwrap();
-
-        // change its color
-        material.base_color = if Some(entity) == top_entity {
-            Color::rgb(0.8, 0.3, 0.3)
-        } else if Some(entity) == selected_square.entity {
-            Color::rgb(0.9, 0.1, 0.1)
-        } else if square.is_white() {
-            Color::rgb(1.0, 0.9, 0.9)
+    if !mouse_button_inputs.just_pressed(MouseButton::Left) {
+        return;
+    }
+
+    let pieces_vec = pieces_query.iter_mut().map(|(_, piece)| *piece).collect();
+
+    for camera in camera_query.iter() {
+        if let Some((square_entity, _intersection)) = camera.intersect_top() {
+            if let Ok(square) = squares_query.get(square_entity) {
+                selected_square.entity = Some(square_entity);
+
+                // if a piece is already selected, set it to move
+                if let Some(selected_piece_entity) = selected_piece.entity {
+                    if let Ok((_piece_entity, mut piece)) = pieces_query.get_mut(selected_piece_entity) {
+                        if piece.is_move_valid((square.x, square.y), &pieces_vec) {
+                            piece.x = square.x;
+                            piece.y = square.y;
+                        }
+                    }
+                    selected_square.entity = None;
+                    selected_piece.entity  = None;
+                } else {
+                    // otherwise, select the piece (if one) in the selected square
+                    for (piece_entity, piece) in pieces_query.iter_mut() {
+                        if piece.x == square.x && piece.y == square.y {
+                            selected_piece.entity = Some(piece_entity);
+                            break;
+                        }
+                    }
+                }
+            }
         } else {
-            Color::rgb(0.0, 0.1, 0.1)
-        };
+            // clicked on nothing, deselect
+            selected_square.entity = None;
+            selected_piece.entity  = None;
+        }
     }
 }
 
@@ -96,3 +126,6 @@ fn color_squares(
 
 
 
+
+
+

+ 3 - 1
src/main.rs

@@ -22,9 +22,11 @@ fn main() {
         })
         .add_plugins(DefaultPlugins)
         .add_plugin(PickingPlugin)
+        .add_plugin(InteractablePickingPlugin)
+        .add_plugin(HighlightablePickingPlugin)
         .add_plugin(BoardPlugin)
+        .add_plugin(PiecesPlugin)
         .add_startup_system(setup.system())
-        .add_startup_system(create_pieces.system())
         .run();
 }
 

+ 337 - 31
src/pieces.rs

@@ -1,7 +1,214 @@
 use bevy::prelude::*;
 
 
-pub fn create_pieces(
+pub struct PiecesPlugin;
+impl Plugin for PiecesPlugin {
+    fn build(&self, app: &mut AppBuilder) {
+        app.add_startup_system(create_pieces.system())
+            .add_system(move_pieces.system());
+    }
+}
+
+
+#[derive(Clone, Copy, PartialEq)]
+pub enum PieceColor {
+    White,
+    Black,
+}
+
+#[derive(Clone, Copy, PartialEq)]
+pub enum PieceType {
+    King,
+    Queen,
+    Bishop,
+    Knight,
+    Rook,
+    Pawn,
+}
+
+#[derive(Clone, Copy)]
+pub struct Piece {
+    pub color: PieceColor,
+    pub piece_type: PieceType,
+    // current positoin
+    pub x: u8,
+    pub y: u8,
+}
+
+impl Piece {
+    pub fn is_move_valid(&self, new_position: (u8,u8), pieces: &Vec<Piece>) -> bool {
+        if color_in_square(new_position, &pieces) == Some(self.color) {
+            return false;
+        }
+
+        if self.x == new_position.0 && self.y == new_position.1 {
+            return false;
+        }
+
+        match self.piece_type {
+            PieceType::King => {
+                ((self.x as i8 - new_position.0 as i8).abs() <=1
+                 && (self.y as i8 - new_position.1 as i8).abs() <= 1)
+            }
+            PieceType::Queen => {
+                is_path_empty((self.x, self.y), new_position, &pieces)
+                    && ((self.x as i8 - new_position.0 as i8).abs()
+                        == (self.y as i8 - new_position.1 as i8).abs()
+                        || self.x == new_position.0
+                        || self.y == new_position.1)
+            }
+            PieceType::Bishop => {
+                is_path_empty((self.x, self.y), new_position, &pieces)
+                    && (self.x as i8 - new_position.0 as i8).abs()
+                    == (self.y as i8 - new_position.1 as i8).abs()
+            }
+            PieceType::Rook => {
+                is_path_empty((self.x, self.y), new_position, &pieces)
+                    && (self.x == new_position.0
+                        || self.y == new_position.1)
+            }
+            PieceType::Knight => {
+                ((self.x as i8 - new_position.0 as i8).abs() == 2
+                 && (self.y as i8 - new_position.1 as i8).abs() == 1)
+                    || ((self.x as i8 - new_position.0 as i8).abs() == 1
+                        && (self.y as i8 - new_position.1 as i8).abs() == 2)
+            }
+            PieceType::Pawn => {
+                if self.color == PieceColor::White {
+                    // normal move
+                    if new_position.0 as i8 - self.x as i8 == 1
+                        && (self.y == new_position.1)
+                        && color_in_square(new_position, &pieces).is_none()
+                    {
+                        return true;
+                    }
+
+                    // initial 2 squares
+                    if self.x == 1
+                        && new_position.0 == 3
+                        && self.y == new_position.1
+                        && is_path_empty((self.x, self.y), new_position, &pieces)
+                        && color_in_square(new_position, &pieces).is_none()
+                    {
+                        return true;
+                    }
+
+                    // capture
+                    if new_position.0 as i8 - self.x as i8 == 1
+                        && (self.y as i8 - new_position.1 as i8).abs() == 1
+                        && color_in_square(new_position, &pieces) == Some(PieceColor::Black)
+                    {
+                        return true;
+                    }
+                } else {
+                    // normal move
+                    if self.x as i8 - new_position.0 as i8 == 1
+                        && (self.y == new_position.1)
+                        && color_in_square(new_position, &pieces).is_none()
+                    {
+                        return true;
+                    }
+
+                    // initial 2 squares
+                    if self.x == 6
+                        && new_position.0 == 4
+                        && self.y == new_position.1
+                        && is_path_empty((self.x, self.y), new_position, &pieces)
+                        && color_in_square(new_position, &pieces).is_none()
+                    {
+                        return true;
+                    }
+
+                    // capture
+                    if self.x as i8 - new_position.0 as i8 == 1
+                        && (self.y as i8 - new_position.1 as i8).abs() == 1
+                        && color_in_square(new_position, &pieces) == Some(PieceColor::White)
+                    {
+                        return true;
+                    }
+                }
+
+                false
+            }
+        }
+    }
+}
+
+
+
+
+
+// returns the color of the piece in the square (or None if empty)
+fn color_in_square(pos: (u8,u8), pieces: &Vec<Piece>) -> Option<PieceColor> {
+    for piece in pieces {
+        if piece.x == pos.0 && piece.y == pos.1 {
+            return Some(piece.color);
+        }
+    }
+    None
+}
+
+// checks to see if the straight line between two squares is clear of pieces
+fn is_path_empty(
+    begin: (u8,u8),
+    end:   (u8,u8),
+    pieces: &Vec<Piece>)
+    -> bool
+{
+    // same column
+    if begin.0 == end.0 {
+        for piece in pieces {
+            if piece.x == begin.0
+                && ((piece.y > begin.1 && piece.y < end.1)
+                    || (piece.y > end.1 && piece.y < begin.1))
+            {
+                return false;
+            }
+        }
+    }
+
+    // same row
+    if begin.1 == end.1 {
+        for piece in pieces {
+            if piece.y == begin.1
+                && ((piece.x > begin.0 && piece.x < end.0)
+                    || (piece.x > end.0 && piece.x < begin.0))
+            {
+                return false;
+            }
+        }
+    }
+
+    // diagonals
+    let x_diff = (begin.0 as i8 - end.0 as i8).abs();
+    let y_diff = (begin.1 as i8 - end.1 as i8).abs();
+    if x_diff == y_diff {
+        for i in 1..x_diff {
+            let pos = if begin.0 < end.0 && begin.1 < end.1 {
+                // left bottom -> right top
+                (begin.0 + i as u8, begin.1 + i as u8)
+            } else if begin.0 < end.0 && begin.1 > end.1 {
+                // left top -> right bottom
+                (begin.0 + i as u8, begin.1 - i as u8)
+            } else if begin.0 > end.0 && begin.1 < end.1 {
+                // right bottom -> left top
+                (begin.0 - i as u8, begin.1 + i as u8)
+            } else {
+                // right top -> left bottom
+                (begin.0 - i as u8, begin.1 - i as u8)
+            };
+
+            if color_in_square(pos, pieces).is_some() {
+                return false;
+            }
+        }
+    }
+
+    true
+}
+
+
+fn create_pieces(
     mut commands: Commands,
     asset_server: Res<AssetServer>,
     mut materials: ResMut<Assets<StandardMaterial>>,
@@ -23,61 +230,70 @@ pub fn create_pieces(
     spawn_rook(
         &mut commands,
         white_material.clone(),
+        PieceColor::White,
         rook_handle.clone(),
-        Vec3::new(0.0, 0.0, 0.0),
+        (0,0),
     );
     spawn_knight(
         &mut commands,
         white_material.clone(),
+        PieceColor::White,
         knight_1_handle.clone(),
         knight_2_handle.clone(),
-        Vec3::new(0.0, 0.0, 1.0),
+        (0,1),
     );
     spawn_bishop(
         &mut commands,
         white_material.clone(),
+        PieceColor::White,
         bishop_handle.clone(),
-        Vec3::new(0.0, 0.0, 2.0),
+        (0,2),
     );
     spawn_queen(
         &mut commands,
         white_material.clone(),
+        PieceColor::White,
         queen_handle.clone(),
-        Vec3::new(0.0, 0.0, 3.0),
+        (0,3),
     );
     spawn_king(
         &mut commands,
         white_material.clone(),
+        PieceColor::White,
         king_handle.clone(),
         king_cross_handle.clone(),
-        Vec3::new(0.0, 0.0, 4.0),
+        (0,4),
     );
     spawn_bishop(
         &mut commands,
         white_material.clone(),
+        PieceColor::White,
         bishop_handle.clone(),
-        Vec3::new(0.0, 0.0, 5.0),
+        (0,5),
     );
     spawn_knight(
         &mut commands,
         white_material.clone(),
+        PieceColor::White,
         knight_1_handle.clone(),
         knight_2_handle.clone(),
-        Vec3::new(0.0, 0.0, 6.0),
+        (0,6),
     );
     spawn_rook(
         &mut commands,
         white_material.clone(),
+        PieceColor::White,
         rook_handle.clone(),
-        Vec3::new(0.0, 0.0, 7.0),
+        (0,7),
     );
 
     for i in 0..8 {
         spawn_pawn(
             &mut commands,
             white_material.clone(),
+            PieceColor::White,
             pawn_handle.clone(),
-            Vec3::new(1.0, 0.0, i as f32),
+            (1, i),
         );
     }
 
@@ -85,61 +301,70 @@ pub fn create_pieces(
     spawn_rook(
         &mut commands,
         black_material.clone(),
+        PieceColor::Black,
         rook_handle.clone(),
-        Vec3::new(7.0, 0.0, 0.0),
+        (7,0),
     );
     spawn_knight(
         &mut commands,
         black_material.clone(),
+        PieceColor::Black,
         knight_1_handle.clone(),
         knight_2_handle.clone(),
-        Vec3::new(7.0, 0.0, 1.0),
+        (7,1),
     );
     spawn_bishop(
         &mut commands,
         black_material.clone(),
+        PieceColor::Black,
         bishop_handle.clone(),
-        Vec3::new(7.0, 0.0, 2.0),
+        (7,2),
     );
     spawn_queen(
         &mut commands,
         black_material.clone(),
+        PieceColor::Black,
         queen_handle.clone(),
-        Vec3::new(7.0, 0.0, 3.0),
+        (7,3),
     );
     spawn_king(
         &mut commands,
         black_material.clone(),
+        PieceColor::Black,
         king_handle.clone(),
         king_cross_handle.clone(),
-        Vec3::new(7.0, 0.0, 4.0),
+        (7,4),
     );
     spawn_bishop(
         &mut commands,
         black_material.clone(),
+        PieceColor::Black,
         bishop_handle.clone(),
-        Vec3::new(7.0, 0.0, 5.0),
+        (7,5),
     );
     spawn_knight(
         &mut commands,
         black_material.clone(),
+        PieceColor::Black,
         knight_1_handle.clone(),
         knight_2_handle.clone(),
-        Vec3::new(7.0, 0.0, 6.0),
+        (7,6),
     );
     spawn_rook(
         &mut commands,
         black_material.clone(),
+        PieceColor::Black,
         rook_handle.clone(),
-        Vec3::new(7.0, 0.0, 7.0),
+        (7,7),
     );
 
     for i in 0..8 {
         spawn_pawn(
             &mut commands,
             black_material.clone(),
+            PieceColor::Black,
             pawn_handle.clone(),
-            Vec3::new(6.0, 0.0, i as f32),
+            (6, i),
         );
     }
 }
@@ -149,16 +374,27 @@ pub fn create_pieces(
 fn spawn_king(
     commands: &mut Commands,
     material: Handle<StandardMaterial>,
+    piece_color: PieceColor,
     mesh: Handle<Mesh>,
     mesh_cross: Handle<Mesh>,
-    position: Vec3,
+    position: (u8, u8),
 ) {
     // spawn parent
     commands
         .spawn_bundle(PbrBundle {
-            transform: Transform::from_translation(position),
+            transform: Transform::from_translation(Vec3::new(
+                position.0 as f32,
+                0.0,
+                position.1 as f32,
+            )),
             ..Default::default()
         })
+        .insert(Piece {
+            color: piece_color,
+            piece_type: PieceType::King,
+            x: position.0,
+            y: position.1,
+        })
         .with_children(|parent| {
             parent.spawn_bundle(PbrBundle {
                 mesh,
@@ -187,16 +423,27 @@ fn spawn_king(
 fn spawn_knight(
     commands: &mut Commands,
     material: Handle<StandardMaterial>,
+    piece_color: PieceColor,
     mesh_1: Handle<Mesh>,
     mesh_2: Handle<Mesh>,
-    position: Vec3,
+    position: (u8, u8),
 ) {
     // spawn parent
     commands
         .spawn_bundle(PbrBundle {
-            transform: Transform::from_translation(position),
+            transform: Transform::from_translation(Vec3::new(
+                position.0 as f32,
+                0.0,
+                position.1 as f32,
+            )),
             ..Default::default()
         })
+        .insert(Piece {
+            color: piece_color,
+            piece_type: PieceType::Knight,
+            x: position.0,
+            y: position.1,
+        })
         .with_children(|parent| {
             parent.spawn_bundle(PbrBundle {
                 mesh: mesh_1,
@@ -225,15 +472,26 @@ fn spawn_knight(
 fn spawn_queen(
     commands: &mut Commands,
     material: Handle<StandardMaterial>,
+    piece_color: PieceColor,
     mesh: Handle<Mesh>,
-    position: Vec3,
+    position: (u8, u8),
 ) {
     // spawn parent
     commands
         .spawn_bundle(PbrBundle {
-            transform: Transform::from_translation(position),
+            transform: Transform::from_translation(Vec3::new(
+                position.0 as f32,
+                0.0,
+                position.1 as f32,
+            )),
             ..Default::default()
         })
+        .insert(Piece {
+            color: piece_color,
+            piece_type: PieceType::Queen,
+            x: position.0,
+            y: position.1,
+        })
         .with_children(|parent| {
             parent.spawn_bundle(PbrBundle {
                 mesh,
@@ -252,15 +510,26 @@ fn spawn_queen(
 fn spawn_bishop(
     commands: &mut Commands,
     material: Handle<StandardMaterial>,
+    piece_color: PieceColor,
     mesh: Handle<Mesh>,
-    position: Vec3,
+    position: (u8, u8),
 ) {
     // spawn parent
     commands
         .spawn_bundle(PbrBundle {
-            transform: Transform::from_translation(position),
+            transform: Transform::from_translation(Vec3::new(
+                position.0 as f32,
+                0.0,
+                position.1 as f32,
+            )),
             ..Default::default()
         })
+        .insert(Piece {
+            color: piece_color,
+            piece_type: PieceType::Bishop,
+            x: position.0,
+            y: position.1,
+        })
         .with_children(|parent| {
             parent.spawn_bundle(PbrBundle {
                 mesh,
@@ -279,15 +548,26 @@ fn spawn_bishop(
 fn spawn_rook(
     commands: &mut Commands,
     material: Handle<StandardMaterial>,
+    piece_color: PieceColor,
     mesh: Handle<Mesh>,
-    position: Vec3,
+    position: (u8, u8),
 ) {
     // spawn parent
     commands
         .spawn_bundle(PbrBundle {
-            transform: Transform::from_translation(position),
+            transform: Transform::from_translation(Vec3::new(
+                position.0 as f32,
+                0.0,
+                position.1 as f32,
+            )),
             ..Default::default()
         })
+        .insert(Piece {
+            color: piece_color,
+            piece_type: PieceType::Rook,
+            x: position.0,
+            y: position.1,
+        })
         .with_children(|parent| {
             parent.spawn_bundle(PbrBundle {
                 mesh,
@@ -306,15 +586,26 @@ fn spawn_rook(
 fn spawn_pawn(
     commands: &mut Commands,
     material: Handle<StandardMaterial>,
+    piece_color: PieceColor,
     mesh: Handle<Mesh>,
-    position: Vec3,
+    position: (u8, u8),
 ) {
     // spawn parent
     commands
         .spawn_bundle(PbrBundle {
-            transform: Transform::from_translation(position),
+            transform: Transform::from_translation(Vec3::new(
+                position.0 as f32,
+                0.0,
+                position.1 as f32,
+            )),
             ..Default::default()
         })
+        .insert(Piece {
+            color: piece_color,
+            piece_type: PieceType::Pawn,
+            x: position.0,
+            y: position.1,
+        })
         .with_children(|parent| {
             parent.spawn_bundle(PbrBundle {
                 mesh,
@@ -330,6 +621,21 @@ fn spawn_pawn(
 }
 
 
+fn move_pieces(
+    time: Res<Time>,
+    mut query: Query<(&mut Transform, &Piece)>,
+) {
+    for (mut transform, piece) in query.iter_mut() {
+        // get the direction to move in
+        let direction = Vec3::new(piece.x as f32, 0.0, piece.y as f32) - transform.translation;
+
+        // only move it if it isn't already there
+        if direction.length() > 0.1 {
+            transform.translation += direction.normalize() * time.delta_seconds();
+        }
+    }
+}
+