refactor + potential input issue fix (?)

This commit is contained in:
dan63047 2023-11-08 22:47:53 +03:00
parent 7a3c2c9c43
commit cc8ee31cff
6 changed files with 679 additions and 697 deletions

9
src/engine/components.rs Normal file
View File

@ -0,0 +1,9 @@
use bevy::prelude::*;
#[derive(Component)]
pub struct BoardVisual{}
#[derive(Component, Clone, Copy)]
pub struct Mino{
pub skin_index: usize
}

View File

@ -1,9 +1,10 @@
use bevy::{prelude::*, utils::HashMap}; use bevy::prelude::*;
use rand::prelude::*; use self::{systems::*, resources::Engine};
use lazy_static::lazy_static;
use bevy::sprite::{Sprite, MaterialMesh2dBundle};
const MINO_SIZE: f32 = 20.0; mod rotation_systems;
mod systems;
mod components;
mod resources;
pub struct UBSGEngine; pub struct UBSGEngine;
@ -14,474 +15,16 @@ impl Plugin for UBSGEngine{
add_state::<GameloopStates>(). add_state::<GameloopStates>().
insert_resource(Engine::default()). insert_resource(Engine::default()).
add_systems(Startup, init_engine). add_systems(Startup, init_engine).
add_systems(Update, (receive_input, das_and_arr).run_if(in_state(GameloopStates::Falling))). add_systems(Update, receive_input).
add_systems(FixedUpdate, gameloop). add_systems(Update, das_and_arr).
add_systems(FixedUpdate, gameloop.run_if(in_state(GameloopStates::Falling))).
add_systems(OnEnter(GameloopStates::AfterLocking), after_locking_routine). add_systems(OnEnter(GameloopStates::AfterLocking), after_locking_routine).
add_systems(Update, draw_board); add_systems(Update, draw_board);
} }
} }
#[derive(Clone)]
enum LockDelayMode{
Disabled,
Gravity,
ResetOnYChange,
ResetOnMovementLimited,
ResetOnMovement
}
#[derive(Clone)]
struct PiecesData {
// X and Y from bottom left point (pieces[piece][rotation] = Vec of coords for Minos)
pieces: Vec<Vec<Vec<(u8, u8)>>>,
// X and Y shifts for pieces (kicks[piece][rotation before spin][direction of rotation] = Vec of points for tests)
kicks: Vec<Vec<Vec<Vec<(i8, i8)>>>>,
// Takes 64x64 sprite fragment with this index as Mino skin (skin_index[piece])
skin_index: Vec<usize>,
// If spawn position is fucked, it fixes it
spawn_offsets: Vec<(isize, isize)>,
lock_delay_mode: LockDelayMode
}
lazy_static!{
static ref ROTATION_SYSTEMS: HashMap<String, PiecesData> = {
let mut rs = HashMap::new();
rs.insert(String::from("SRS"), PiecesData{
pieces: vec![
vec![ // Z
vec![(0, 2), (1, 2), (1, 1), (2, 1)],
vec![(2, 2), (2, 1), (1, 1), (1, 0)],
vec![(2, 0), (1, 0), (1, 1), (0, 1)],
vec![(0, 0), (0, 1), (1, 1), (1, 2)]
],
vec![ // J
vec![(0, 2), (0, 1), (1, 1), (2, 1)],
vec![(2, 2), (1, 2), (1, 1), (1, 0)],
vec![(2, 0), (2, 1), (1, 1), (0, 1)],
vec![(0, 0), (1, 0), (1, 1), (1, 2)]
],
vec![ // I
vec![(0, 2), (1, 2), (2, 2), (3, 2)],
vec![(2, 3), (2, 2), (2, 1), (2, 0)],
vec![(3, 1), (2, 1), (1, 1), (0, 1)],
vec![(1, 0), (1, 1), (1, 2), (1, 3)]
],
vec![ // T
vec![(1, 2), (0, 1), (1, 1), (2, 1)],
vec![(2, 1), (1, 2), (1, 1), (1, 0)],
vec![(1, 0), (2, 1), (1, 1), (0, 1)],
vec![(0, 1), (1, 0), (1, 1), (1, 2)]
],
vec![ // O
vec![(0, 0), (0, 1), (1, 1), (1, 0)],
vec![(0, 1), (1, 1), (1, 0), (0, 0)],
vec![(1, 1), (1, 0), (0, 0), (0, 1)],
vec![(1, 0), (0, 0), (0, 1), (1, 1)]
],
vec![ // L
vec![(2, 2), (2, 1), (1, 1), (0, 1)],
vec![(2, 0), (1, 0), (1, 1), (1, 2)],
vec![(0, 0), (0, 1), (1, 1), (2, 1)],
vec![(0, 2), (1, 2), (1, 1), (1, 0)]
],
vec![ // S
vec![(2, 2), (1, 2), (1, 1), (0, 1)],
vec![(2, 0), (2, 1), (1, 1), (1, 2)],
vec![(0, 0), (1, 0), (1, 1), (2, 1)],
vec![(0, 2), (0, 1), (1, 1), (1, 0)]
]
],
kicks: vec![
vec![ // Z
vec![
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 0 -> 90
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 0 -> 270
],
vec![
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 180
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 180 -> 270
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 180 -> 90
],
vec![
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 0
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 180
]
],
vec![ // J
vec![
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 0 -> 90
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 0 -> 270
],
vec![
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 180
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 180 -> 270
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 180 -> 90
],
vec![
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 0
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 180
]
],
vec![ // I
vec![
vec![( 0, 0),(-2, 0),( 1, 0),(-2,-1),( 1, 2)], // 0 -> 90
vec![( 0, 0),(-1, 0),( 2, 0),(-1, 2),( 2,-1)], // 0 -> 270
],
vec![
vec![( 0, 0),(-1, 0),( 2, 0),(-1, 2),( 2,-1)], // 90 -> 180
vec![( 0, 0),( 2, 0),(-1, 0),( 2, 1),(-1,-2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 2, 0),(-1, 0),( 2, 1),(-1,-2)], // 180 -> 270
vec![( 0, 0),( 1, 0),(-2, 0),( 1,-2),(-2, 1)], // 180 -> 90
],
vec![
vec![( 0, 0),( 1, 0),(-2, 0),( 1,-2),(-2, 1)], // 270 -> 0
vec![( 0, 0),(-2, 0),( 1, 0),(-2,-1),( 1, 2)], // 270 -> 180
]
],
vec![ // T
vec![
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 0 -> 90
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 0 -> 270
],
vec![
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 180
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 180 -> 270
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 180 -> 90
],
vec![
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 0
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 180
]
],
vec![ // O
vec![
vec![( 0, 0)], // 0 -> 90
vec![( 0, 0)], // 0 -> 270
],
vec![
vec![( 0, 0)], // 90 -> 180
vec![( 0, 0)], // 90 -> 0
],
vec![
vec![( 0, 0)], // 180 -> 270
vec![( 0, 0)], // 180 -> 90
],
vec![
vec![( 0, 0)], // 270 -> 0
vec![( 0, 0)], // 270 -> 180
]
],
vec![ // L
vec![
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 0 -> 90
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 0 -> 270
],
vec![
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 180
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 180 -> 270
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 180 -> 90
],
vec![
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 0
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 180
]
],
vec![ // S
vec![
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 0 -> 90
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 0 -> 270
],
vec![
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 180
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 180 -> 270
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 180 -> 90
],
vec![
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 0
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 180
]
],
],
skin_index: vec![0, 1, 2, 3, 4, 5, 6],
spawn_offsets: vec![
(0, 0), // Z
(0, 0), // J
(0, -1), // I
(0, 0), // T
(1, 1), // O
(0, 0), // L
(0, 0) // S
],
lock_delay_mode: LockDelayMode::ResetOnMovementLimited
});
rs
};
}
#[derive(Component, Clone, Copy)]
struct Mino{
skin_index: usize
}
#[derive(Clone, Copy)]
struct Piece{
id: usize,
position: (isize, isize),
rotation: usize
}
#[derive(Component)]
struct BoardVisual{}
struct Board{
width: u8,
height: u8,
buffer_height: u8,
show_grid: bool,
show_shadow: bool,
// X axis - from left to right; Y axis - from bottom to top (grid[y][x])
grid: Vec<Vec<Option<Mino>>>
}
impl Board{
fn create(width: u8, height: u8, buffer_height: u8, show_grid: bool, show_shadow: bool) -> Board {
let grid: Vec<Vec<Option<Mino>>> = vec![vec![None; width as usize]; (height+buffer_height) as usize];
Board { width: width, height: height, buffer_height: buffer_height, show_grid: show_grid, show_shadow: show_shadow, grid: grid }
}
fn clear_full_lines(&mut self) {
let mut lines_cleared: usize = 0;
for row in 0..self.grid.len(){
if self.grid[row-lines_cleared].iter().all(|l| l.is_some()){
self.grid.remove(row-lines_cleared);
let empty_row: Vec<Option<Mino>> = vec![None; self.width as usize];
self.grid.push(empty_row);
lines_cleared += 1;
}
}
}
}
struct Handling{
das: f32, // ms
arr: f32, // ms
sdf: f32, // gravity*sdf = soft drop
das_left: f32, // ms
arr_left: f32, // ms
sdf_active: bool,
active_left: bool,
active_right: bool,
direction: i8 // -1 - left, 1 - right, 0 - none
}
impl Handling {
fn create(das: f32, arr: f32, sdf: f32) -> Handling{
Handling { das: das, arr: arr, sdf: sdf, das_left: das, arr_left: arr, sdf_active:false, active_left: false, active_right: false, direction: 0}
}
fn movement_key_pressed(&mut self, left: bool, right: bool){
if left {
self.active_left = left;
self.direction = -1;
}
if right {
self.active_right = right;
self.direction = 1;
}
self.das_left = self.das;
}
fn movement_key_released(&mut self, left: bool, right: bool){
if left {
self.active_left = !left;
}
if right {
self.active_right = !right;
}
if self.active_left {
self.direction = -1;
}
if self.active_right {
self.direction = 1;
}
if !self.active_left && !self.active_right{
self.arr_left = self.arr;
self.das_left = self.das;
self.direction = 0;
}
}
fn movement_tick(&mut self, delta: f32) -> i8 {
if !self.active_left && !self.active_right {
return 0;
}
if self.das_left > 0.0 {
self.das_left -= delta;
if self.das_left <= 0.0 {
self.arr_left += self.das_left;
self.das_left = 0.0;
return self.direction;
}else{
return 0;
}
}else{
self.arr_left -= delta;
if self.arr_left <= 0.0 {
self.arr_left += self.arr;
return self.direction;
}else {
return 0;
}
}
}
}
#[derive(Resource)]
struct Engine {
current_piece: Option<Piece>,
board: Board,
handling: Handling,
rotation_system: PiecesData,
next_queue: Vec<Piece>,
hold: Option<Piece>,
can_hold: bool,
g: f32,
g_bucket: f32,
lock_delay: u8,
lock_delay_left: u8,
lock_delay_resets: u8,
lock_delay_resets_left: u8
}
impl Default for Engine {
fn default() -> Engine {
Engine {
current_piece: None,
board: Board::create(10, 20, 20, true, true),
handling: Handling::create(200.0, 33.0, 20.0),
rotation_system: ROTATION_SYSTEMS["SRS"].clone(),
next_queue: vec![],
hold: None,
can_hold: true,
g: 1.0/60.0,
g_bucket: 0.0,
lock_delay: 30,
lock_delay_left: 30,
lock_delay_resets: 15,
lock_delay_resets_left: 15
}
}
}
impl Engine {
fn temporary_random(&mut self){
let piece_id = random::<usize>() % self.rotation_system.pieces.len();
let final_position = (3+self.rotation_system.spawn_offsets[piece_id].0, 20+self.rotation_system.spawn_offsets[piece_id].1);
self.current_piece = Some(Piece { id: piece_id, position: final_position, rotation: 0 });
if self.g >= 20.0 { self.current_piece.as_mut().unwrap().position.1 = self.lowest_point_under_current_piece() }
}
fn lock_current_piece(&mut self) -> bool {
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;
}
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.grid[y][x] = Some(Mino{ skin_index: color_index });
}
self.current_piece = None;
return true;
}
fn sonic_drop(&mut self) -> bool {
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;
}
self.current_piece.as_mut().unwrap().position.1 = self.lowest_point_under_current_piece();
true
}
fn lowest_point_under_current_piece(&self) -> isize{
let mut y = self.current_piece.as_ref().unwrap().position.1;
while self.position_is_valid((self.current_piece.as_ref().unwrap().position.0, y-1), self.current_piece.as_ref().unwrap().rotation){
y -= 1
}
y
}
fn rotate_current_piece(&mut self, rotation: i8) -> bool {
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
}else{
1
};
for test in &self.rotation_system.kicks[self.current_piece.as_ref().unwrap().id][self.current_piece.as_ref().unwrap().rotation][id_for_kicks]{
let future_position = (self.current_piece.as_ref().unwrap().position.0 + test.0 as isize, self.current_piece.as_ref().unwrap().position.1 + test.1 as isize);
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;
return true;
}
}
false
}
fn move_current_piece(&mut self, shift: (i8, i8)) -> bool {
if (shift.0 == 0 && shift.1 == 0) || self.current_piece.is_none(){
return true;
}
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
);
if self.position_is_valid(future_position, self.current_piece.as_ref().unwrap().rotation) {
self.current_piece.as_mut().unwrap().position = future_position;
true
}else {
false
}
}
fn position_is_valid(&self, future_position: (isize, isize), future_rotation: usize) -> bool {
for mino in &self.rotation_system.pieces[self.current_piece.as_ref().unwrap().id][future_rotation]{
match self.board.grid.get((future_position.1 + mino.1 as isize) as usize) {
Some(line) => match line.get((future_position.0 + mino.0 as isize) as usize) {
Some(cell) => match cell {
Some(_) => return false,
None => continue,
},
None => return false,
},
None => return false,
}
}
true
}
}
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)] #[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
enum GameStates{ pub enum GameStates{
#[default] #[default]
Init, Init,
Gameplay, Gameplay,
@ -490,199 +33,10 @@ enum GameStates{
} }
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)] #[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
enum GameloopStates { pub enum GameloopStates {
#[default] #[default]
Init, Init,
Spawn, Spawn,
Falling, Falling,
AfterLocking AfterLocking
}
fn init_engine(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
mut engine: ResMut<Engine>,
mut next_state: ResMut<NextState<GameloopStates>>,
){
commands.spawn((
MaterialMesh2dBundle {
mesh: meshes.add(Mesh::from(shape::Quad{ size: Vec2 { x: engine.board.width as f32 * MINO_SIZE, y: engine.board.height as f32 * MINO_SIZE }, flip: false })).into(),
material: materials.add(ColorMaterial::from(Color::PURPLE)),
transform: Transform::from_xyz(0.0, 0.0, -1.0),
..default()
},
BoardVisual{}
));
engine.temporary_random();
next_state.set(GameloopStates::Falling);
}
fn draw_board(
mut commands: Commands,
engine: Res<Engine>,
all_minos: Query<Entity, With<Mino>>,
asset_server: Res<AssetServer>
){
for mino in all_minos.iter() {
commands.entity(mino).despawn();
}
let mut x: f32 = 0.0;
let mut y: f32 = 0.0;
// draw board
for row in &engine.board.grid {
for mino in row {
match mino {
Some(mino) => {
commands.spawn((
SpriteBundle {
transform: Transform::from_xyz(
x*MINO_SIZE-(engine.board.width as f32)/2.0*MINO_SIZE+MINO_SIZE/2.0,
y*MINO_SIZE-(engine.board.height as f32)/2.0*MINO_SIZE+MINO_SIZE/2.0,
0.0
),
texture: asset_server.load("skin.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 },
}
),
custom_size: Some(Vec2 {x: MINO_SIZE, y: MINO_SIZE}),
..default()
},
..default()
},
*mino,
));
}
None => {},
};
x += 1.0;
}
x = 0.0;
y += 1.0;
}
//draw current piece
match engine.current_piece.as_ref() {
Some(piece) => {
x = piece.position.0 as f32;
y = piece.position.1 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("skin.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 },
}
),
custom_size: Some(Vec2 {x: MINO_SIZE, y: MINO_SIZE}),
..default()
},
..default()
},
Mino{skin_index: engine.rotation_system.skin_index[piece.id]},
));
}
},
None => {},
}
}
fn receive_input(
keyboard_input: Res<Input<KeyCode>>,
mut engine: ResMut<Engine>,
mut next_state: ResMut<NextState<GameloopStates>>,
){
if keyboard_input.any_just_pressed([KeyCode::Up, KeyCode::X]) {
engine.rotate_current_piece(1);
}
if keyboard_input.just_pressed(KeyCode::Z) {
engine.rotate_current_piece(-1);
}
if keyboard_input.just_pressed(KeyCode::Left) {
engine.move_current_piece((-1, 0));
engine.handling.movement_key_pressed(true, false)
}
if keyboard_input.just_pressed(KeyCode::Right) {
engine.move_current_piece((1, 0));
engine.handling.movement_key_pressed(false, true)
}
if keyboard_input.just_released(KeyCode::Left) {
engine.handling.movement_key_released(true, false)
}
if keyboard_input.just_released(KeyCode::Right) {
engine.handling.movement_key_released(false, true)
}
if keyboard_input.just_pressed(KeyCode::Down) {
engine.handling.sdf_active = true;
}
if keyboard_input.just_released(KeyCode::Down) {
engine.handling.sdf_active = false;
}
if keyboard_input.just_pressed(KeyCode::Space) {
engine.sonic_drop();
engine.lock_current_piece();
next_state.set(GameloopStates::AfterLocking);
}
}
fn das_and_arr(
mut engine: ResMut<Engine>,
time: Res<Time>
){
let direction = engine.handling.movement_tick(time.delta_seconds()*1000.0);
engine.move_current_piece((direction, 0));
}
fn gameloop(
clocks: Res<Time<Fixed>>,
mut engine: ResMut<Engine>,
mut next_state: ResMut<NextState<GameloopStates>>,
) {
info!("{:?}", clocks);
match engine.current_piece {
Some(piece) => {
engine.g_bucket += engine.g;
if engine.handling.sdf_active {engine.g_bucket += engine.g * engine.handling.sdf}
while engine.g_bucket >= 1.0 {
engine.move_current_piece((0, -1));
engine.g_bucket -= 1.0;
}
if !engine.position_is_valid((piece.position.0, piece.position.1-1), piece.rotation){
engine.lock_delay_left -= 1;
}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){
engine.lock_current_piece();
next_state.set(GameloopStates::AfterLocking);
}
},
None => {
},
}
}
fn after_locking_routine(
mut engine: ResMut<Engine>,
mut next_state: ResMut<NextState<GameloopStates>>,
){
engine.board.clear_full_lines();
engine.lock_delay_left = engine.lock_delay;
engine.lock_delay_resets_left = engine.lock_delay_resets;
engine.temporary_random();
next_state.set(GameloopStates::Falling);
} }

