feat/refactor: draw full game field, randomized starting game state, basic code splitting

This commit is contained in:
YK 2024-07-14 03:21:42 +03:00
parent 138476111c
commit 3436bcf98d
5 changed files with 207 additions and 45 deletions

22
Cargo.lock generated
View File

@ -1804,6 +1804,7 @@ dependencies = [
"bevy",
"itertools 0.13.0",
"log",
"rand",
]
[[package]]
@ -2984,6 +2985,12 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "presser"
version = "0.3.1"
@ -3035,6 +3042,18 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
@ -3043,6 +3062,9 @@ name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "range-alloc"

View File

@ -10,6 +10,7 @@ anyhow = "1.0.86"
bevy = { version = "0.14.0", features = ["dynamic_linking"] }
itertools = "0.13.0"
log = { version = "*", features = ["max_level_debug", "release_max_level_warn"] }
rand = "0.8.5"
# Enable a small amount of optimization in debug mode.
[profile.dev]

View File

@ -1,64 +1,64 @@
use bevy::prelude::*;
mod setup;
mod prelude;
// This resource tracks the game's score
#[derive(Resource, Deref, DerefMut)]
struct Score (usize);
use prelude::*;
#[derive(Component)]
struct ScoreboardUi;
const BG_COLOR: Color = Color::srgb(0.949, 0.937, 0.769);
const SCOREBOARD_FONT_SIZE: f32 = 44.0;
const TEXT_COLOR: Color = Color::BLACK;
const SCORE_COLOR: Color = Color::srgb(0.4, 0.05, 0.04);
const SCOREBOARD_TEXT_PADDING: Val = Val::Px(22.0);
pub struct SqPlugin;
impl Plugin for SqPlugin {
fn build (&self, app: &mut App) {
let thread = &mut thread_rng();
let mut start = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1];
start.shuffle(thread);
// add things to your app here
app
.insert_resource(Score(0))
.insert_resource(ClearColor(BG_COLOR))
.insert_resource(Field(start))
;
}
}
fn setup (
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
asset_server: Res<AssetServer>,
) {
commands.spawn(Camera2dBundle::default());
commands.spawn((
ScoreboardUi,
TextBundle::from_sections([
TextSection::new(
"Score: ",
TextStyle {
font_size: SCOREBOARD_FONT_SIZE,
color: TEXT_COLOR,
..default()
fn spawn_square_at (commands: &mut Commands, level: u32, position: usize) {
let Some(&(x, y)) = sq_origins.get(position) else {
return;
};
let text = 2i32.pow(level);
let label = Text2dBundle {
text: Text::from_section(text.to_string(), TextStyle {
font_size: 48.,
color: Color::WHITE,
..Default::default()
}),
transform: Transform {
translation: Vec3::new(x, y, 0.0),
..Default::default()
},
),
TextSection::from_style(TextStyle {
font_size: SCOREBOARD_FONT_SIZE,
color: SCORE_COLOR,
..default()
}),
])
.with_style(Style {
position_type: PositionType::Absolute,
top: SCOREBOARD_TEXT_PADDING,
left: SCOREBOARD_TEXT_PADDING,
..default()
}),
));
..Default::default()
}
;
commands.spawn(SpriteBundle {
sprite: Sprite {
color: sq_colors[level as usize % sq_colors.len()],
..Default::default()
},
transform: Transform {
translation: Vec3::new(x, y, 0.0),
scale: Vec3::new(148.0, 148.0, 1.0),
..Default::default()
},
..Default::default()
});
commands.spawn(label);
}
fn update_scoreboard (score: Res<Score>, mut query: Query<&mut Text, With<ScoreboardUi>>) {
@ -66,6 +66,18 @@ fn update_scoreboard (score: Res<Score>, mut query: Query<&mut Text, With<Scoreb
text.sections[1].value = score.to_string();
}
fn render_field (
mut commands: Commands,
asset_server: Res<AssetServer>,
field: Res<Field>,
) {
for (idx, &val) in field.iter().enumerate() {
if val > 0 {
spawn_square_at(&mut commands, val, idx);
}
}
}
fn main () {
App::new()
@ -76,7 +88,8 @@ fn main () {
}),
..Default::default()
}), SqPlugin))
.add_systems(Startup, setup)
.add_systems(Startup, setup::setup)
.add_systems(Update, update_scoreboard)
.add_systems(Update, render_field)
.run();
}

47
src/prelude.rs Normal file
View File

