Compare commits
5 Commits
1a196ee3f2
...
6e7313a509
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e7313a509 | ||
|
|
9517b89479 | ||
|
|
efaad5c268 | ||
|
|
6c84c3b3b3 | ||
|
|
531db5fa20 |
113
Cargo.lock
generated
113
Cargo.lock
generated
@ -137,10 +137,10 @@ checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"const-random",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
"zerocopy 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1206,7 +1206,7 @@ dependencies = [
|
||||
"derive_more",
|
||||
"glam 0.29.2",
|
||||
"itertools",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rand_distr",
|
||||
"serde",
|
||||
"smallvec",
|
||||
@ -1768,7 +1768,7 @@ checksum = "7915222f4a08ccc782e08d10b751b42e5f9d786e697d0cb3fd09333cb7e8b6ea"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bevy_utils_proc_macros 0.12.1",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"hashbrown 0.14.5",
|
||||
"instant",
|
||||
"nonmax",
|
||||
@ -1786,7 +1786,7 @@ checksum = "63c2174d43a0de99f863c98a472370047a2bfa7d1e5cec8d9d647fb500905d9d"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bevy_utils_proc_macros 0.15.3",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"hashbrown 0.14.5",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
@ -2218,7 +2218,7 @@ version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"once_cell",
|
||||
"tiny-keccak",
|
||||
]
|
||||
@ -2871,10 +2871,22 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.13.3+wasi-0.2.2",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gilrs"
|
||||
version = "0.11.0"
|
||||
@ -2943,7 +2955,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@ -3567,6 +3579,7 @@ dependencies = [
|
||||
"bevy 0.15.3",
|
||||
"bevy_pancam",
|
||||
"bevy_touch_camera",
|
||||
"rand 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4334,7 +4347,7 @@ version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
"zerocopy 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4409,8 +4422,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
"zerocopy 0.8.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4420,7 +4444,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4429,7 +4463,16 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4439,7 +4482,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5216,7 +5259,7 @@ version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@ -5260,6 +5303,15 @@ version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.13.3+wasi-0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
@ -6209,6 +6261,15 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||
dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11-dl"
|
||||
version = "2.21.0"
|
||||
@ -6285,7 +6346,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
"zerocopy-derive 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcf01143b2dd5d134f11f545cf9f1431b13b749695cb33bcce051e7568f99478"
|
||||
dependencies = [
|
||||
"zerocopy-derive 0.8.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6298,3 +6368,14 @@ dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712c8386f4f4299382c9abee219bee7084f78fb939d88b6840fcc1320d5f6da2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
@ -7,10 +7,12 @@ edition = "2024"
|
||||
bevy = "0.15.3"
|
||||
bevy_pancam = "0.17.0"
|
||||
bevy_touch_camera = "0.1.2"
|
||||
rand = "0.9.0"
|
||||
|
||||
# Enable a small amount of optimization in the dev profile.
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
debug = true
|
||||
|
||||
# Enable a large amount of optimization in the dev profile for dependencies.
|
||||
[profile.dev.package."*"]
|
||||
|
||||
82
src/helpers.rs
Executable file
82
src/helpers.rs
Executable file
@ -0,0 +1,82 @@
|
||||
use crate::*;
|
||||
use bevy::prelude::*;
|
||||
|
||||
|
||||
pub struct RelatedMineIterator<'a> {
|
||||
inner: std::slice::Iter<'a, Option<Entity>>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for RelatedMineIterator<'a> {
|
||||
type Item = &'a Option<Entity>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.inner.next()
|
||||
}
|
||||
}
|
||||
|
||||
impl RelatedBoxes {
|
||||
pub fn iter(&self) -> Vec<Option<Entity>> {
|
||||
vec![
|
||||
self.ul.clone(),
|
||||
self.u.clone(),
|
||||
self.ur.clone(),
|
||||
self.l.clone(),
|
||||
self.r.clone(),
|
||||
self.dl.clone(),
|
||||
self.d.clone(),
|
||||
self.dr.clone(),
|
||||
]
|
||||
}
|
||||
pub fn relates_with(&self, entity: Entity) -> bool {
|
||||
for rel_entity in self.iter() {
|
||||
if let Some(e) = rel_entity {
|
||||
if e == entity {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
pub fn nearby_box_unopened_count(
|
||||
&self,
|
||||
opened_boxes: &Query<&OpenedBox>,
|
||||
) -> usize {
|
||||
let mut i = 0;
|
||||
for ent in self.iter() {
|
||||
if let Some(e) = ent {
|
||||
if !opened_boxes.contains(e) {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
pub fn nearby_box_marked_count(
|
||||
&self,
|
||||
boxes: &Query<&MarkedBox>,
|
||||
) -> usize {
|
||||
let mut i = 0;
|
||||
for ent in self.iter() {
|
||||
if let Some(e) = ent {
|
||||
if boxes.contains(e) {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
pub fn nearby_mines_count(
|
||||
&self,
|
||||
mine_boxes: &Query<&MineBox>,
|
||||
) -> usize {
|
||||
let mut i = 0;
|
||||
for ent in self.iter() {
|
||||
if let Some(e) = ent {
|
||||
if mine_boxes.contains(e) {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
476
src/main.rs
476
src/main.rs
@ -1,20 +1,69 @@
|
||||
use bevy::{ecs::system::SystemParam, input::mouse::MouseButtonInput, prelude::*, state::commands};
|
||||
mod helpers;
|
||||
use rand::{rng, Rng};
|
||||
use bevy::{prelude::*, text::FontSmoothing, time::Stopwatch};
|
||||
use bevy_pancam::*;
|
||||
|
||||
const BOARD_WIDTH :usize = 50;
|
||||
const BOARD_HEIGHT :usize = 50;
|
||||
const NUMER_OF_MINES :usize = 50;
|
||||
const COLOR_OPEN_BOX: Color = Color::srgb(0.749, 0.749, 0.635);
|
||||
const COLOR_HIDDEN_BOX: Color = Color::srgb(0.459, 0.459, 0.408);
|
||||
const COLOR_MARKED_BOX: Color = Color::srgb(0.769, 0.435, 0.043);
|
||||
const COLOR_OPEN_MINE: Color = Color::srgb(1., 0., 0.);
|
||||
|
||||
#[derive(Default, Reflect)]
|
||||
enum BoxType {
|
||||
Open,
|
||||
const BOARD_WIDTH :usize = 9;
|
||||
const BOARD_HEIGHT :usize = 9;
|
||||
const NUMER_OF_MINES :usize = 10;
|
||||
|
||||
#[derive(Component)]
|
||||
struct GameStopwatch(Stopwatch);
|
||||
|
||||
// Actions
|
||||
#[derive(Component)]
|
||||
struct BoxToMarkFlip;
|
||||
#[derive(Component)]
|
||||
struct BoxToMark;
|
||||
#[derive(Component)]
|
||||
struct BoxToOpen;
|
||||
|
||||
// Box States
|
||||
#[derive(Component)]
|
||||
struct OpenedBox;
|
||||
#[derive(Component)]
|
||||
struct MineBox;
|
||||
#[derive(Component)]
|
||||
struct MarkedBox;
|
||||
|
||||
#[derive(Component)]
|
||||
struct Box;
|
||||
|
||||
#[derive(Component)]
|
||||
struct HoveredBox;
|
||||
|
||||
#[derive(States, Default, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
enum GameState {
|
||||
StartUi,
|
||||
#[default]
|
||||
Closed,
|
||||
Mine
|
||||
Start,
|
||||
Playing,
|
||||
Win,
|
||||
Fail,
|
||||
}
|
||||
|
||||
#[derive(Default, Reflect, Component)]
|
||||
struct Box(BoxType);
|
||||
#[derive(Component, Clone, Copy)]
|
||||
struct RelatedBoxes {
|
||||
ul: Option<Entity>,
|
||||
u: Option<Entity>,
|
||||
ur: Option<Entity>,
|
||||
l: Option<Entity>,
|
||||
r: Option<Entity>,
|
||||
dl: Option<Entity>,
|
||||
d: Option<Entity>,
|
||||
dr: Option<Entity>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#[derive(Resource)]
|
||||
struct BoxMatrix([[Option<Entity>; BOARD_WIDTH]; BOARD_HEIGHT]);
|
||||
|
||||
#[derive(Resource)]
|
||||
struct MouseWorldCoordinate(Option<Vec2>);
|
||||
@ -25,66 +74,395 @@ fn main() {
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_plugins(PanCamPlugin)
|
||||
.insert_resource(MouseWorldCoordinate(None))
|
||||
.add_systems(Startup, (draw_mines, init_camera))
|
||||
.add_systems(PreUpdate, mouse_world_pos)
|
||||
.add_systems(Update, handle_box)
|
||||
.insert_resource(BoxMatrix([[None; BOARD_WIDTH]; BOARD_HEIGHT]))
|
||||
.insert_state(GameState::Start)
|
||||
.add_systems(Startup, (
|
||||
load_initial_entities,
|
||||
init_camera
|
||||
))
|
||||
.add_systems(PreUpdate, (mouse_world_pos, mark_hovered_box))
|
||||
.add_systems(Update, (init_mines).run_if(in_state(GameState::Start)).run_if(any_with_component::<HoveredBox>))
|
||||
.add_systems(Update, (
|
||||
(
|
||||
handle_box,
|
||||
game_stopwatch,
|
||||
switch_to_win,
|
||||
).run_if(in_state(GameState::Playing)).run_if(any_with_component::<HoveredBox>),
|
||||
open_box,
|
||||
mark_box,
|
||||
markflip_box,
|
||||
))
|
||||
.add_systems(OnEnter(GameState::Start), (despawn_boxes.before(draw_boxes), draw_boxes))
|
||||
.add_systems(OnEnter(GameState::Fail), draw_fail)
|
||||
.add_systems(OnEnter(GameState::Win), draw_win)
|
||||
.run();
|
||||
}
|
||||
|
||||
fn draw_mines(
|
||||
fn despawn_boxes(
|
||||
mut commands: Commands,
|
||||
boxes: Query<Entity, With<Box>>,
|
||||
) {
|
||||
for e in boxes.iter() {
|
||||
commands.entity(e).despawn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn load_initial_entities(
|
||||
mut commands: Commands,
|
||||
) {
|
||||
commands.spawn((
|
||||
// Accepts a `String` or any type that converts into a `String`, such as `&str`
|
||||
Text::new("0"),
|
||||
TextFont {
|
||||
font_size: 20.,
|
||||
..default()
|
||||
},
|
||||
TextColor(Color::srgb(0.,1.,1.)),
|
||||
Node {
|
||||
position_type: PositionType::Absolute,
|
||||
top: Val::Percent(0.),
|
||||
right: Val::Percent(50.),
|
||||
..default()
|
||||
},
|
||||
GameStopwatch(Stopwatch::new()),
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
fn game_stopwatch(
|
||||
mut game_stopwatch: Query<(&mut GameStopwatch, &mut Text)>,
|
||||
time: Res<Time>,
|
||||
) {
|
||||
let (mut stopwatch, mut text) = game_stopwatch.single_mut();
|
||||
stopwatch.0.tick(time.delta());
|
||||
let seconds = stopwatch.0.elapsed().as_secs_f64();
|
||||
text.0 = format!("T: {:.3}s", seconds);
|
||||
}
|
||||
|
||||
fn switch_to_win(
|
||||
mut next_state: ResMut<NextState<GameState>>,
|
||||
opened_safes: Query<&OpenedBox, Without<MineBox>>,
|
||||
) {
|
||||
if opened_safes.iter().count() != (BOARD_WIDTH*BOARD_HEIGHT - NUMER_OF_MINES) {
|
||||
return
|
||||
}
|
||||
next_state.set(GameState::Win);
|
||||
}
|
||||
|
||||
fn draw_win(
|
||||
mut commands: Commands,
|
||||
mut game_stopwatch: Query<&mut GameStopwatch>,
|
||||
) {
|
||||
let mut stopwatch = game_stopwatch.single_mut();
|
||||
stopwatch.0.pause();
|
||||
commands.spawn((
|
||||
// Accepts a `String` or any type that converts into a `String`, such as `&str`
|
||||
Text::new("WIN!!"),
|
||||
TextFont {
|
||||
font_size: 200.,
|
||||
..default()
|
||||
},
|
||||
TextColor(Color::srgb(0.,1.,1.)),
|
||||
Node {
|
||||
position_type: PositionType::Absolute,
|
||||
bottom: Val::Percent(50.),
|
||||
right: Val::Percent(50.),
|
||||
..default()
|
||||
},
|
||||
));
|
||||
}
|
||||
fn draw_fail(
|
||||
mut commands: Commands,
|
||||
mut game_stopwatch: Query<&mut GameStopwatch>,
|
||||
mut next_state: ResMut<NextState<GameState>>,
|
||||
) {
|
||||
let mut stopwatch = game_stopwatch.single_mut();
|
||||
stopwatch.0.pause();
|
||||
commands.spawn((
|
||||
// Accepts a `String` or any type that converts into a `String`, such as `&str`
|
||||
Text::new("FAIL!"),
|
||||
TextFont {
|
||||
font_size: 200.,
|
||||
..default()
|
||||
},
|
||||
TextColor(Color::srgb(1.,0.,0.)),
|
||||
Node {
|
||||
position_type: PositionType::Absolute,
|
||||
bottom: Val::Percent(50.),
|
||||
right: Val::Percent(50.),
|
||||
..default()
|
||||
},
|
||||
));
|
||||
next_state.set(GameState::Start);
|
||||
}
|
||||
|
||||
fn markflip_box(
|
||||
mut commands: Commands,
|
||||
box_entity_to_open: Query<Entity, With<BoxToMarkFlip>>,
|
||||
box_marked: Query<&MarkedBox>,
|
||||
mut color_material: Query<&mut MeshMaterial2d<ColorMaterial>>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||
) {
|
||||
for entity in box_entity_to_open.iter() {
|
||||
commands.entity(entity).remove::<BoxToMarkFlip>();
|
||||
let is_marked = box_marked.contains(entity);
|
||||
*color_material.get_mut(entity).unwrap() = match is_marked {
|
||||
true => {
|
||||
commands.entity(entity).remove::<(BoxToMarkFlip, MarkedBox)>();
|
||||
MeshMaterial2d(materials.add(COLOR_HIDDEN_BOX))
|
||||
},
|
||||
false => {
|
||||
commands.entity(entity).remove::<BoxToMarkFlip>().insert(MarkedBox);
|
||||
MeshMaterial2d(materials.add(COLOR_MARKED_BOX))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
fn mark_box(
|
||||
mut commands: Commands,
|
||||
box_entity_to_open: Query<Entity, (With<BoxToMark>, Without<OpenedBox>)>,
|
||||
mut color_material: Query<&mut MeshMaterial2d<ColorMaterial>>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||
) {
|
||||
for entity in box_entity_to_open.iter() {
|
||||
commands.entity(entity).remove::<BoxToMark>();
|
||||
commands.entity(entity).insert(MarkedBox);
|
||||
*color_material.get_mut(entity).unwrap() = MeshMaterial2d(materials.add(COLOR_MARKED_BOX));
|
||||
}
|
||||
}
|
||||
fn open_box(
|
||||
mut commands: Commands,
|
||||
box_entity_to_open: Query<Entity, (With<BoxToOpen>, Without<OpenedBox>)>,
|
||||
marked_boxes: Query<&MarkedBox>,
|
||||
mine_boxes: Query<&MineBox>,
|
||||
safe_opened_boxes: Query<&OpenedBox, Without<MineBox>>,
|
||||
related_boxes: Query<&RelatedBoxes>,
|
||||
mut color_material: Query<&mut MeshMaterial2d<ColorMaterial>>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||
mut next_state: ResMut<NextState<GameState>>,
|
||||
) {
|
||||
let mut boxes_to_open: Vec<Entity> = box_entity_to_open.iter().collect();
|
||||
if boxes_to_open.len() == 0 {
|
||||
return
|
||||
}
|
||||
let mut counter: usize = 0;
|
||||
loop {
|
||||
if counter >= boxes_to_open.len() {
|
||||
break
|
||||
}
|
||||
let entity = boxes_to_open[counter];
|
||||
counter += 1;
|
||||
commands.entity(entity).remove::<BoxToOpen>();
|
||||
if marked_boxes.contains(entity) {
|
||||
continue
|
||||
}
|
||||
commands.entity(entity).insert(OpenedBox);
|
||||
let mut r#material = color_material.get_mut(entity).unwrap();
|
||||
if mine_boxes.contains(entity) {
|
||||
next_state.set(GameState::Fail);
|
||||
*r#material = MeshMaterial2d(materials.add(COLOR_OPEN_MINE));
|
||||
return
|
||||
}
|
||||
*r#material = MeshMaterial2d(materials.add(COLOR_OPEN_BOX));
|
||||
let related_boxes = related_boxes.get(entity).unwrap();
|
||||
let rel_mine_count = related_boxes.nearby_mines_count(&mine_boxes);
|
||||
let text_entity = commands.spawn((
|
||||
Text2d::new( if rel_mine_count != 0 { rel_mine_count.to_string() } else {"".to_string()}),
|
||||
Transform::default().with_scale(Vec3::new(0.3,0.3,0.)),
|
||||
)).id();
|
||||
commands.entity(entity).add_child(text_entity);
|
||||
if rel_mine_count != 0 {
|
||||
continue
|
||||
}
|
||||
for related_box in related_boxes.iter() {
|
||||
let box_entity = match related_box {
|
||||
Some(b) => {b},
|
||||
None => {continue},
|
||||
};
|
||||
if safe_opened_boxes.contains(box_entity) {
|
||||
continue
|
||||
}
|
||||
if boxes_to_open.contains(&related_box.unwrap()) {
|
||||
continue
|
||||
}
|
||||
boxes_to_open.push(related_box.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_mines(
|
||||
mut commands: Commands,
|
||||
mouse_button_input: Res<ButtonInput<MouseButton>>,
|
||||
mine_boxes: Query<&MineBox>,
|
||||
mut hovered_box: Query<(Entity, &RelatedBoxes), With<HoveredBox>>,
|
||||
mut next_state: ResMut<NextState<GameState>>,
|
||||
box_matrix: Res<BoxMatrix>,
|
||||
mut game_stopwatch: Query<&mut GameStopwatch>,
|
||||
) {
|
||||
let _mouse_key = if mouse_button_input.just_pressed(MouseButton::Left) || mouse_button_input.just_pressed(MouseButton::Right) { MouseButton::Left }
|
||||
else {return};
|
||||
|
||||
let (hovered_entity, rel_mine) = hovered_box.single_mut();
|
||||
commands.entity(hovered_entity).insert(BoxToOpen);
|
||||
let mut number_of_mines = 0;
|
||||
'main: loop {
|
||||
for i in 0..box_matrix.0.len() {
|
||||
for j in 0..box_matrix.0[i].len() {
|
||||
let entity = box_matrix.0[i][j].unwrap();
|
||||
if entity == hovered_entity || rel_mine.relates_with(entity) {
|
||||
continue;
|
||||
}
|
||||
if !mine_boxes.contains(entity) {
|
||||
if random_bool(NUMER_OF_MINES as f64 / (BOARD_WIDTH*BOARD_HEIGHT) as f64) {
|
||||
number_of_mines += 1;
|
||||
commands.entity(entity).insert(MineBox);
|
||||
}
|
||||
}
|
||||
if number_of_mines >= NUMER_OF_MINES {
|
||||
break 'main
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
game_stopwatch.single_mut().0.reset();
|
||||
next_state.set(GameState::Playing);
|
||||
}
|
||||
|
||||
fn draw_boxes(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||
mut box_matrix: ResMut<BoxMatrix>,
|
||||
) {
|
||||
let rec = meshes.add(Rectangle::new(5., 5.));
|
||||
let offset_x = 8.;
|
||||
let offset_y = 8.;
|
||||
for i in 0..BOARD_WIDTH {
|
||||
for j in 0..BOARD_HEIGHT {
|
||||
commands.spawn((
|
||||
Mesh2d(rec.clone()),
|
||||
MeshMaterial2d(materials.add(Color::hsl(10.,10.,10.))),
|
||||
Transform::from_xyz(offset_x*(i as f32)+0., offset_y*(j as f32)+0., 0.),
|
||||
Box::default(),
|
||||
))
|
||||
;
|
||||
let offset_x = 5.9;
|
||||
let offset_y = 5.9;
|
||||
let mut matrix: [[Option<Entity>; BOARD_WIDTH]; BOARD_HEIGHT] = [[None; BOARD_WIDTH]; BOARD_HEIGHT];
|
||||
|
||||
for i in 0..BOARD_HEIGHT {
|
||||
for j in 0..BOARD_WIDTH {
|
||||
let x = offset_x*(i as f32);
|
||||
let y = offset_y*(j as f32);
|
||||
matrix[i][j] = Some(commands.spawn((
|
||||
Mesh2d(rec.clone()),
|
||||
MeshMaterial2d(materials.add(COLOR_HIDDEN_BOX)),
|
||||
Transform::from_xyz(x, y, 0.),
|
||||
Box,
|
||||
)
|
||||
).id());
|
||||
}
|
||||
}
|
||||
let get_cell = |i: isize, j: isize| -> Option<Entity> {
|
||||
match matrix.get(i as usize).and_then(|row| row.get(j as usize)).copied() {
|
||||
Some(s) => {s},
|
||||
None => {None},
|
||||
}
|
||||
};
|
||||
for i in 0..BOARD_HEIGHT {
|
||||
commands.entity(matrix[i][0].unwrap()).insert(
|
||||
RelatedBoxes {
|
||||
ul: None,
|
||||
u: get_cell(i as isize -1, 0),
|
||||
ur: get_cell(i as isize -1, 1),
|
||||
l: None,
|
||||
r: get_cell(i as isize , 1),
|
||||
dl: None,
|
||||
d: get_cell(i as isize +1, 0),
|
||||
dr: get_cell(i as isize +1, 1),
|
||||
}
|
||||
);
|
||||
for j in 0..BOARD_WIDTH {
|
||||
commands.entity(matrix[i][j].unwrap()).insert(
|
||||
RelatedBoxes {
|
||||
ul: get_cell(i as isize - 1, j as isize - 1),
|
||||
u: get_cell(i as isize - 1, j as isize),
|
||||
ur: get_cell(i as isize - 1, j as isize + 1),
|
||||
l: get_cell(i as isize, j as isize - 1),
|
||||
r: get_cell(i as isize, j as isize + 1),
|
||||
dl: get_cell(i as isize + 1, j as isize - 1),
|
||||
d: get_cell(i as isize + 1, j as isize),
|
||||
dr: get_cell(i as isize + 1, j as isize + 1),
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
box_matrix.0 = matrix;
|
||||
}
|
||||
|
||||
fn init_camera(mut commands: Commands) {
|
||||
commands.spawn((Camera2d, PanCam::default()));
|
||||
}
|
||||
fn handle_box(
|
||||
mouse_button_input: Res<ButtonInput<MouseButton>>,
|
||||
|
||||
fn mark_hovered_box(
|
||||
mut commands: Commands,
|
||||
mouse_world: Res<MouseWorldCoordinate>,
|
||||
mut boxes: Query<(&mut Box, &Transform, &MeshMaterial2d<ColorMaterial>)>
|
||||
) {
|
||||
if !mouse_button_input.just_pressed(MouseButton::Left){
|
||||
return
|
||||
mut boxes: Query<(Entity, &Transform), With<Box>>,
|
||||
prev_hovered: Query<Entity, With<HoveredBox>>,
|
||||
) {
|
||||
for e in prev_hovered.iter() {
|
||||
commands.entity(e).remove::<HoveredBox>();
|
||||
}
|
||||
let mouse = match mouse_world.0 {
|
||||
Some(x) => {x},
|
||||
None => return,
|
||||
};
|
||||
for (mut r#box, transform, material) in boxes.iter() {
|
||||
let lcl_x = transform.local_x().x;
|
||||
let lcl_y = transform.local_y().y;
|
||||
if lcl_x <= mouse.x &&
|
||||
lcl_x+BOARD_WIDTH as f32 >= mouse.x &&
|
||||
lcl_y <= mouse.y &&
|
||||
lcl_y+BOARD_HEIGHT as f32 >= mouse.y
|
||||
{
|
||||
println!("TRUE");
|
||||
let (entity, _) = match boxes.iter_mut().find(|(_, transform)| {
|
||||
let min = transform.translation.truncate() - 5. / 2.0;
|
||||
let max = transform.translation.truncate() + 5. / 2.0;
|
||||
mouse.x >= min.x && mouse.x <= max.x &&
|
||||
mouse.y >= min.y && mouse.y <= max.y
|
||||
}) {
|
||||
Some(s) => {s},
|
||||
None => {return},
|
||||
};
|
||||
commands.entity(entity).insert(HoveredBox);
|
||||
}
|
||||
|
||||
fn handle_box(
|
||||
mut commands: Commands,
|
||||
mouse_button_input: Res<ButtonInput<MouseButton>>,
|
||||
hovered_boxes: Query<Entity, With<HoveredBox>>,
|
||||
opened_boxes: Query<&OpenedBox>,
|
||||
mine_boxes: Query<&MineBox>,
|
||||
marked_boxes: Query<&MarkedBox>,
|
||||
related_boxes: Query<&RelatedBoxes>,
|
||||
) {
|
||||
|
||||
let mouse_key = if mouse_button_input.just_pressed(MouseButton::Left) { MouseButton::Left }
|
||||
else if mouse_button_input.just_pressed(MouseButton::Right) {MouseButton::Right}
|
||||
else {return};
|
||||
let entity = hovered_boxes.get_single().unwrap();
|
||||
if !opened_boxes.contains(entity) {
|
||||
match mouse_key {
|
||||
MouseButton::Left => {
|
||||
commands.entity(entity).insert(BoxToOpen);
|
||||
},
|
||||
MouseButton::Right => {
|
||||
commands.entity(entity).insert(BoxToMarkFlip);
|
||||
},
|
||||
_ => return
|
||||
};
|
||||
} else {
|
||||
let rel_box = related_boxes.get(entity).unwrap();
|
||||
let box_count = rel_box.nearby_mines_count(&mine_boxes);
|
||||
let rel_box_marked_count = rel_box.nearby_box_marked_count(&marked_boxes);
|
||||
let rel_box_unopened_count = rel_box.nearby_box_unopened_count(&opened_boxes);
|
||||
if rel_box_marked_count == box_count {
|
||||
for rel_box in rel_box.iter() {
|
||||
if let Some(e) = rel_box {
|
||||
commands.entity(e).insert(BoxToOpen);
|
||||
}
|
||||
}
|
||||
} else if rel_box_unopened_count == box_count {
|
||||
for rel_box in rel_box.iter() {
|
||||
if let Some(e) = rel_box {
|
||||
commands.entity(e).insert(BoxToMark);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("Open box");
|
||||
//if pointers.button != PointerButton::Primary {
|
||||
// return;
|
||||
//}
|
||||
// gizmos.circle_2d(Isometry2d::IDENTITY, 5., Color::WHITE);
|
||||
}
|
||||
|
||||
fn mouse_world_pos(
|
||||
@ -100,3 +478,7 @@ fn mouse_world_pos(
|
||||
);
|
||||
|
||||
}
|
||||
fn random_bool(probability: f64) -> bool {
|
||||
let mut rnd = rng();
|
||||
rnd.random::<f64>() < probability
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user