241
src/engine/resources.rs Normal file
View File

@ -0,0 +1,241 @@
use bevy::prelude::*;
use rand::random;
use super::{rotation_systems::{PiecesData, ROTATION_SYSTEMS}, components::Mino};
#[derive(Clone, Copy)]
pub struct Piece{
pub id: usize,
pub position: (isize, isize),
pub rotation: usize
}
pub struct Board{
pub width: u8,
pub height: u8,
pub buffer_height: u8,
pub show_grid: bool,
pub show_shadow: bool,
// X axis - from left to right; Y axis - from bottom to top (grid[y][x])
pub grid: Vec<Vec<Option<Mino>>>
}
impl Board{
pub fn create(width: u8, height: u8, buffer_height: u8, show_grid: bool, show_shadow: bool) -> Board {
let grid: Vec<Vec<Option<Mino>>> = vec![vec![None; width as usize]; (height+buffer_height) as usize];
Board { width: width, height: height, buffer_height: buffer_height, show_grid: show_grid, show_shadow: show_shadow, grid: grid }
}
pub fn clear_full_lines(&mut self) {
let mut lines_cleared: usize = 0;
for row in 0..self.grid.len(){
if self.grid[row-lines_cleared].iter().all(|l| l.is_some()){
self.grid.remove(row-lines_cleared);
let empty_row: Vec<Option<Mino>> = vec![None; self.width as usize];
self.grid.push(empty_row);
lines_cleared += 1;
}
}
}
}
pub struct Handling{
pub das: f32, // ms
pub arr: f32, // ms
pub sdf: f32, // gravity*sdf = soft drop
pub das_left: f32, // ms
pub arr_left: f32, // ms
pub sdf_active: bool,
pub active_left: bool,
pub active_right: bool,
pub direction: i8 // -1 - left, 1 - right, 0 - none
}
impl Handling {
pub fn create(das: f32, arr: f32, sdf: f32) -> Handling{
Handling { das: das, arr: arr, sdf: sdf, das_left: das, arr_left: arr, sdf_active:false, active_left: false, active_right: false, direction: 0}
}
pub fn movement_key_pressed(&mut self, left: bool, right: bool){
if left {
self.active_left = left;
self.direction = -1;
}
if right {
self.active_right = right;
self.direction = 1;
}
self.das_left = self.das;
}
pub fn movement_key_released(&mut self, left: bool, right: bool){
if left {
self.active_left = !left;
}
if right {
self.active_right = !right;
}
if self.active_left {
self.direction = -1;
}
if self.active_right {
self.direction = 1;
}
if !self.active_left && !self.active_right{
self.arr_left = self.arr;
self.das_left = self.das;
self.direction = 0;
}
}
pub fn movement_tick(&mut self, delta: f32) -> i8 {
if !self.active_left && !self.active_right {
return 0;
}
if self.das_left > 0.0 {
self.das_left -= delta;
if self.das_left <= 0.0 {
self.arr_left += self.das_left;
self.das_left = 0.0;
return self.direction;
}else{
return 0;
}
}else{
self.arr_left -= delta;
if self.arr_left <= 0.0 {
self.arr_left += self.arr;
return self.direction;
}else {
return 0;
}
}
}
}
#[derive(Resource)]
pub struct Engine {
pub current_piece: Option<Piece>,
pub board: Board,
pub handling: Handling,
pub rotation_system: PiecesData,
pub next_queue: Vec<Piece>,
pub hold: Option<Piece>,
pub can_hold: bool,
pub g: f32,
pub g_bucket: f32,
pub lock_delay: u8,
pub lock_delay_left: u8,
pub lock_delay_resets: u8,
pub lock_delay_resets_left: u8
}
impl Default for Engine {
fn default() -> Engine {
Engine {
current_piece: None,
board: Board::create(10, 20, 20, true, true),
handling: Handling::create(200.0, 33.0, 20.0),
rotation_system: ROTATION_SYSTEMS["SRS"].clone(),
next_queue: vec![],
hold: None,
can_hold: true,
g: 1.0/60.0,
g_bucket: 0.0,
lock_delay: 30,
lock_delay_left: 30,
lock_delay_resets: 15,
lock_delay_resets_left: 15
}
}
}
impl Engine {
pub fn temporary_random(&mut self){
let piece_id = random::<usize>() % self.rotation_system.pieces.len();
let final_position = (3+self.rotation_system.spawn_offsets[piece_id].0, 20+self.rotation_system.spawn_offsets[piece_id].1);
self.current_piece = Some(Piece { id: piece_id, position: final_position, rotation: 0 });
if self.g >= 20.0 { self.current_piece.as_mut().unwrap().position.1 = self.lowest_point_under_current_piece() }
}
pub fn lock_current_piece(&mut self) -> bool {
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;
}
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.grid[y][x] = Some(Mino{ skin_index: color_index });
}
self.current_piece = None;
return true;
}
pub fn sonic_drop(&mut self) -> bool {
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;
}
self.current_piece.as_mut().unwrap().position.1 = self.lowest_point_under_current_piece();
true
}
pub fn lowest_point_under_current_piece(&self) -> isize{
let mut y = self.current_piece.as_ref().unwrap().position.1;
while self.position_is_valid((self.current_piece.as_ref().unwrap().position.0, y-1), self.current_piece.as_ref().unwrap().rotation){
y -= 1
}
y
}
pub fn rotate_current_piece(&mut self, rotation: i8) -> bool {
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
}else{
1
};
for test in &self.rotation_system.kicks[self.current_piece.as_ref().unwrap().id][self.current_piece.as_ref().unwrap().rotation][id_for_kicks]{
let future_position = (self.current_piece.as_ref().unwrap().position.0 + test.0 as isize, self.current_piece.as_ref().unwrap().position.1 + test.1 as isize);
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;
return true;
}
}
false
}
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;
}
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
);
if self.position_is_valid(future_position, self.current_piece.as_ref().unwrap().rotation) {
self.current_piece.as_mut().unwrap().position = future_position;
true
}else {
false
}
}
pub fn position_is_valid(&self, future_position: (isize, isize), future_rotation: usize) -> bool {
for mino in &self.rotation_system.pieces[self.current_piece.as_ref().unwrap().id][future_rotation]{
match self.board.grid.get((future_position.1 + mino.1 as isize) as usize) {
Some(line) => match line.get((future_position.0 + mino.0 as isize) as usize) {
Some(cell) => match cell {
Some(_) => return false,
None => continue,
},
None => return false,
},
None => return false,
}
}
true
}
}

