flappy dragons
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "flappy"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bracket-lib = "~0.8.1"
|
||||
@@ -0,0 +1,196 @@
|
||||
use bracket_lib::prelude::*;
|
||||
|
||||
const SCREEN_WIDTH: i32 = 80;
|
||||
const SCREEN_HEIGHT: i32 = 50;
|
||||
const FRAME_DURATION: f32 = 75.0;
|
||||
|
||||
enum GameMode {
|
||||
Menu,
|
||||
Playing,
|
||||
End,
|
||||
}
|
||||
|
||||
struct State {
|
||||
mode: GameMode,
|
||||
player: Player,
|
||||
frame_time: f32,
|
||||
score: i32,
|
||||
obstacle: Obstacle,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn new() -> Self {
|
||||
State {
|
||||
mode: GameMode::Menu,
|
||||
frame_time: 0.0,
|
||||
player: Player::new(5, 25),
|
||||
score: 0,
|
||||
obstacle: Obstacle::new(SCREEN_WIDTH, 0),
|
||||
}
|
||||
}
|
||||
|
||||
fn dead(&mut self, ctx: &mut BTerm) {
|
||||
ctx.cls();
|
||||
ctx.print_centered(8, "You are dead !!");
|
||||
ctx.print_centered(9, &format!("You passed {} obstacles", self.score));
|
||||
ctx.print_centered(11, "(P) Play again");
|
||||
ctx.print_centered(13, "(Q) Quit");
|
||||
|
||||
if let Some(key) = ctx.key {
|
||||
match key {
|
||||
VirtualKeyCode::P => self.restart(),
|
||||
VirtualKeyCode::Q => ctx.quitting = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn play(&mut self, ctx: &mut BTerm) {
|
||||
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 fly");
|
||||
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_player(&self.player) {
|
||||
self.mode = GameMode::End;
|
||||
}
|
||||
}
|
||||
|
||||
fn restart(&mut self) {
|
||||
self.player = Player::new(5, 25);
|
||||
self.frame_time = 0.0;
|
||||
self.mode = GameMode::Playing;
|
||||
self.score = 0;
|
||||
self.obstacle = Obstacle::new(SCREEN_WIDTH, 0);
|
||||
}
|
||||
|
||||
fn main_menu(&mut self, ctx: &mut BTerm) {
|
||||
ctx.cls();
|
||||
ctx.print_centered(8, "Welcome to Flappy Dragons !");
|
||||
ctx.print_centered(10, "(P) Play");
|
||||
ctx.print_centered(12, "(Q) Quit");
|
||||
|
||||
if let Some(key) = ctx.key {
|
||||
match key {
|
||||
VirtualKeyCode::P => self.restart(),
|
||||
VirtualKeyCode::Q => ctx.quitting = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GameState for State {
|
||||
fn tick(&mut self, ctx: &mut BTerm) {
|
||||
match self.mode {
|
||||
GameMode::Menu => self.main_menu(ctx),
|
||||
GameMode::End => self.dead(ctx),
|
||||
GameMode::Playing => self.play(ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Player {
|
||||
x: i32,
|
||||
y: i32,
|
||||
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,
|
||||
gap_size: i32,
|
||||
}
|
||||
|
||||
impl Obstacle {
|
||||
fn new(x: i32, score: i32) -> Self {
|
||||
let mut random = RandomNumberGenerator::new();
|
||||
|
||||
Obstacle {
|
||||
x,
|
||||
gap_y: random.range(10, 40),
|
||||
gap_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.gap_size / 2;
|
||||
|
||||
// Top half of the obstacle
|
||||
for y in 0..self.gap_y - half_size {
|
||||
ctx.set(screen_x, y, RED, BLACK, to_cp437('|'))
|
||||
}
|
||||
|
||||
// Bottom 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_player(&mut self, player: &Player) -> bool {
|
||||
let half_size = self.gap_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)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> BError {
|
||||
let ctx = BTermBuilder::simple80x50()
|
||||
.with_title("Flappy Dragon")
|
||||
.build()?;
|
||||
|
||||
main_loop(ctx, State::new())
|
||||
}
|
||||
Reference in New Issue
Block a user