learn-wgpu/code/showcase/pong/src/system.rs

244 lines
7.7 KiB
Rust
Raw Normal View History

2020-05-26 00:33:53 +00:00
use crate::input;
2020-09-28 05:24:43 +00:00
use crate::state::{self, GameState};
2020-05-14 21:03:58 +00:00
use crate::util;
2020-05-26 00:33:53 +00:00
pub trait System {
#[allow(unused_variables)]
fn start(&mut self, state: &mut state::State) {}
fn update_state(
2020-09-28 05:24:43 +00:00
&self,
input: &input::Input,
state: &mut state::State,
2020-05-26 00:33:53 +00:00
events: &mut Vec<state::Event>,
);
2020-05-19 17:42:01 +00:00
}
2020-05-26 00:33:53 +00:00
pub struct VisibilitySystem;
impl System for VisibilitySystem {
fn update_state(
2020-09-28 05:24:43 +00:00
&self,
_input: &input::Input,
state: &mut state::State,
2020-05-26 00:33:53 +00:00
_events: &mut Vec<state::Event>,
) {
let gs = state.game_state;
2020-09-28 05:24:43 +00:00
let is_in_game = any!(
gs,
GameState::Serving,
GameState::Playing,
GameState::GameOver
);
2020-05-26 00:33:53 +00:00
state.ball.visible = is_in_game && gs != GameState::GameOver;
state.player1.visible = is_in_game;
state.player1_score.visible = is_in_game;
state.player2.visible = is_in_game;
state.player2_score.visible = is_in_game;
state.title_text.visible = gs == GameState::MainMenu;
state.play_button.visible = gs == GameState::MainMenu;
state.quit_button.visible = gs == GameState::MainMenu;
state.win_text.visible = gs == GameState::GameOver;
2020-05-19 17:42:01 +00:00
}
}
2020-05-26 00:33:53 +00:00
#[derive(Debug)]
pub struct MenuSystem;
2020-05-19 17:42:01 +00:00
impl System for MenuSystem {
fn start(&mut self, state: &mut state::State) {
state.player1.score = 0;
state.player2.score = 0;
2020-05-26 00:33:53 +00:00
state.player1.position.y = 0.0;
state.player2.position.y = 0.0;
2020-05-19 17:42:01 +00:00
state.play_button.focused = true;
2020-05-26 00:33:53 +00:00
state.quit_button.focused = false;
2020-05-19 17:42:01 +00:00
}
2020-05-26 00:33:53 +00:00
fn update_state(
2020-09-28 05:24:43 +00:00
&self,
2020-05-26 00:33:53 +00:00
input: &input::Input,
2020-09-28 05:24:43 +00:00
state: &mut state::State,
events: &mut Vec<state::Event>,
2020-05-26 00:33:53 +00:00
) {
if state.play_button.focused && input.ui_down_pressed() {
2020-05-21 20:07:02 +00:00
events.push(state::Event::FocusChanged);
2020-05-19 17:42:01 +00:00
state.play_button.focused = false;
state.quit_button.focused = true;
2020-05-26 00:33:53 +00:00
} else if state.quit_button.focused && input.ui_up_pressed() {
2020-05-21 20:07:02 +00:00
events.push(state::Event::FocusChanged);
2020-05-19 17:42:01 +00:00
state.quit_button.focused = false;
state.play_button.focused = true;
}
2020-05-26 00:33:53 +00:00
if state.play_button.focused && input.enter_pressed {
2020-05-21 20:07:02 +00:00
events.push(state::Event::ButtonPressed);
2020-05-19 17:42:01 +00:00
state.game_state = state::GameState::Serving;
2020-05-26 00:33:53 +00:00
} else if state.quit_button.focused && input.enter_pressed {
2020-05-21 20:07:02 +00:00
events.push(state::Event::ButtonPressed);
2020-05-19 17:42:01 +00:00
state.game_state = state::GameState::Quiting;
}
}
}
2020-05-26 00:33:53 +00:00
pub struct PlaySystem;
2020-05-19 17:42:01 +00:00
impl System for PlaySystem {
2020-05-26 00:33:53 +00:00
fn update_state(
2020-09-28 05:24:43 +00:00
&self,
2020-05-26 00:33:53 +00:00
input: &input::Input,
state: &mut state::State,
2020-09-28 05:24:43 +00:00
_events: &mut Vec<state::Event>,
2020-05-26 00:33:53 +00:00
) {
2020-05-19 17:42:01 +00:00
// move the players
2020-05-26 00:33:53 +00:00
if input.p1_up_pressed {
state.player1.position.y += util::PLAYER_SPEED;
2020-05-14 21:03:58 +00:00
}
2020-05-26 00:33:53 +00:00
if input.p1_down_pressed {
state.player1.position.y -= util::PLAYER_SPEED;
2020-05-14 21:03:58 +00:00
}
2020-05-26 00:33:53 +00:00
if input.p2_up_pressed {
state.player2.position.y += util::PLAYER_SPEED;
2020-05-14 21:03:58 +00:00
}
2020-05-26 00:33:53 +00:00
if input.p2_down_pressed {
state.player2.position.y -= util::PLAYER_SPEED;
2020-05-14 21:03:58 +00:00
}
// normalize players
2020-05-28 19:22:06 +00:00
if state.player1.position.y > 1.0 - state.player1.size.y * 0.5 {
state.player1.position.y = 1.0 - state.player1.size.y * 0.5;
} else if state.player1.position.y < state.player1.size.y * 0.5 - 1.0 {
state.player1.position.y = state.player1.size.y * 0.5 - 1.0;
2020-05-14 21:03:58 +00:00
}
2020-05-28 19:22:06 +00:00
if state.player2.position.y > 1.0 - state.player1.size.y * 0.5 {
state.player2.position.y = 1.0 - state.player1.size.y * 0.5;
} else if state.player2.position.y < state.player1.size.y * 0.5 - 1.0 {
state.player2.position.y = state.player1.size.y * 0.5 - 1.0;
2020-05-14 21:03:58 +00:00
}
2020-05-26 00:33:53 +00:00
if state.player1.score > 2 || state.player2.score > 2 {
state.game_state = state::GameState::GameOver;
}
}
}
pub struct BallSystem;
2020-05-28 19:22:06 +00:00
2020-05-26 00:33:53 +00:00
impl System for BallSystem {
fn update_state(
2020-09-28 05:24:43 +00:00
&self,
2020-05-26 00:33:53 +00:00
_input: &input::Input,
2020-09-28 05:24:43 +00:00
state: &mut state::State,
2020-05-26 00:33:53 +00:00
events: &mut Vec<state::Event>,
) {
// bounce the ball off the players
if state.player1.contains(&state.ball) {
events.push(state::Event::BallBounce(state.ball.position));
state.ball.position.x -= state.ball.velocity.x - state.player1.size.x;
state.ball.velocity = util::calc_ball_velocity(&state.ball, &state.player1);
} else if state.player2.contains(&state.ball) {
events.push(state::Event::BallBounce(state.ball.position));
state.ball.position.x -= state.ball.velocity.x + state.player2.size.x;
state.ball.velocity.x *= -state.player2.size.y;
state.ball.velocity = util::calc_ball_velocity(&state.ball, &state.player2);
}
2020-05-28 19:22:06 +00:00
2020-05-14 21:03:58 +00:00
state.ball.position += state.ball.velocity;
if state.ball.position.y > 1.0 {
2020-05-26 00:33:53 +00:00
events.push(state::Event::BallBounce(state.ball.position));
2020-05-14 21:03:58 +00:00
state.ball.position.y = 1.0;
state.ball.velocity.y *= -1.0;
2020-05-19 17:42:01 +00:00
} else if state.ball.position.y < -1.0 {
2020-05-26 00:33:53 +00:00
events.push(state::Event::BallBounce(state.ball.position));
2020-05-14 21:03:58 +00:00
state.ball.position.y = -1.0;
state.ball.velocity.y *= -1.0;
}
2020-05-19 17:42:01 +00:00
2020-05-14 21:03:58 +00:00
if state.ball.position.x > 1.0 {
2020-05-19 17:42:01 +00:00
state.player1.score += 1;
state.game_state = state::GameState::Serving;
2020-05-26 00:33:53 +00:00
events.push(state::Event::Score(0));
2020-05-19 17:42:01 +00:00
} else if state.ball.position.x < -1.0 {
state.player2.score += 1;
state.game_state = state::GameState::Serving;
2020-05-26 00:33:53 +00:00
events.push(state::Event::Score(1));
2020-05-14 21:03:58 +00:00
}
}
2020-05-19 17:42:01 +00:00
}
pub struct ServingSystem {
last_time: std::time::Instant,
}
impl ServingSystem {
pub fn new() -> Self {
Self {
last_time: std::time::Instant::now(),
}
}
}
impl System for ServingSystem {
fn start(&mut self, state: &mut state::State) {
self.last_time = std::time::Instant::now();
2020-05-26 00:33:53 +00:00
let direction = state.ball.position.x.signum();
2020-05-19 17:42:01 +00:00
state.ball.position = (0.0, 0.0).into();
2020-05-26 00:33:53 +00:00
state.ball.velocity = cgmath::Vector2::unit_x() * direction * -util::BALL_SPEED;
2020-05-19 17:42:01 +00:00
state.player1_score.text = format!("{}", state.player1.score);
state.player2_score.text = format!("{}", state.player2.score);
}
2020-05-26 00:33:53 +00:00
fn update_state(
&self,
_input: &input::Input,
2020-09-28 05:24:43 +00:00
state: &mut state::State,
2020-05-26 00:33:53 +00:00
_events: &mut Vec<state::Event>,
) {
2020-05-19 17:42:01 +00:00
let current_time = std::time::Instant::now();
let delta_time = current_time - self.last_time;
2020-05-26 00:33:53 +00:00
if delta_time.as_secs_f32() > 2.0 {
2020-05-19 17:42:01 +00:00
state.game_state = state::GameState::Playing;
}
}
}
pub struct GameOverSystem {
last_time: std::time::Instant,
}
impl GameOverSystem {
pub fn new() -> Self {
2020-09-28 05:24:43 +00:00
Self {
2020-05-19 17:42:01 +00:00
last_time: std::time::Instant::now(),
}
}
}
impl System for GameOverSystem {
fn start(&mut self, state: &mut state::State) {
self.last_time = std::time::Instant::now();
2020-05-28 19:22:06 +00:00
state.player1_score.text = format!("{}", state.player1.score);
state.player2_score.text = format!("{}", state.player2.score);
2020-09-28 05:24:43 +00:00
2020-05-19 17:42:01 +00:00
state.win_text.text = if state.player1.score > state.player2.score {
2020-05-28 19:22:06 +00:00
String::from("Player 1 wins!")
2020-05-19 17:42:01 +00:00
} else {
2020-05-28 19:22:06 +00:00
String::from("Player 2 wins!")
2020-05-19 17:42:01 +00:00
};
}
2020-09-28 05:24:43 +00:00
fn update_state(
&self,
2020-05-26 00:33:53 +00:00
_input: &input::Input,
state: &mut state::State,
_events: &mut Vec<state::Event>,
) {
2020-05-19 17:42:01 +00:00
let current_time = std::time::Instant::now();
let delta_time = current_time - self.last_time;
if delta_time.as_secs_f32() > 1.0 {
state.game_state = state::GameState::MainMenu;
}
}
2020-09-28 05:24:43 +00:00
}