View File

@ -0,0 +1,216 @@
use bevy::utils::HashMap;
use lazy_static::lazy_static;
#[derive(Clone)]
pub enum LockDelayMode{
Disabled,
Gravity,
ResetOnYChange,
ResetOnMovementLimited,
ResetOnMovement
}
#[derive(Clone)]
pub struct PiecesData {
// X and Y from bottom left point (pieces[piece][rotation] = Vec of coords for Minos)
pub pieces: Vec<Vec<Vec<(u8, u8)>>>,
// X and Y shifts for pieces (kicks[piece][rotation before spin][direction of rotation] = Vec of points for tests)
pub kicks: Vec<Vec<Vec<Vec<(i8, i8)>>>>,
// Takes 64x64 sprite fragment with this index as Mino skin (skin_index[piece])
pub skin_index: Vec<usize>,
// If spawn position is fucked, it fixes it
pub spawn_offsets: Vec<(isize, isize)>,
pub lock_delay_mode: LockDelayMode
}
lazy_static!{
pub static ref ROTATION_SYSTEMS: HashMap<String, PiecesData> = {
let mut rs = HashMap::new();
rs.insert(String::from("SRS"), PiecesData{
pieces: vec![
vec![ // Z
vec![(0, 2), (1, 2), (1, 1), (2, 1)],
vec![(2, 2), (2, 1), (1, 1), (1, 0)],
vec![(2, 0), (1, 0), (1, 1), (0, 1)],
vec![(0, 0), (0, 1), (1, 1), (1, 2)]
],
vec![ // J
vec![(0, 2), (0, 1), (1, 1), (2, 1)],
vec![(2, 2), (1, 2), (1, 1), (1, 0)],
vec![(2, 0), (2, 1), (1, 1), (0, 1)],
vec![(0, 0), (1, 0), (1, 1), (1, 2)]
],
vec![ // I
vec![(0, 2), (1, 2), (2, 2), (3, 2)],
vec![(2, 3), (2, 2), (2, 1), (2, 0)],
vec![(3, 1), (2, 1), (1, 1), (0, 1)],
vec![(1, 0), (1, 1), (1, 2), (1, 3)]
],
vec![ // T
vec![(1, 2), (0, 1), (1, 1), (2, 1)],
vec![(2, 1), (1, 2), (1, 1), (1, 0)],
vec![(1, 0), (2, 1), (1, 1), (0, 1)],
vec![(0, 1), (1, 0), (1, 1), (1, 2)]
],
vec![ // O
vec![(0, 0), (0, 1), (1, 1), (1, 0)],
vec![(0, 1), (1, 1), (1, 0), (0, 0)],
vec![(1, 1), (1, 0), (0, 0), (0, 1)],
vec![(1, 0), (0, 0), (0, 1), (1, 1)]
],
vec![ // L
vec![(2, 2), (2, 1), (1, 1), (0, 1)],
vec![(2, 0), (1, 0), (1, 1), (1, 2)],
vec![(0, 0), (0, 1), (1, 1), (2, 1)],
vec![(0, 2), (1, 2), (1, 1), (1, 0)]
],
vec![ // S
vec![(2, 2), (1, 2), (1, 1), (0, 1)],
vec![(2, 0), (2, 1), (1, 1), (1, 2)],
vec![(0, 0), (1, 0), (1, 1), (2, 1)],
vec![(0, 2), (0, 1), (1, 1), (1, 0)]
]
],
kicks: vec![
vec![ // Z
vec![
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 0 -> 90
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 0 -> 270
],
vec![
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 180
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 180 -> 270
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 180 -> 90
],
vec![
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 0
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 180
]
],
vec![ // J
vec![
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 0 -> 90
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 0 -> 270
],
vec![
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 180
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 180 -> 270
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 180 -> 90
],
vec![
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 0
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 180
]
],
vec![ // I
vec![
vec![( 0, 0),(-2, 0),( 1, 0),(-2,-1),( 1, 2)], // 0 -> 90
vec![( 0, 0),(-1, 0),( 2, 0),(-1, 2),( 2,-1)], // 0 -> 270
],
vec![
vec![( 0, 0),(-1, 0),( 2, 0),(-1, 2),( 2,-1)], // 90 -> 180
vec![( 0, 0),( 2, 0),(-1, 0),( 2, 1),(-1,-2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 2, 0),(-1, 0),( 2, 1),(-1,-2)], // 180 -> 270
vec![( 0, 0),( 1, 0),(-2, 0),( 1,-2),(-2, 1)], // 180 -> 90
],
vec![
vec![( 0, 0),( 1, 0),(-2, 0),( 1,-2),(-2, 1)], // 270 -> 0
vec![( 0, 0),(-2, 0),( 1, 0),(-2,-1),( 1, 2)], // 270 -> 180
]
],
vec![ // T
vec![
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 0 -> 90
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 0 -> 270
],
vec![
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 180
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 180 -> 270
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 180 -> 90
],
vec![
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 0
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 180
]
],
vec![ // O
vec![
vec![( 0, 0)], // 0 -> 90
vec![( 0, 0)], // 0 -> 270
],
vec![
vec![( 0, 0)], // 90 -> 180
vec![( 0, 0)], // 90 -> 0
],
vec![
vec![( 0, 0)], // 180 -> 270
vec![( 0, 0)], // 180 -> 90
],
vec![
vec![( 0, 0)], // 270 -> 0
vec![( 0, 0)], // 270 -> 180
]
],
vec![ // L
vec![
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 0 -> 90
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 0 -> 270
],
vec![
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 180
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 180 -> 270
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 180 -> 90
],
vec![
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 0
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 180
]
],
vec![ // S
vec![
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 0 -> 90
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 0 -> 270
],
vec![
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 180
vec![( 0, 0),( 1, 0),( 1,-1),( 0, 2),( 1, 2)], // 90 -> 0
],
vec![
vec![( 0, 0),( 1, 0),( 1, 1),( 0,-2),( 1,-2)], // 180 -> 270
vec![( 0, 0),(-1, 0),(-1, 1),( 0,-2),(-1,-2)], // 180 -> 90
],
vec![
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 0
vec![( 0, 0),(-1, 0),(-1,-1),( 0, 2),(-1, 2)], // 270 -> 180
]
],
],
skin_index: vec![0, 1, 2, 3, 4, 5, 6],
spawn_offsets: vec![
(0, 0), // Z
(0, 0), // J
(0, -1), // I
(0, 0), // T
(1, 1), // O
(0, 0), // L
(0, 0) // S
],
lock_delay_mode: LockDelayMode::ResetOnMovementLimited
});
rs
};
}

