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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
use crate::settings::Settings;
use crate::types::Positioned;
use crate::types::{BoundingBox, Dimensions, Position};
use std::io::{self, StdinLock, StdoutLock, Write};
use termion::input::Keys;
use termion::input::TermRead;
use termion::raw::RawTerminal;
use crate::display::{self, Viewport};
use crate::entities::Character;
use crate::types::command::Command;
type Stdout<'a> = RawTerminal<StdoutLock<'a>>;
/// The full state of a running Game
pub struct Game<'a> {
settings: Settings,
viewport: Viewport<Stdout<'a>>,
/// An iterator on keypresses from the user
keys: Keys<StdinLock<'a>>,
/// The player character
character: Character,
}
impl<'a> Game<'a> {
pub fn new(
settings: Settings,
stdout: RawTerminal<StdoutLock<'a>>,
stdin: StdinLock<'a>,
w: u16,
h: u16,
) -> Game<'a> {
Game {
settings: settings,
viewport: Viewport {
outer: BoundingBox::at_origin(Dimensions { w, h }),
inner: BoundingBox::at_origin(Dimensions {
w: w - 2,
h: h - 2,
}),
out: stdout,
},
keys: stdin.keys(),
character: Character::new(),
}
}
/// Returns true if there's a collision in the game at the given Position
fn collision_at(&self, pos: Position) -> bool {
!pos.within(self.viewport.inner)
}
fn draw_entities(&mut self) -> io::Result<()> {
self.viewport.draw(&self.character)
}
/// Run the game
pub fn run(mut self) -> io::Result<()> {
info!("Running game");
self.viewport.init()?;
self.draw_entities()?;
self.flush()?;
loop {
let mut old_position = None;
match Command::from_key(self.keys.next().unwrap().unwrap()) {
Some(Command::Quit) => {
info!("Quitting game due to user request");
break;
}
Some(Command::Move(direction)) => {
let new_pos = self.character.position + direction;
if !self.collision_at(new_pos) {
old_position = Some(self.character.position);
self.character.position = new_pos;
}
}
_ => (),
}
match old_position {
Some(old_pos) => {
self.viewport.clear(old_pos)?;
self.viewport.draw(&self.character)?;
}
None => ()
}
self.flush()?;
debug!("{:?}", self.character);
}
Ok(())
}
}
impl<'a> Drop for Game<'a> {
fn drop(&mut self) {
display::clear(self).unwrap_or(());
}
}
impl<'a> Write for Game<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.viewport.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.viewport.flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.viewport.write_all(buf)
}
}
impl<'a> Positioned for Game<'a> {
fn position(&self) -> Position {
Position { x: 0, y: 0 }
}
}
|