🎉 Initial commit

main
Pau Costa Ferrer 2023-11-01 13:05:38 +01:00
commit 4f87e79324
4 changed files with 2298 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

2068
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

9
Cargo.toml Normal file
View File

@ -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"

220
src/main.rs Normal file
View File

@ -0,0 +1,220 @@
use bracket_lib::prelude::*;
enum GameMode {
Menu,
Playing,
End,
}
const SCREEN_WIDTH : i32 = 80;
const SCREEN_HEIGHT : i32 = 50;
const FRAME_DURATION : f32 = 75.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 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_obstacle(&self, player: &Dragon) -> 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_below_gap || player_above_gap)
}
}
struct Dragon {
x: i32,
y: i32,
velocity: f32,
}
impl Dragon{
fn new(x: i32, y: i32)-> Self {
Dragon{
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 State{
mode: GameMode,
player: Dragon,
frame_time: f32,
score: i32,
obstacle: Obstacle,
}
impl State{
fn new()-> Self{
State {
mode: GameMode::Menu,
player: Dragon::new(5, 25),
frame_time: 0.0,
obstacle: Obstacle::new(SCREEN_WIDTH, 0),
score: 0,
}
}
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 flap");
ctx.print(0,1, &format!("Score: {}", self.score));
self.obstacle.render(ctx,self.player.x);
// if the player is over the obstacle, update
// score and create a new obstacle
if self.player.x > self.obstacle.x {
self.score += 1;
self.obstacle = Obstacle::new(
self.player.x + SCREEN_WIDTH, self.score
);
}
// End conditions
// Hit the floor:
if self.player.y > SCREEN_HEIGHT {
self.mode = GameMode::End;
}
// Hit an obstacle
if self.obstacle.hit_obstacle(&self.player){
self.mode = GameMode::End;
}
}
fn dead(&mut self, ctx: &mut BTerm){
//Print text to screen
ctx.cls();
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(9, "(Q) Quit Game");
// Handle user input
if let Some(key) = ctx.key {
match key {
VirtualKeyCode::P => self.restart(),
VirtualKeyCode::Q => ctx.quitting = true,
_ => {}
}
}
}
fn main_menu(&mut self, ctx: &mut BTerm){
// Print text to screen
ctx.cls();
ctx.print_centered(5, "Welcome to Flappy Dragon");
ctx.print_centered(8, "(P) Play Game");
ctx.print_centered(9, "(Q) Quit Game");
// Handle user input
if let Some(key) = ctx.key {
match key {
VirtualKeyCode::P => self.restart(),
VirtualKeyCode::Q => ctx.quitting = true,
_ => {}
}
}
}
fn restart(&mut self){
self.player = Dragon::new(5, 25);
self.frame_time = 0.0;
self.obstacle = Obstacle::new(SCREEN_WIDTH, 0);
self.score = 0;
self.mode = GameMode::Playing;
}
}
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),
}
}
}
fn main() -> BError {
println!("Hello, world!");
let context = BTermBuilder::simple80x50()
.with_title("Flappy Dragon")
.build()?;
main_loop(context, State::new())
}