202
src/engine/systems.rs Normal file
View File

@ -0,0 +1,202 @@
use bevy::{prelude::*, sprite::MaterialMesh2dBundle};
use crate::engine::components::*;
use super::{resources::Engine, GameloopStates};
const MINO_SIZE: f32 = 20.0;
pub fn init_engine(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
mut engine: ResMut<Engine>,
mut next_state: ResMut<NextState<GameloopStates>>,
){
commands.spawn((
MaterialMesh2dBundle {
mesh: meshes.add(Mesh::from(shape::Quad{ size: Vec2 { x: engine.board.width as f32 * MINO_SIZE, y: engine.board.height as f32 * MINO_SIZE }, flip: false })).into(),
material: materials.add(ColorMaterial::from(Color::PURPLE)),
transform: Transform::from_xyz(0.0, 0.0, -1.0),
..default()
},
BoardVisual{}
));
engine.temporary_random();
next_state.set(GameloopStates::Falling);
}
pub fn draw_board(
mut commands: Commands,
engine: Res<Engine>,
all_minos: Query<Entity, With<Mino>>,
asset_server: Res<AssetServer>
){
for mino in all_minos.iter() {
commands.entity(mino).despawn();
}
let mut x: f32 = 0.0;
let mut y: f32 = 0.0;
// draw board
for row in &engine.board.grid {
for mino in row {
match mino {
Some(mino) => {
commands.spawn((
SpriteBundle {
transform: Transform::from_xyz(
x*MINO_SIZE-(engine.board.width as f32)/2.0*MINO_SIZE+MINO_SIZE/2.0,
y*MINO_SIZE-(engine.board.height as f32)/2.0*MINO_SIZE+MINO_SIZE/2.0,
0.0
),
texture: asset_server.load("skin.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 },
}
),
custom_size: Some(Vec2 {x: MINO_SIZE, y: MINO_SIZE}),
..default()
},
..default()
},
*mino,
));
}
None => {},
};
x += 1.0;
}
x = 0.0;
y += 1.0;
}
//draw current piece
match engine.current_piece.as_ref() {
Some(piece) => {
x = piece.position.0 as f32;
y = piece.position.1 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("skin.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 },
}
),
custom_size: Some(Vec2 {x: MINO_SIZE, y: MINO_SIZE}),
..default()
},
..default()
},
Mino{skin_index: engine.rotation_system.skin_index[piece.id]},
));
}
},
None => {},
}
}
pub fn receive_input(
keyboard_input: Res<Input<KeyCode>>,
mut engine: ResMut<Engine>,
state: Res<State<GameloopStates>>,
mut next_state: ResMut<NextState<GameloopStates>>,
){
if keyboard_input.any_just_pressed([KeyCode::Up, KeyCode::X]) && state.get() == &GameloopStates::Falling {
engine.rotate_current_piece(1);
}
if keyboard_input.just_pressed(KeyCode::Z) && state.get() == &GameloopStates::Falling {
engine.rotate_current_piece(-1);
}
if keyboard_input.just_pressed(KeyCode::Left) {
if state.get() == &GameloopStates::Falling {
engine.move_current_piece((-1, 0));
}
engine.handling.movement_key_pressed(true, false)
}
if keyboard_input.just_pressed(KeyCode::Right) {
if state.get() == &GameloopStates::Falling {
engine.move_current_piece((1, 0));
}
engine.handling.movement_key_pressed(false, true)
}
if keyboard_input.just_released(KeyCode::Left) {
engine.handling.movement_key_released(true, false)
}
if keyboard_input.just_released(KeyCode::Right) {
engine.handling.movement_key_released(false, true)
}
if keyboard_input.just_pressed(KeyCode::Down) {
engine.handling.sdf_active = true;
}
if keyboard_input.just_released(KeyCode::Down) {
engine.handling.sdf_active = false;
}
if keyboard_input.just_pressed(KeyCode::Space) && state.get() == &GameloopStates::Falling {
engine.sonic_drop();
engine.lock_current_piece();
next_state.set(GameloopStates::AfterLocking);
}
}
pub fn das_and_arr(
mut engine: ResMut<Engine>,
time: Res<Time>,
state: Res<State<GameloopStates>>,
){
let direction = engine.handling.movement_tick(time.delta_seconds()*1000.0);
if state.get() == &GameloopStates::Falling{
engine.move_current_piece((direction, 0));
}
}
pub fn gameloop(
clocks: Res<Time<Fixed>>,
mut engine: ResMut<Engine>,
mut next_state: ResMut<NextState<GameloopStates>>,
) {
info!("{:?}", clocks);
match engine.current_piece {
Some(piece) => {
engine.g_bucket += engine.g;
if engine.handling.sdf_active {engine.g_bucket += engine.g * engine.handling.sdf}
while engine.g_bucket >= 1.0 {
engine.move_current_piece((0, -1));
engine.g_bucket -= 1.0;
}
if !engine.position_is_valid((piece.position.0, piece.position.1-1), piece.rotation){
engine.lock_delay_left -= 1;
}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){
engine.lock_current_piece();
next_state.set(GameloopStates::AfterLocking);
}
},
None => {
},
}
}
pub fn after_locking_routine(
mut engine: ResMut<Engine>,
mut next_state: ResMut<NextState<GameloopStates>>,
){
engine.board.clear_full_lines();
engine.lock_delay_left = engine.lock_delay;
engine.lock_delay_resets_left = engine.lock_delay_resets;
engine.temporary_random();
next_state.set(GameloopStates::Falling);
}

