Init
This commit is contained in:
commit
7a3c2c9c43
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
.vscode
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "untitled_block_stacking_game"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bevy = "0.12.0"
|
||||||
|
rand = "0.8.5"
|
||||||
|
lazy_static = "1.4.0"
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1,688 @@
|
||||||
|
use bevy::{prelude::*, utils::HashMap};
|
||||||
|
use rand::prelude::*;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use bevy::sprite::{Sprite, MaterialMesh2dBundle};
|
||||||
|
|
||||||
|
const MINO_SIZE: f32 = 20.0;
|
||||||
|
|
||||||
|
pub struct UBSGEngine;
|
||||||
|
|
||||||
|
impl Plugin for UBSGEngine{
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.init_resource::<Engine>().
|
||||||
|
add_state::<GameStates>().
|
||||||
|
add_state::<GameloopStates>().
|
||||||
|
insert_resource(Engine::default()).
|
||||||
|
add_systems(Startup, init_engine).
|
||||||
|
add_systems(Update, (receive_input, das_and_arr).run_if(in_state(GameloopStates::Falling))).
|
||||||
|
add_systems(FixedUpdate, gameloop).
|
||||||
|
add_systems(OnEnter(GameloopStates::AfterLocking), after_locking_routine).
|
||||||
|
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)]
|
||||||
|
enum GameStates{
|
||||||
|
#[default]
|
||||||
|
Init,
|
||||||
|
Gameplay,
|
||||||
|
Pause,
|
||||||
|
GameOver
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
|
||||||
|
enum GameloopStates {
|
||||||
|
#[default]
|
||||||
|
Init,
|
||||||
|
Spawn,
|
||||||
|
Falling,
|
||||||
|
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);
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
mod engine;
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use engine::UBSGEngine;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.insert_resource(ClearColor(Color::DARK_GRAY))
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_plugins(UBSGEngine)
|
||||||
|
.add_systems(Startup, startup)
|
||||||
|
//.add_systems(Update, gameloop)
|
||||||
|
.insert_resource(Time::<Fixed>::from_hz(60.0))
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn startup(
|
||||||
|
mut commands: Commands,
|
||||||
|
//mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
//mut materials: ResMut<Assets<ColorMaterial>>,
|
||||||
|
//asset_server: Res<AssetServer>,
|
||||||
|
) {
|
||||||
|
commands.spawn(Camera2dBundle::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn gameloop(
|
||||||
|
// mut camera: Query<(Entity), With<Camera>>,
|
||||||
|
// 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();
|
||||||
|
// }
|
Loading…
Reference in New Issue