summaryrefslogtreecommitdiffstats
path: root/src/game.rs
blob: 03586385560305d34f93f1f5c884acf4b298d959 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use std::io::{Read, Write};

use termion::{
    cursor::HideCursor, event::Key, input::TermRead, raw::IntoRawMode, screen::AlternateScreen,
};

use crate::{
    entity::{Controllable, Player},
    error::Result,
    physics::Vector,
    structure::Building,
    Render, Velocity,
};

#[derive(Debug)]
pub(crate) enum Command {
    Quit,
    UpdatePlayer,
}

#[derive(Debug, Default)]
pub struct Game {
    pub player: Player,
    pub structures: Vec<Building>,
}

impl Game {
    pub fn run_loop<R: Read, W: IntoRawMode>(&mut self, reader: R, writer: W) -> Result<()> {
        let mut screen = AlternateScreen::from(HideCursor::from(writer).into_raw_mode().unwrap());
        self.write_screen(&mut screen)?;

        for key in reader.keys() {
            match self.handle_input(key?) {
                Some(Command::Quit) => break,
                Some(Command::UpdatePlayer) => &mut self.update()?,
                None => continue,
            };
            self.write_screen(&mut screen)?;
        }

        write!(screen, "{}", termion::cursor::Show).map_err(From::from)
    }

    fn write_screen(&self, writer: &mut impl Write) -> Result<()> {
        write!(writer, "{}", termion::clear::All)?;

        self.player.render(writer)?;

        for entity in &self.structures {
            entity.render(writer)?;
        }

        writer.flush().map_err(From::from)
    }

    fn handle_input(&mut self, key: Key) -> Option<Command> {
        match key {
            Key::Char('q') => Some(Command::Quit),
            _ => self.player.handle_input(key),
        }
    }

    fn update(&mut self) -> Result<()> {
        self.player.tick_time()?;
        self.player.set_velocity(Vector::default())
    }
}

#[cfg(test)]
mod tests {
    use std::io::stdout;

    use crate::{structure::Building, Game, Position};

    #[test]
    fn run_game() {
        let stdin = "q".as_bytes();
        let stdout = stdout();

        let mut game = Game::default();

        if let Err(err) = game.run_loop(stdin, stdout) {
            eprintln!("{}", err)
        }
    }

    #[test]
    fn move_player() {
        let stdin = "sssdddq".as_bytes();
        let stdout = stdout();

        let mut game = Game::default();

        if let Err(err) = game.run_loop(stdin, stdout) {
            eprintln!("{}", err)
        }
    }
}