diff --git a/assets/default_mino.png b/assets/default_mino.png new file mode 100644 index 0000000..0b737d7 Binary files /dev/null and b/assets/default_mino.png differ diff --git a/assets/skin.png b/assets/skin.png deleted file mode 100644 index 2a3d6ff..0000000 Binary files a/assets/skin.png and /dev/null differ diff --git a/skin.xcf b/skin.xcf index b5556bb..2d72576 100644 Binary files a/skin.xcf and b/skin.xcf differ diff --git a/src/engine/components.rs b/src/engine/components.rs index 28b24eb..f29f935 100644 --- a/src/engine/components.rs +++ b/src/engine/components.rs @@ -5,5 +5,5 @@ pub struct BoardVisual{} #[derive(Component, Clone, Copy)] pub struct Mino{ - pub skin_index: usize + pub color: Color } \ No newline at end of file diff --git a/src/engine/resources.rs b/src/engine/resources.rs index 0184978..7dc8877 100644 --- a/src/engine/resources.rs +++ b/src/engine/resources.rs @@ -2,11 +2,12 @@ use std::mem::swap; use bevy::prelude::*; -use super::{rotation_systems::{PiecesData, ROTATION_SYSTEMS}, components::Mino, randomizers::{Randomizer, Bag}}; +use super::{rotation_systems::{PiecesData, ROTATION_SYSTEMS, LockDelayMode}, components::Mino, randomizers::{Randomizer, Bag}}; #[derive(Clone, Copy)] pub struct Piece{ pub id: usize, + pub color: Color, pub position: (isize, isize), pub rotation: usize } @@ -14,7 +15,7 @@ pub struct Piece{ impl Piece { pub fn create(pieces_data: &PiecesData, id: usize) -> Piece{ let final_position = (3+pieces_data.spawn_offsets[id].0, 20+pieces_data.spawn_offsets[id].1); - Piece { id: id, position: final_position, rotation: 0 } + Piece { id: id, color: pieces_data.colours[id], position: final_position, rotation: 0 } } } @@ -138,7 +139,8 @@ pub struct Engine { pub lock_delay: u8, pub lock_delay_left: u8, pub lock_delay_resets: u8, - pub lock_delay_resets_left: u8 + pub lock_delay_resets_left: u8, + pub need_to_lock: bool, // when lock resets ended } impl Default for Engine { @@ -158,6 +160,7 @@ impl Default for Engine { lock_delay_left: 30, lock_delay_resets: 15, lock_delay_resets_left: 15, + need_to_lock: false, randomizer: Box::new(Bag{}), } } @@ -165,6 +168,9 @@ impl Default for Engine { impl Engine { fn from_next_to_current(&mut self){ + if self.next_queue.len() <= self.board.show_next as usize { + self.next_queue.append(&mut self.randomizer.populate_next(&self.rotation_system)); + } self.current_piece = self.next_queue.first().copied(); self.next_queue.remove(0); } @@ -176,9 +182,6 @@ impl Engine { } pub fn spawn_sequence(&mut self) -> bool { - if self.next_queue.len() <= self.board.show_next as usize { - self.next_queue.append(&mut self.randomizer.populate_next(&self.rotation_system)); - } self.from_next_to_current(); if !self.position_is_valid(self.current_piece.as_ref().unwrap().position, self.current_piece.as_ref().unwrap().rotation){ return false; @@ -193,6 +196,7 @@ impl Engine { return false; } self.current_piece.as_mut().unwrap().rotation = 0; + self.current_piece.as_mut().unwrap().position = (3+self.rotation_system.spawn_offsets[self.current_piece.as_ref().unwrap().id].0, 20+self.rotation_system.spawn_offsets[self.current_piece.as_ref().unwrap().id].1); match self.hold { Some(_) => { swap(&mut self.current_piece, &mut self.hold); @@ -211,17 +215,20 @@ impl Engine { return false; } let minos_to_write = &self.rotation_system.pieces[self.current_piece.as_ref().unwrap().id][self.current_piece.as_ref().unwrap().rotation]; - let color_index = self.rotation_system.skin_index[self.current_piece.as_ref().unwrap().id]; for mino in minos_to_write{ let x = (self.current_piece.as_ref().unwrap().position.0 + mino.0 as isize) as usize; let y = (self.current_piece.as_ref().unwrap().position.1 + mino.1 as isize) as usize; - self.board.board[y][x] = Some(Mino{ skin_index: color_index }); + self.board.board[y][x] = Some(Mino{ color: self.rotation_system.colours[self.current_piece.as_ref().unwrap().id] }); } self.current_piece = None; + self.need_to_lock = false; return true; } pub fn sonic_drop(&mut self) -> bool { + if self.current_piece.is_none(){ + return false; + } if !self.position_is_valid((self.current_piece.as_ref().unwrap().position.0, self.current_piece.as_ref().unwrap().position.1-1), self.current_piece.as_ref().unwrap().rotation) { return false; } @@ -237,7 +244,43 @@ impl Engine { y } + fn lock_delay_check(&mut self, shift: (i8, i8)){ + match self.rotation_system.lock_delay_mode { + LockDelayMode::Disabled => {}, + LockDelayMode::Gravity => {}, + LockDelayMode::ResetOnYChange => { + if shift.1 < 0 { + self.lock_delay_left = self.lock_delay; + if self.lock_delay_resets_left == 0{ + self.need_to_lock = true; + }else{ + self.lock_delay_resets_left -= 1; + } + } + }, + LockDelayMode::ResetOnMovementLimited => { + if !self.position_is_valid((self.current_piece.as_ref().unwrap().position.0, self.current_piece.as_ref().unwrap().position.1-1), self.current_piece.as_ref().unwrap().rotation){ + self.lock_delay_left = self.lock_delay; + if self.lock_delay_resets_left == 0{ + self.need_to_lock = true; + }else{ + self.lock_delay_resets_left -= 1; + } + } + }, + LockDelayMode::ResetOnMovement => { + if !self.position_is_valid((self.current_piece.as_ref().unwrap().position.0, self.current_piece.as_ref().unwrap().position.1-1), self.current_piece.as_ref().unwrap().rotation){ + self.lock_delay_left = self.lock_delay; + } + }, + } + info!("lock resets: {}, lock delay: {}", self.lock_delay_resets_left, self.lock_delay_left); + } + pub fn rotate_current_piece(&mut self, rotation: i8) -> bool { + if self.current_piece.is_none(){ + return false; + } let future_rotation = (self.current_piece.as_ref().unwrap().rotation as i8 + rotation) as usize % self.rotation_system.pieces[self.current_piece.as_ref().unwrap().id].len(); let id_for_kicks: usize = if rotation == 1 { 0 @@ -249,6 +292,7 @@ impl Engine { if self.position_is_valid(future_position, future_rotation) { self.current_piece.as_mut().unwrap().rotation = future_rotation; self.current_piece.as_mut().unwrap().position = future_position; + self.lock_delay_check(*test); return true; } } @@ -258,7 +302,8 @@ impl Engine { pub fn move_current_piece(&mut self, shift: (i8, i8)) -> bool { if (shift.0 == 0 && shift.1 == 0) || self.current_piece.is_none(){ return true; - } + } + self.lock_delay_check(shift); let future_position = ( self.current_piece.as_ref().unwrap().position.0 + shift.0 as isize, // future X self.current_piece.as_ref().unwrap().position.1 + shift.1 as isize // future Y diff --git a/src/engine/rotation_systems.rs b/src/engine/rotation_systems.rs index b27abb5..337244d 100644 --- a/src/engine/rotation_systems.rs +++ b/src/engine/rotation_systems.rs @@ -1,4 +1,4 @@ -use bevy::utils::HashMap; +use bevy::{utils::HashMap, prelude::Color}; use lazy_static::lazy_static; #[derive(Clone)] @@ -16,8 +16,7 @@ pub struct PiecesData { pub pieces: Vec>>, // X and Y shifts for pieces (kicks[piece][rotation before spin][direction of rotation] = Vec of points for tests) pub kicks: Vec>>>, - // Takes 64x64 sprite fragment with this index as Mino skin (skin_index[piece]) - pub skin_index: Vec, + pub colours: Vec, // If spawn position is fucked, it fixes it pub spawn_offsets: Vec<(isize, isize)>, pub lock_delay_mode: LockDelayMode @@ -199,7 +198,15 @@ lazy_static!{ ] ], ], - skin_index: vec![0, 1, 2, 3, 4, 5, 6], + colours: vec![ + Color::RED, // Z + Color::Rgba { red: 0.0, green: 0.3, blue: 1.0, alpha: 1.0 }, // J + Color::CYAN, // I + Color::Rgba { red: 1.0, green: 0.0, blue: 1.0, alpha: 1.0 }, // T + Color::YELLOW, // O + Color::ORANGE, // L + Color::GREEN // Z + ], spawn_offsets: vec![ (0, 0), // Z (0, 0), // J diff --git a/src/engine/systems.rs b/src/engine/systems.rs index 18f62aa..27478cf 100644 --- a/src/engine/systems.rs +++ b/src/engine/systems.rs @@ -48,14 +48,9 @@ pub fn draw_board( y*MINO_SIZE-(engine.board.height as f32)/2.0*MINO_SIZE+MINO_SIZE/2.0, 0.0 ), - texture: asset_server.load("skin.png"), + texture: asset_server.load("default_mino.png"), sprite: Sprite { - rect: Some( - Rect{ - min: Vec2 { x: 0.0+(64.0*mino.skin_index as f32), y: 0.0 }, - max: Vec2 { x: 63.0+(64.0*mino.skin_index as f32), y: 63.0 }, - } - ), + color: mino.color, custom_size: Some(Vec2 {x: MINO_SIZE, y: MINO_SIZE}), ..default() }, @@ -83,22 +78,17 @@ pub fn draw_board( transform: Transform::from_xyz( x*MINO_SIZE - (engine.board.width as f32)/2.0*MINO_SIZE + MINO_SIZE/2.0 + mino.0 as f32 * MINO_SIZE, y*MINO_SIZE - (engine.board.height as f32)/2.0*MINO_SIZE + MINO_SIZE/2.0 + mino.1 as f32 * MINO_SIZE, - 0.0 + 1.0 ), - texture: asset_server.load("skin.png"), + texture: asset_server.load("default_mino.png"), sprite: Sprite { - rect: Some( - Rect{ - min: Vec2 { x: 00.0+(64.0*engine.rotation_system.skin_index[piece.id] as f32), y: 00.0 }, - max: Vec2 { x: 63.0+(64.0*engine.rotation_system.skin_index[piece.id] as f32), y: 63.0 }, - } - ), + color: engine.rotation_system.colours[piece.id], custom_size: Some(Vec2 {x: MINO_SIZE, y: MINO_SIZE}), ..default() }, ..default() }, - Mino{skin_index: engine.rotation_system.skin_index[piece.id]}, + Mino{color: engine.rotation_system.colours[piece.id]}, )); } }, @@ -117,20 +107,15 @@ pub fn draw_board( y* MINO_SIZE + MINO_SIZE/2.0 + mino.1 as f32 * MINO_SIZE, 0.0 ), - texture: asset_server.load("skin.png"), + texture: asset_server.load("default_mino.png"), sprite: Sprite { - rect: Some( - Rect{ - min: Vec2 { x: 00.0+(64.0*engine.rotation_system.skin_index[engine.next_queue[i].id] as f32), y: 00.0 }, - max: Vec2 { x: 63.0+(64.0*engine.rotation_system.skin_index[engine.next_queue[i].id] as f32), y: 63.0 }, - } - ), + color: engine.rotation_system.colours[engine.next_queue[i].id], custom_size: Some(Vec2 {x: MINO_SIZE, y: MINO_SIZE}), ..default() }, ..default() }, - Mino{skin_index: engine.rotation_system.skin_index[engine.next_queue[i].id]}, + Mino{color: engine.rotation_system.colours[engine.next_queue[i].id]}, )); } y -= 4.0; @@ -148,26 +133,50 @@ pub fn draw_board( -2.0*MINO_SIZE + (engine.board.height as f32)/2.0*MINO_SIZE + MINO_SIZE/2.0 + mino.1 as f32 * MINO_SIZE, 0.0 ), - texture: asset_server.load("skin.png"), + texture: asset_server.load("default_mino.png"), sprite: Sprite { - rect: Some( - Rect{ - min: Vec2 { x: 00.0+(64.0*engine.rotation_system.skin_index[piece.id] as f32), y: 00.0 }, - max: Vec2 { x: 63.0+(64.0*engine.rotation_system.skin_index[piece.id] as f32), y: 63.0 }, - } - ), + color: piece.color, custom_size: Some(Vec2 {x: MINO_SIZE, y: MINO_SIZE}), ..default() }, ..default() }, - Mino{skin_index: engine.rotation_system.skin_index[piece.id]}, + Mino{color: piece.color}, )); } }, None => {}, } + // draw shadow + if engine.board.show_shadow { + match engine.current_piece.as_ref() { + Some(piece) => { + x = piece.position.0 as f32; + y = engine.lowest_point_under_current_piece() as f32; + for mino in &engine.rotation_system.pieces[piece.id][piece.rotation]{ + commands.spawn(( + SpriteBundle { + transform: Transform::from_xyz( + x*MINO_SIZE - (engine.board.width as f32)/2.0*MINO_SIZE + MINO_SIZE/2.0 + mino.0 as f32 * MINO_SIZE, + y*MINO_SIZE - (engine.board.height as f32)/2.0*MINO_SIZE + MINO_SIZE/2.0 + mino.1 as f32 * MINO_SIZE, + 0.0 + ), + texture: asset_server.load("default_mino.png"), + sprite: Sprite { + color: Color::Rgba { red: 1.0, green: 1.0, blue: 1.0, alpha: 0.1 }, + custom_size: Some(Vec2 {x: MINO_SIZE, y: MINO_SIZE}), + ..default() + }, + ..default() + }, + Mino{color: engine.rotation_system.colours[piece.id]}, + )); + } + }, + None => {}, + } + } } pub fn receive_input( @@ -246,7 +255,7 @@ pub fn gameloop( }else{ engine.lock_delay_left = engine.lock_delay; } - if engine.lock_delay_left < 1 && !engine.position_is_valid((piece.position.0, piece.position.1-1), piece.rotation){ + if (engine.lock_delay_left < 1 || engine.need_to_lock) && !engine.position_is_valid((piece.position.0, piece.position.1-1), piece.rotation){ engine.lock_current_piece(); next_state.set(GameloopStates::AfterLocking); }