@ -0,0 +1,47 @@
pub use bevy::prelude::*;
pub use rand::{ seq::SliceRandom, thread_rng, Rng };
#[derive(Resource, Deref, DerefMut)]
pub struct Score (pub usize);
#[derive(Component)]
pub struct ScoreboardUi;
#[derive(Resource, Deref, DerefMut)]
pub struct Field (pub Vec<u32>);
pub const BG_COLOR: Color = Color::srgb(0.949, 0.937, 0.769);
pub const SCOREBOARD_FONT_SIZE: f32 = 44.0;
pub const TEXT_COLOR: Color = Color::BLACK;
pub const SCORE_COLOR: Color = Color::srgb(0.4, 0.05, 0.04);
pub const SCOREBOARD_TEXT_PADDING: Val = Val::Px(22.0);
pub struct SqPlugin;
pub const sq_origins: [(f32, f32); 16] = [
(-225., 225.), (-75., 225.), (75., 225.), (225., 225.,),
(-225., 75.), (-75., 75.), (75., 75.), (225., 75.,),
(-225., -75.), (-75., -75.), (75., -75.), (225., -75.,),
(-225., -225.), (-75., -225.), (75., -225.), (225., -225.,),
];
pub const sq_colors: [Color; 16] = [
Color::srgb(0.373, 0.851, 0.91),
Color::srgb(0.373, 0.643, 0.91),
Color::srgb(0.247, 0.161, 0.761),
Color::srgb(0.451, 0.161, 0.761),
Color::srgb(0.502, 0.047, 0.98),
Color::srgb(0.663, 0.137, 0.91),
Color::srgb(0.443, 0.102, 0.6),
Color::srgb(0.851, 0.094, 0.773),
Color::srgb(0.89, 0.086, 0.412),
Color::srgb(0.91, 0.102, 0.102),
Color::srgb(0.671, 0.039, 0.039),
Color::srgb(0.82, 0.251, 0.059),
Color::srgb(0.851, 0.71, 0.039),
Color::srgb(0.569, 0.184, 0.051),
Color::srgb(0.016, 0.055, 0.231),
Color::srgb(0.02, 0.02, 0.02),
];

79
src/setup.rs Normal file
View File

@ -0,0 +1,79 @@
use crate::prelude::*;
pub fn setup (
mut commands: Commands,
mut _meshes: ResMut<Assets<Mesh>>,
mut _materials: ResMut<Assets<ColorMaterial>>,
_asset_server: Res<AssetServer>,
) {
commands.spawn(Camera2dBundle::default());
commands.spawn((
ScoreboardUi,
TextBundle::from_sections([
TextSection::new(
"Score: ",
TextStyle {
font_size: SCOREBOARD_FONT_SIZE,
color: TEXT_COLOR,
..default()
},
),
TextSection::from_style(TextStyle {
font_size: SCOREBOARD_FONT_SIZE,
color: SCORE_COLOR,
..default()
}),
])
.with_style(Style {
position_type: PositionType::Absolute,
top: SCOREBOARD_TEXT_PADDING,
left: SCOREBOARD_TEXT_PADDING,
..default()
}),
));
draw_board(&mut commands);
}
fn draw_board (commands: &mut Commands) {
let borders = [-305., 305.];
let lines = [-150., 0., 150.];
let border_width = 10.;
let line_width = 1.;
let length = 620.;
let border_color = Color::BLACK;
let line_color = Color::srgba(0., 0., 0., 0.667);
let bg_color = Color::srgba(0.2, 0.01, 0.5, 0.632);
// bg
commands.spawn(SpriteBundle {
sprite: Sprite { color: bg_color, ..Default::default() },
transform: Transform {
scale: Vec3::new(length, length, 1.0),
..Default::default()
},
..Default::default()
});
let line = |color: Color, translation: Vec3, scale: Vec3| SpriteBundle {
sprite: Sprite { color, ..Default::default() },
transform: Transform { translation, scale, ..Default::default() },
..Default::default()
};
// @TODO variable grid size
for border in 0..2 {
commands.spawn(line(border_color, Vec3::new(borders[border], 0.0, 0.0), Vec3::new(border_width, length, 1.0)));
commands.spawn(line(border_color, Vec3::new(0.0, borders[border], 0.0), Vec3::new(length, border_width, 1.0)));
}
for mesh in 0..3 {
commands.spawn(line(line_color, Vec3::new(lines[mesh], 0.0, 0.0), Vec3::new(line_width, length, 1.0)));
commands.spawn(line(line_color, Vec3::new(0.0, lines[mesh], 0.0), Vec3::new(length, line_width, 1.0)));
}
}