#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum GameState { MainMenu, Serving, Playing, GameOver, Quiting, } pub struct State { pub ball: Ball, pub player1: Player, pub player2: Player, pub title_text: Text, pub play_button: Text, pub quit_button: Text, pub player1_score: Text, pub player2_score: Text, pub win_text: Text, pub game_state: GameState, } pub struct Ball { pub position: cgmath::Vector2, pub velocity: cgmath::Vector2, pub radius: f32, pub visible: bool, } #[derive(Debug)] pub struct Player { pub position: cgmath::Vector2, pub size: cgmath::Vector2, pub score: u32, pub visible: bool, } // I don't like giving state methods, but whatever impl Player { pub fn contains(&self, ball: &Ball) -> bool { let radii = self.size * 0.5; let min = self.position - radii; let max = self.position + radii; let b_radii = cgmath::Vector2 { x: ball.radius, y: ball.radius, }; let b_min = ball.position - b_radii; let b_max = ball.position + b_radii; min.x < b_max.x && max.x > b_min.x && min.y < b_max.y && max.y > b_min.y } } pub const UNBOUNDED_F32: f32 = std::f32::INFINITY; #[derive(Debug)] pub struct Text { pub position: cgmath::Vector2, pub bounds: cgmath::Vector2, pub color: cgmath::Vector4, pub text: String, pub size: f32, pub visible: bool, pub focused: bool, pub centered: bool, } impl Default for Text { fn default() -> Self { Self { position: (0.0, 0.0).into(), bounds: (UNBOUNDED_F32, UNBOUNDED_F32).into(), color: (1.0, 1.0, 1.0, 1.0).into(), text: String::new(), size: 16.0, visible: false, focused: false, centered: false, } } } #[derive(Debug, Copy, Clone)] pub enum Event { ButtonPressed, FocusChanged, BallBounce(cgmath::Vector2), Score(u32), } #[cfg(test)] mod test { use super::*; #[test] fn player_contains_ball() { let ball = Ball { position: (0.0, 0.0).into(), velocity: (0.0, 0.0).into(), radius: 1.0, visible: true, }; let p1 = Player { position: (0.0, -1.5).into(), size: (2.0, 2.0).into(), score: 0, visible: true, }; assert!(p1.contains(&ball)); } }