Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2nd player #23

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Were you inspired to make your own terminal-based game? Open a PR to add it to t
* [Pong](https://github.com/basilkohler/rusty_pong)
* [TETRIS](https://github.com/madchicken/rust-tetris)
* [Columns](https://github.com/Rendez/rust_columns)
* [Snake](https://github.com/konstcode/snake)

## Contribution

Expand Down
4 changes: 4 additions & 0 deletions src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ pub fn new_frame() -> Frame {
pub trait Drawable {
fn draw(&self, frame: &mut Frame);
}

pub trait Reset {
fn reset(&mut self);
}
7 changes: 7 additions & 0 deletions src/invaders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
};
use rusty_time::Timer;
use std::{cmp::max, time::Duration};
use crate::frame::Reset;

pub struct Invader {
pub x: usize,
Expand Down Expand Up @@ -102,6 +103,12 @@ impl Default for Invaders {
}
}

impl Reset for Invaders {
fn reset(&mut self) {
*self = Invaders::new();
}
}

impl Drawable for Invaders {
fn draw(&self, frame: &mut Frame) {
for invader in self.army.iter() {
Expand Down
10 changes: 8 additions & 2 deletions src/level.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::frame::{Drawable, Frame};
use crate::frame::{Drawable, Frame, Reset};

const MAX_LEVEL: u8 = 3;

Expand All @@ -25,6 +25,12 @@ impl Default for Level {
}
}

impl Reset for Level {
fn reset(&mut self) {
*self = Level::default();
}
}

impl Drawable for Level {
fn draw(&self, frame: &mut Frame) {
// format our level string
Expand All @@ -33,7 +39,7 @@ impl Drawable for Level {
// iterate over all characters
for (i, c) in formatted.chars().enumerate() {
// put them in the first row
frame[i + 20][0] = c;
frame[i + 13][0] = c;
}
}
}
Expand Down
52 changes: 39 additions & 13 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ use std::{
};

use invaders::{
frame::{self, new_frame, Drawable, Frame},
frame::{new_frame, Drawable, Reset, Frame},
invaders::Invaders,
level::Level,
menu::Menu,
player::Player,
player::{Player, Player2Mode},
render,
score::Score,
};

fn render_screen(render_rx: Receiver<Frame>) {
let mut last_frame = frame::new_frame();
let mut last_frame = new_frame();
let mut stdout = io::stdout();
render::render(&mut stdout, &last_frame, &last_frame, true);
while let Ok(curr_frame) = render_rx.recv() {
Expand All @@ -32,10 +32,12 @@ fn render_screen(render_rx: Receiver<Frame>) {
}
}

fn reset_game(in_menu: &mut bool, player: &mut Player, invaders: &mut Invaders) {
fn reset_game(in_menu: &mut bool, player2_mode: &mut Player2Mode, to_reset: &mut Vec<&mut dyn Reset>) {
*in_menu = true;
*player = Player::new();
*invaders = Invaders::new();
*player2_mode = Player2Mode::Enabled(false);
for elem in to_reset {
elem.reset();
}
}

fn main() -> Result<(), Box<dyn Error>> {
Expand All @@ -58,13 +60,15 @@ fn main() -> Result<(), Box<dyn Error>> {
});

// Game loop
let mut player = Player::new();
let mut player = Player::new('A');
let mut player2 = Player::new('Q');
let mut instant = Instant::now();
let mut invaders = Invaders::new();
let mut score = Score::new();
let mut menu = Menu::new();
let mut in_menu = true;
let mut level = Level::new();
let mut player2_mode = Player2Mode::Enabled(false);

'gameloop: loop {
// Per-frame init
Expand All @@ -82,6 +86,10 @@ fn main() -> Result<(), Box<dyn Error>> {
KeyCode::Char(' ') | KeyCode::Enter => {
if menu.selection == 0 {
in_menu = false;
}
else if menu.selection == 1 {
in_menu = false;
player2_mode = Player2Mode::Enabled(true);
} else {
break 'gameloop;
}
Expand All @@ -107,29 +115,46 @@ fn main() -> Result<(), Box<dyn Error>> {
if player.shoot() {
audio.play("pew");
}
}
},
KeyCode::Char('a') => player2.move_left(),
KeyCode::Char('d') => player2.move_right(),
KeyCode::Char('w') => {
if player2.shoot() {
audio.play("pew");
}
},
KeyCode::Esc | KeyCode::Char('q') => {
audio.play("lose");
reset_game(&mut in_menu, &mut player, &mut invaders);
}
let mut to_reset: Vec<&mut dyn Reset> = vec![&mut player, &mut player2, &mut invaders, &mut score, &mut level];
reset_game(&mut in_menu, &mut player2_mode, &mut to_reset);
},
KeyCode::Char('e') => {
player2_mode = Player2Mode::Enabled(true);
},
_ => {}
}
}
}

// Updates
player.update(delta);
if player2_mode == Player2Mode::Enabled(true) { player2.update(delta); }

if invaders.update(delta) {
audio.play("move");
}
let hits: u16 = player.detect_hits(&mut invaders);
let mut hits: u16 = player.detect_hits(&mut invaders);
hits += player2.detect_hits(&mut invaders);
if hits > 0 {
audio.play("explode");
score.add_points(hits);
}
// Draw & render

let drawables: Vec<&dyn Drawable> = vec![&player, &invaders, &score, &level];
let mut drawables: Vec<&dyn Drawable> = vec![&player, &invaders, &score, &level, &player2_mode];
if player2_mode == Player2Mode::Enabled(true) {
drawables.push(&player2);
}
for drawable in drawables {
drawable.draw(&mut curr_frame);
}
Expand All @@ -145,7 +170,8 @@ fn main() -> Result<(), Box<dyn Error>> {
invaders = Invaders::new();
} else if invaders.reached_bottom() {
audio.play("lose");
reset_game(&mut in_menu, &mut player, &mut invaders);
let mut to_reset: Vec<&mut dyn Reset> = vec![&mut player, &mut player2, &mut invaders, &mut score, &mut level];
reset_game(&mut in_menu, &mut player2_mode, &mut to_reset);
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ pub struct Menu {
impl Menu {
pub fn new() -> Self {
Self {
options: vec![String::from("New game"), String::from("Exit")],
options: vec![String::from("New game"),
String::from("2 players"),
String::from("Exit")],
selection: 0,
}
}
Expand Down
35 changes: 31 additions & 4 deletions src/player.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
frame::{Drawable, Frame},
frame::{Drawable, Reset, Frame},
invaders::Invaders,
shot::Shot,
{NUM_COLS, NUM_ROWS},
Expand All @@ -10,14 +10,16 @@ pub struct Player {
x: usize,
y: usize,
shots: Vec<Shot>,
view: char,
}

impl Player {
pub fn new() -> Self {
pub fn new(view: char) -> Self {
Self {
x: NUM_COLS / 2,
y: NUM_ROWS - 1,
shots: Vec::new(),
view: view
}
}
pub fn move_left(&mut self) {
Expand Down Expand Up @@ -61,15 +63,40 @@ impl Player {

impl Default for Player {
fn default() -> Self {
Self::new()
Self::new('A')
}
}

impl Reset for Player {
fn reset(&mut self) {
*self = Player::new(self.view);
}
}

impl Drawable for Player {
fn draw(&self, frame: &mut Frame) {
frame[self.x][self.y] = 'A';
frame[self.x][self.y] = self.view;
for shot in self.shots.iter() {
shot.draw(frame);
}
}
}
#[derive(PartialEq, Debug)]
pub enum Player2Mode {
Enabled(bool),
}

impl Drawable for Player2Mode {
fn draw(&self, frame: &mut Frame) {
// format our player2 string
if *self == Player2Mode::Enabled(false) {
let formatted = format!("P2: PRESS E");

// iterate over all characters
for (i, c) in formatted.chars().enumerate() {
// put them in the first row
frame[i + 23][0] = c;
}
}
}
}
8 changes: 7 additions & 1 deletion src/score.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::frame::{Drawable, Frame};
use crate::frame::{Drawable, Frame, Reset};

#[derive(Default)]
pub struct Score {
Expand All @@ -15,6 +15,12 @@ impl Score {
}
}

impl Reset for Score {
fn reset(&mut self) {
*self = Score::default();
}
}

impl Drawable for Score {
fn draw(&self, frame: &mut Frame) {
// format our score string
Expand Down
Loading