Finish project from first half of the book
This commit is contained in:
		
							
								
								
									
										118
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								src/main.rs
									
									
									
									
									
								
							| @@ -1,7 +1,15 @@ | |||||||
| use bracket_lib::prelude::*; | use bracket_lib::prelude::*; | ||||||
|  |  | ||||||
|  | const SCREEN_WIDTH: i32 = 80; | ||||||
|  | const SCREEN_HEIGHT: i32 = 50; | ||||||
|  | const FRAME_DURATION: f32 = 75.0; | ||||||
|  |  | ||||||
| struct State { | struct State { | ||||||
|  |     player: Player, | ||||||
|  |     frame_time: f32, | ||||||
|  |     obstacle: Obstacle, | ||||||
|     mode: GameMode, |     mode: GameMode, | ||||||
|  |     score: i32, | ||||||
| } | } | ||||||
|  |  | ||||||
| struct Player { | struct Player { | ||||||
| @@ -10,19 +18,120 @@ struct Player { | |||||||
|     velocity: f32, |     velocity: f32, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl Player { | ||||||
|  |     fn new(x: i32, y: i32) -> Self { | ||||||
|  |         Player { | ||||||
|  |             x, | ||||||
|  |             y, | ||||||
|  |             velocity: 0.0, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn render(&mut self, ctx: &mut BTerm) { | ||||||
|  |         ctx.set(0, self.y, YELLOW, BLACK, to_cp437('@')) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn gravity_and_move(&mut self) { | ||||||
|  |         if self.velocity < 2.0 { | ||||||
|  |             self.velocity += 0.2; | ||||||
|  |         } | ||||||
|  |         self.y += self.velocity as i32; | ||||||
|  |         self.x += 1; | ||||||
|  |         if self.y < 0 { | ||||||
|  |             self.y = 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn flap(&mut self) { | ||||||
|  |         self.velocity = -2.0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct Obstacle { | ||||||
|  |     x: i32, | ||||||
|  |     gap_y: i32, | ||||||
|  |     size: i32, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Obstacle { | ||||||
|  |     fn new(x: i32, score: i32) -> Self { | ||||||
|  |         let mut random = RandomNumberGenerator::new(); | ||||||
|  |         Obstacle { | ||||||
|  |             x, | ||||||
|  |             gap_y: random.range(10, 40), | ||||||
|  |             size: i32::max(2, 20 - score), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn render(&mut self, ctx: &mut BTerm, player_x: i32) { | ||||||
|  |         let screen_x = self.x - player_x; | ||||||
|  |         let half_size = self.size / 2; | ||||||
|  |  | ||||||
|  |         // Draw the top half of the obstacle | ||||||
|  |         for y in 0..self.gap_y - half_size { | ||||||
|  |             ctx.set(screen_x, y, RED, BLACK, to_cp437('|')); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Draw the lower half of the obstacle | ||||||
|  |         for y in self.gap_y + half_size..SCREEN_HEIGHT { | ||||||
|  |             ctx.set(screen_x, y, RED, BLACK, to_cp437('|')); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn hit_obstacle(&self, player: &Player) -> bool { | ||||||
|  |         let half_size = self.size / 2; | ||||||
|  |         let does_x_match = player.x == self.x; | ||||||
|  |         let player_above_gap = player.y < self.gap_y - half_size; | ||||||
|  |         let player_below_gap = player.y > self.gap_y + half_size; | ||||||
|  |  | ||||||
|  |         does_x_match && (player_above_gap || player_below_gap) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl State { | impl State { | ||||||
|     fn new() -> State { |     fn new() -> State { | ||||||
|         State { |         State { | ||||||
|  |             player: Player::new(5, 25), | ||||||
|  |             frame_time: 0.0, | ||||||
|  |             obstacle: Obstacle::new(SCREEN_WIDTH, 0), | ||||||
|             mode: GameMode::Menu, |             mode: GameMode::Menu, | ||||||
|  |             score: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn play(&mut self, ctx: &mut BTerm) { |     fn play(&mut self, ctx: &mut BTerm) { | ||||||
|         self.mode = GameMode::End; |         ctx.cls_bg(NAVY); | ||||||
|  |         self.frame_time += ctx.frame_time_ms; | ||||||
|  |         if self.frame_time > FRAME_DURATION { | ||||||
|  |             self.frame_time = 0.0; | ||||||
|  |             self.player.gravity_and_move(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if let Some(VirtualKeyCode::Space) = ctx.key { | ||||||
|  |             self.player.flap(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         self.player.render(ctx); | ||||||
|  |         ctx.print(0, 0, "Press SPACE to flap."); | ||||||
|  |         ctx.print(0, 1, &format!("Score: {}", self.score)); | ||||||
|  |  | ||||||
|  |         self.obstacle.render(ctx, self.player.x); | ||||||
|  |         if self.player.x > self.obstacle.x { | ||||||
|  |             self.score += 1; | ||||||
|  |             self.obstacle = Obstacle::new(self.player.x + SCREEN_WIDTH, self.score); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if self.player.y > SCREEN_HEIGHT || self.obstacle.hit_obstacle(&self.player) { | ||||||
|  |             self.mode = GameMode::End; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn restart(&mut self) { |     fn restart(&mut self) { | ||||||
|  |         self.player = Player::new(5, 25); | ||||||
|  |  | ||||||
|  |         self.frame_time = 0.0; | ||||||
|         self.mode = GameMode::Playing; |         self.mode = GameMode::Playing; | ||||||
|  |         self.score = 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn main_menu(&mut self, ctx: &mut BTerm) { |     fn main_menu(&mut self, ctx: &mut BTerm) { | ||||||
| @@ -44,6 +153,7 @@ impl State { | |||||||
|         ctx.cls(); |         ctx.cls(); | ||||||
|  |  | ||||||
|         ctx.print_centered(5, "You are dead!"); |         ctx.print_centered(5, "You are dead!"); | ||||||
|  |         ctx.print_centered(6, &format!("You earned {} points", self.score)); | ||||||
|         ctx.print_centered(8, "(P) Play Game"); |         ctx.print_centered(8, "(P) Play Game"); | ||||||
|         ctx.print_centered(9, "(Q) Quit Game"); |         ctx.print_centered(9, "(Q) Quit Game"); | ||||||
|  |  | ||||||
| @@ -57,6 +167,12 @@ impl State { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl Default for State { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self::new() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| enum GameMode { | enum GameMode { | ||||||
|     Menu, |     Menu, | ||||||
|     Playing, |     Playing, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user