a full game loop appears

main
Jordan Orelli 12 months ago
parent 042e7357fa
commit 2535799505

37
Cargo.lock generated

@ -2812,6 +2812,12 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]] [[package]]
name = "pretty-type-name" name = "pretty-type-name"
version = "1.0.1" version = "1.0.1"
@ -2858,6 +2864,36 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17fd96390ed3feda12e1dfe2645ed587e0bea749e319333f104a33ff62f77a0b" checksum = "17fd96390ed3feda12e1dfe2645ed587e0bea749e319333f104a33ff62f77a0b"
[[package]]
name = "rand"
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",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]] [[package]]
name = "range-alloc" name = "range-alloc"
version = "0.1.3" version = "0.1.3"
@ -2963,6 +2999,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bevy", "bevy",
"bevy-inspector-egui", "bevy-inspector-egui",
"rand",
"tracing", "tracing",
] ]

@ -17,4 +17,5 @@ edition = "2021"
[dependencies] [dependencies]
bevy = { version = "0.11.2", features = [ ] } bevy = { version = "0.11.2", features = [ ] }
bevy-inspector-egui = "0.19.0" bevy-inspector-egui = "0.19.0"
rand = "0.8.5"
tracing = "0.1.37" tracing = "0.1.37"

@ -4,6 +4,9 @@ use bevy::prelude::*;
#[derive(Event, Default, Debug)] #[derive(Event, Default, Debug)]
pub(crate) struct Play; pub(crate) struct Play;
#[derive(Event, Default, Debug)]
pub(crate) struct GameFinished;
#[derive(Event)] #[derive(Event)]
pub(crate) struct PlayerMove { pub(crate) struct PlayerMove {
throw: Throw, throw: Throw,
@ -14,5 +17,6 @@ pub(crate) struct Events {}
impl Plugin for Events { impl Plugin for Events {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_event::<Play>(); app.add_event::<Play>();
app.add_event::<GameFinished>();
} }
} }

@ -1,4 +1,5 @@
use bevy::prelude::*; use bevy::prelude::*;
use rand::Rng;
use tracing::info; use tracing::info;
use crate::{events::Events, play::Play, start_menu::StartMenu}; use crate::{events::Events, play::Play, start_menu::StartMenu};
@ -25,3 +26,36 @@ pub(crate) enum Throw {
Paper, Paper,
Scissors, Scissors,
} }
impl Throw {
pub fn random() -> Self {
let mut rng = rand::thread_rng();
match rng.gen_range(0..3) {
0 => Throw::Rock,
1 => Throw::Paper,
2 => Throw::Scissors,
_ => unreachable!(),
}
}
pub fn against(&self, other: &Self) -> Outcome {
match (self, other) {
(Throw::Rock, Throw::Rock)
| (Throw::Paper, Throw::Paper)
| (Throw::Scissors, Throw::Scissors) => Outcome::Tie,
(Throw::Rock, Throw::Scissors)
| (Throw::Paper, Throw::Rock)
| (Throw::Scissors, Throw::Paper) => Outcome::Win,
(Throw::Rock, Throw::Paper)
| (Throw::Paper, Throw::Scissors)
| (Throw::Scissors, Throw::Rock) => Outcome::Loss,
}
}
}
#[derive(Debug)]
pub(crate) enum Outcome {
Win,
Loss,
Tie,
}