View File

@ -28,44 +28,4 @@ fn startup(
// time: Res<Time>, // time: Res<Time>,
// ) { // ) {
// }
// //! Shows how to create systems that run every fixed timestep, rather than every tick.
// use bevy::prelude::*;
// const FIXED_TIMESTEP: f32 = 1.0/60.0;
// fn main() {
// App::new()
// .add_plugins(DefaultPlugins)
// // this system will run once every update (it should match your screen's refresh rate)
// //.add_systems(Update, frame_update)
// // add our system to the fixed timestep schedule
// .add_systems(FixedUpdate, fixed_update)
// // configure our fixed timestep schedule to run twice a second
// .insert_resource(FixedTime::new_from_secs(FIXED_TIMESTEP))
// .run();
// }
// /// your mom
// fn frame_update(mut last_time: Local<f32>, time: Res<Time>) {
// info!(
// "time since last frame_update: {}",
// time.raw_elapsed_seconds() - *last_time
// );
// *last_time = time.raw_elapsed_seconds();
// }
// fn fixed_update(mut last_time: Local<f32>, time: Res<Time>, fixed_time: Res<FixedTime>) {
// info!(
// "time since last fixed_update: {}",
// time.raw_elapsed_seconds() - *last_time
// );
// info!("fixed timestep: {}", FIXED_TIMESTEP);
// info!(
// "FPS: {}\n",
// fixed_time.accumulated().as_secs_f32()/FIXED_TIMESTEP*60.
// );
// *last_time = time.raw_elapsed_seconds();
// } // }