@ -2,9 +2,11 @@ use crate::{events, game::Throw, ui};
use bevy::ecs::system::EntityCommand; use bevy::ecs::system::EntityCommand;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::text::DEFAULT_FONT_HANDLE; use bevy::text::DEFAULT_FONT_HANDLE;
use bevy::time::Stopwatch;
use std::time::Duration; use std::time::Duration;
#[derive(Component)]
struct PlayContainer;
#[derive(Debug)] #[derive(Debug)]
pub enum Phase { pub enum Phase {
BeforePlay, BeforePlay,
@ -28,6 +30,11 @@ impl Board {
p2_throw: None, p2_throw: None,
} }
} }
pub fn clear(&mut self) {
self.p1_throw = None;
self.p2_throw = None;
}
} }
pub struct Play {} pub struct Play {}
@ -42,7 +49,11 @@ struct Action {
throw: Throw, throw: Throw,
} }
fn advance_game_state(time: Res<Time>, mut board: ResMut<Board>) { fn advance_game_state(
time: Res<Time>,
mut board: ResMut<Board>,
mut finished: EventWriter<events::GameFinished>,
) {
// add some stuff here // add some stuff here
match &mut board.phase { match &mut board.phase {
Phase::BeforePlay => {} Phase::BeforePlay => {}
@ -50,7 +61,23 @@ fn advance_game_state(time: Res<Time>, mut board: ResMut<Board>) {
timer.tick(time.delta()); timer.tick(time.delta());
if timer.just_finished() { if timer.just_finished() {
info!("Countdown timer finished"); info!("Countdown timer finished");
if board.p1_throw.is_none() {
info!("Player panics and throws at random");
board.p1_throw = Some(Throw::random());
}
board.p2_throw = Some(Throw::random());
board.phase = Phase::Reveal(Timer::new(Duration::from_secs(3), TimerMode::Once)); board.phase = Phase::Reveal(Timer::new(Duration::from_secs(3), TimerMode::Once));
info!("Player threw: {throw:?}", throw = board.p1_throw);
info!("Computer threw: {throw:?}", throw = board.p2_throw);
info!(
"Outcome: {outcome:?}",
outcome = board
.p1_throw
.as_ref()
.unwrap()
.against(board.p2_throw.as_ref().unwrap())
);
} }
} }
Phase::Reveal(timer) => { Phase::Reveal(timer) => {
@ -58,6 +85,7 @@ fn advance_game_state(time: Res<Time>, mut board: ResMut<Board>) {
if timer.just_finished() { if timer.just_finished() {
info!("Reveal timer finished"); info!("Reveal timer finished");
board.phase = Phase::AfterPlay; board.phase = Phase::AfterPlay;
finished.send_default();
} }
} }
Phase::AfterPlay => {} Phase::AfterPlay => {}
@ -71,6 +99,10 @@ fn handle_actions(
for (interaction, action) in actions.iter() { for (interaction, action) in actions.iter() {
if matches!(interaction, Interaction::Pressed) { if matches!(interaction, Interaction::Pressed) {
info!("Clicked {throw:?}", throw = action.throw); info!("Clicked {throw:?}", throw = action.throw);
if !matches!(board.phase, Phase::Countdown(_)) {
info!("Ignoring player throw");
return;
}
if board.p1_throw.is_some() { if board.p1_throw.is_some() {
info!("Replacing existing throw"); info!("Replacing existing throw");
} }
@ -147,6 +179,20 @@ fn header() -> impl Bundle {
) )
} }
fn handle_game_finished(
mut events: EventReader<events::GameFinished>,
mut commands: Commands,
q: Query<Entity, With<PlayContainer>>,
) {
if events.is_empty() {
return;
}
events.clear();
for e in q.iter() {
commands.entity(e).despawn_recursive();
}
}
fn handle_play( fn handle_play(
mut events: EventReader<events::Play>, mut events: EventReader<events::Play>,
mut commands: Commands, mut commands: Commands,
@ -160,10 +206,12 @@ fn handle_play(
info!("play event {e:?}"); info!("play event {e:?}");
} }
board.phase = Phase::Countdown(Timer::new(Duration::from_millis(3000), TimerMode::Once)); board.phase = Phase::Countdown(Timer::new(Duration::from_millis(3000), TimerMode::Once));
board.clear();
info!("Starting countdown"); info!("Starting countdown");
let mut bg = commands.spawn(( let mut bg = commands.spawn((
Name::new("Play Container"), Name::new("Play Container"),
PlayContainer {},
NodeBundle { NodeBundle {
style: Style { style: Style {
display: Display::Flex, display: Display::Flex,
@ -235,7 +283,15 @@ fn handle_play(
impl Plugin for Play { impl Plugin for Play {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(Update, (handle_play, handle_actions, advance_game_state)); app.add_systems(
Update,
(
handle_play,
handle_actions,
advance_game_state,
handle_game_finished,
),
);
app.insert_resource(Board::new()); app.insert_resource(Board::new());
} }
} }

@ -138,11 +138,20 @@ impl EntityCommand for Label {
} }
} }
fn setup(mut commands: Commands) { fn handle_game_finished(mut events: EventReader<events::GameFinished>, mut commands: Commands) {
if events.is_empty() {
return;
}
events.clear();
info!("Game finished, reconstructing start menu");
spawn_start_menu(commands);
}
fn spawn_start_menu(mut commands: Commands) {
let red = Color::rgb(0.8, 0.2, 0.2); let red = Color::rgb(0.8, 0.2, 0.2);
let green = Color::rgb(0.2, 0.8, 0.2); let green = Color::rgb(0.2, 0.8, 0.2);
commands.spawn(Camera2dBundle::default());
commands commands
.spawn((Name::new("Start Menu"), MainMenu, column())) .spawn((Name::new("Start Menu"), MainMenu, column()))
.with_children(|menu| { .with_children(|menu| {
@ -180,10 +189,18 @@ fn setup(mut commands: Commands) {
}); });
} }
fn setup(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
spawn_start_menu(commands);
}
impl Plugin for StartMenu { impl Plugin for StartMenu {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_plugins(ui::Plugin {}); app.add_plugins(ui::Plugin {});
app.add_systems(Startup, setup); app.add_systems(Startup, setup);
app.add_systems(Update, (click_quit, click_play, handle_play)); app.add_systems(
Update,
(click_quit, click_play, handle_play, handle_game_finished),
);
} }
} }

Loading…
Cancel
Save