Convert to bin/lib architecture
This commit is contained in:
parent
d8cecfc282
commit
8725b3bc48
186
iced-tetris/src/lib.rs
Normal file
186
iced-tetris/src/lib.rs
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
use iced::widget::canvas::{self, Path, Stroke, Text};
|
||||
use iced::{
|
||||
executor, keyboard, time, Application, Color, Command, Element, Length, Point, Rectangle,
|
||||
Settings, Size, Subscription,
|
||||
};
|
||||
use tetris_logic::{BlockGrid, MoveDirection, Tetromino};
|
||||
*/
|
||||
|
||||
use iced::{
|
||||
widget::canvas::{self, Path, Stroke, Text},
|
||||
Color, Element, Length, Pixels, Point, Renderer, Size, Subscription, Task, Theme,
|
||||
};
|
||||
use tetris_logic::{BlockGrid, MoveDirection, Tetromino};
|
||||
|
||||
pub fn tetris_main() -> iced::Result {
|
||||
iced::application(Tetris::title, update, view)
|
||||
.subscription(subscription)
|
||||
.run_with(|| (Tetris::new(), Task::none()))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Message {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
Pause,
|
||||
Tick(chrono::DateTime<chrono::Local>),
|
||||
}
|
||||
|
||||
fn update(state: &mut Tetris, message: Message) {
|
||||
match message {
|
||||
Message::Pause => state.paused = !state.paused,
|
||||
Message::Tick(_time) => {
|
||||
if !state.paused {
|
||||
state.ticks += 1;
|
||||
}
|
||||
}
|
||||
Message::Up => {
|
||||
state.blocks.rotate_active_piece();
|
||||
}
|
||||
Message::Down => {
|
||||
state.blocks.move_active_piece(MoveDirection::HardDrop);
|
||||
}
|
||||
Message::Left => {
|
||||
state.blocks.move_active_piece(MoveDirection::Left);
|
||||
}
|
||||
Message::Right => {
|
||||
state.blocks.move_active_piece(MoveDirection::Right);
|
||||
}
|
||||
};
|
||||
if state.blocks.piece_currently_active() {
|
||||
if state.ticks % 10 == 0 && !state.paused {
|
||||
state.blocks.move_active_piece(MoveDirection::SoftDrop);
|
||||
}
|
||||
} else {
|
||||
let piece: Tetromino = rand::random();
|
||||
state.blocks.drop_piece(piece);
|
||||
}
|
||||
|
||||
let lines_removed = state.blocks.clear_pieces();
|
||||
state.lines_removed += lines_removed;
|
||||
}
|
||||
|
||||
fn subscription(_state: &Tetris) -> Subscription<Message> {
|
||||
let keyboard_subscription = iced::keyboard::on_key_press(|key, _modifiers| {
|
||||
use iced::keyboard::key::{Key, Named};
|
||||
match key {
|
||||
Key::Named(Named::ArrowUp) => Some(Message::Up),
|
||||
Key::Named(Named::ArrowDown) => Some(Message::Down),
|
||||
Key::Named(Named::ArrowLeft) => Some(Message::Left),
|
||||
Key::Named(Named::ArrowRight) => Some(Message::Right),
|
||||
Key::Named(Named::Space) => Some(Message::Pause),
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
|
||||
let time_subscription = iced::time::every(std::time::Duration::from_millis(50))
|
||||
.map(|_| Message::Tick(chrono::Local::now()));
|
||||
Subscription::batch([time_subscription, keyboard_subscription])
|
||||
}
|
||||
|
||||
fn view(state: &Tetris) -> Element<Message> {
|
||||
iced::widget::canvas(state)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
|
||||
struct Tetris {
|
||||
background_cache: canvas::Cache,
|
||||
blocks: BlockGrid,
|
||||
ticks: usize,
|
||||
paused: bool,
|
||||
lines_removed: u32,
|
||||
}
|
||||
|
||||
impl Tetris {
|
||||
fn title(&self) -> String {
|
||||
String::from("Tetris - Iced")
|
||||
}
|
||||
|
||||
fn new() -> Tetris {
|
||||
Tetris {
|
||||
background_cache: canvas::Cache::default(),
|
||||
blocks: BlockGrid::new(),
|
||||
ticks: 0,
|
||||
paused: false,
|
||||
lines_removed: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl canvas::Program<Message> for Tetris {
|
||||
type State = ();
|
||||
|
||||
fn draw(
|
||||
&self,
|
||||
_state: &Self::State,
|
||||
renderer: &Renderer,
|
||||
_theme: &Theme,
|
||||
bounds: iced::Rectangle,
|
||||
_cursor: iced::mouse::Cursor,
|
||||
) -> Vec<canvas::Geometry<Renderer>> {
|
||||
let game_width = bounds.width / 3.0;
|
||||
let block_length = game_width / 10.0;
|
||||
let center = bounds.center();
|
||||
let top_left = Point::new(center.x - game_width / 2.0, 0.0);
|
||||
|
||||
let background = self
|
||||
.background_cache
|
||||
.draw(renderer, bounds.size(), |frame| {
|
||||
let game_size = Size::new(block_length * 10.0, block_length * 20.0);
|
||||
let game_bg = Path::rectangle(top_left, game_size);
|
||||
frame.fill(&game_bg, Color::BLACK);
|
||||
});
|
||||
|
||||
let block_size = Size::new(block_length, block_length);
|
||||
let mut frame = canvas::Frame::new(renderer, bounds.size());
|
||||
|
||||
for (i, j, tetronimo) in self.blocks.iter() {
|
||||
let point = Point::new(
|
||||
i as f32 * block_length + top_left.x,
|
||||
j as f32 * block_length + top_left.y,
|
||||
);
|
||||
let block = Path::rectangle(point, block_size);
|
||||
let color = tetronimo.color();
|
||||
let fill_color = Color::from_rgb8(color.0, color.1, color.2);
|
||||
frame.fill(&block, fill_color);
|
||||
|
||||
let stroke_color = Color::from_rgb8(
|
||||
color.0.checked_sub(20).unwrap_or(0),
|
||||
color.1.checked_sub(20).unwrap_or(0),
|
||||
color.2.checked_sub(20).unwrap_or(0),
|
||||
);
|
||||
let stroke = Stroke::default().with_width(3.0).with_color(stroke_color);
|
||||
frame.stroke(&block, stroke);
|
||||
}
|
||||
|
||||
let text_color = Color::from_rgb8(255, 30, 30);
|
||||
let text_size = Pixels(32.0);
|
||||
let score = Text {
|
||||
content: format!("Lines removed: {}", self.lines_removed),
|
||||
position: Point::new(10.0, 30.0),
|
||||
size: text_size,
|
||||
color: text_color,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
frame.fill_text(score);
|
||||
|
||||
if self.paused {
|
||||
let paused = Text {
|
||||
content: "PAUSED".to_string(),
|
||||
position: Point::new(10.0, 60.0),
|
||||
color: text_color,
|
||||
size: text_size,
|
||||
..Default::default()
|
||||
};
|
||||
frame.fill_text(paused);
|
||||
}
|
||||
|
||||
vec![background, frame.into_geometry()]
|
||||
}
|
||||
}
|
@ -1,187 +1,3 @@
|
||||
/*
|
||||
use iced::widget::canvas::{self, Path, Stroke, Text};
|
||||
use iced::{
|
||||
executor, keyboard, time, Application, Color, Command, Element, Length, Point, Rectangle,
|
||||
Settings, Size, Subscription,
|
||||
};
|
||||
use tetris_logic::{BlockGrid, MoveDirection, Tetromino};
|
||||
*/
|
||||
|
||||
use iced::{
|
||||
widget::canvas::{self, Path, Stroke, Text},
|
||||
Color, Element, Length, Pixels, Point, Renderer, Size, Subscription, Task, Theme,
|
||||
};
|
||||
use tetris_logic::{BlockGrid, MoveDirection, Tetromino};
|
||||
|
||||
fn main() -> iced::Result {
|
||||
//Tetris::run(Settings::default())
|
||||
iced::application(Tetris::title, update, view)
|
||||
.subscription(subscription)
|
||||
.run_with(|| (Tetris::new(), Task::none()))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Message {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
Pause,
|
||||
Tick(chrono::DateTime<chrono::Local>),
|
||||
}
|
||||
|
||||
fn update(state: &mut Tetris, message: Message) {
|
||||
match message {
|
||||
Message::Pause => state.paused = !state.paused,
|
||||
Message::Tick(_time) => {
|
||||
if !state.paused {
|
||||
state.ticks += 1;
|
||||
}
|
||||
}
|
||||
Message::Up => {
|
||||
state.blocks.rotate_active_piece();
|
||||
}
|
||||
Message::Down => {
|
||||
state.blocks.move_active_piece(MoveDirection::HardDrop);
|
||||
}
|
||||
Message::Left => {
|
||||
state.blocks.move_active_piece(MoveDirection::Left);
|
||||
}
|
||||
Message::Right => {
|
||||
state.blocks.move_active_piece(MoveDirection::Right);
|
||||
}
|
||||
};
|
||||
if state.blocks.piece_currently_active() {
|
||||
if state.ticks % 10 == 0 && !state.paused {
|
||||
state.blocks.move_active_piece(MoveDirection::SoftDrop);
|
||||
}
|
||||
} else {
|
||||
let piece: Tetromino = rand::random();
|
||||
state.blocks.drop_piece(piece);
|
||||
}
|
||||
|
||||
let lines_removed = state.blocks.clear_pieces();
|
||||
state.lines_removed += lines_removed;
|
||||
}
|
||||
|
||||
fn subscription(_state: &Tetris) -> Subscription<Message> {
|
||||
let keyboard_subscription = iced::keyboard::on_key_press(|key, _modifiers| {
|
||||
use iced::keyboard::key::{Key, Named};
|
||||
match key {
|
||||
Key::Named(Named::ArrowUp) => Some(Message::Up),
|
||||
Key::Named(Named::ArrowDown) => Some(Message::Down),
|
||||
Key::Named(Named::ArrowLeft) => Some(Message::Left),
|
||||
Key::Named(Named::ArrowRight) => Some(Message::Right),
|
||||
Key::Named(Named::Space) => Some(Message::Pause),
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
|
||||
let time_subscription = iced::time::every(std::time::Duration::from_millis(50))
|
||||
.map(|_| Message::Tick(chrono::Local::now()));
|
||||
Subscription::batch([time_subscription, keyboard_subscription])
|
||||
}
|
||||
|
||||
fn view(state: &Tetris) -> Element<Message> {
|
||||
iced::widget::canvas(state)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
|
||||
struct Tetris {
|
||||
background_cache: canvas::Cache,
|
||||
blocks: BlockGrid,
|
||||
ticks: usize,
|
||||
paused: bool,
|
||||
lines_removed: u32,
|
||||
}
|
||||
|
||||
impl Tetris {
|
||||
fn title(&self) -> String {
|
||||
String::from("Tetris - Iced")
|
||||
}
|
||||
|
||||
fn new() -> Tetris {
|
||||
Tetris {
|
||||
background_cache: canvas::Cache::default(),
|
||||
blocks: BlockGrid::new(),
|
||||
ticks: 0,
|
||||
paused: false,
|
||||
lines_removed: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl canvas::Program<Message> for Tetris {
|
||||
type State = ();
|
||||
|
||||
fn draw(
|
||||
&self,
|
||||
_state: &Self::State,
|
||||
renderer: &Renderer,
|
||||
_theme: &Theme,
|
||||
bounds: iced::Rectangle,
|
||||
_cursor: iced::mouse::Cursor,
|
||||
) -> Vec<canvas::Geometry<Renderer>> {
|
||||
let game_width = bounds.width / 3.0;
|
||||
let block_length = game_width / 10.0;
|
||||
let center = bounds.center();
|
||||
let top_left = Point::new(center.x - game_width / 2.0, 0.0);
|
||||
|
||||
let background = self
|
||||
.background_cache
|
||||
.draw(renderer, bounds.size(), |frame| {
|
||||
let game_size = Size::new(block_length * 10.0, block_length * 20.0);
|
||||
let game_bg = Path::rectangle(top_left, game_size);
|
||||
frame.fill(&game_bg, Color::BLACK);
|
||||
});
|
||||
|
||||
let block_size = Size::new(block_length, block_length);
|
||||
let mut frame = canvas::Frame::new(renderer, bounds.size());
|
||||
|
||||
for (i, j, tetronimo) in self.blocks.iter() {
|
||||
let point = Point::new(
|
||||
i as f32 * block_length + top_left.x,
|
||||
j as f32 * block_length + top_left.y,
|
||||
);
|
||||
let block = Path::rectangle(point, block_size);
|
||||
let color = tetronimo.color();
|
||||
let fill_color = Color::from_rgb8(color.0, color.1, color.2);
|
||||
frame.fill(&block, fill_color);
|
||||
|
||||
let stroke_color = Color::from_rgb8(
|
||||
color.0.checked_sub(20).unwrap_or(0),
|
||||
color.1.checked_sub(20).unwrap_or(0),
|
||||
color.2.checked_sub(20).unwrap_or(0),
|
||||
);
|
||||
let stroke = Stroke::default().with_width(3.0).with_color(stroke_color);
|
||||
frame.stroke(&block, stroke);
|
||||
}
|
||||
|
||||
let text_color = Color::from_rgb8(255, 30, 30);
|
||||
let text_size = Pixels(32.0);
|
||||
let score = Text {
|
||||
content: format!("Lines removed: {}", self.lines_removed),
|
||||
position: Point::new(10.0, 30.0),
|
||||
size: text_size,
|
||||
color: text_color,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
frame.fill_text(score);
|
||||
|
||||
if self.paused {
|
||||
let paused = Text {
|
||||
content: "PAUSED".to_string(),
|
||||
position: Point::new(10.0, 60.0),
|
||||
color: text_color,
|
||||
size: text_size,
|
||||
..Default::default()
|
||||
};
|
||||
frame.fill_text(paused);
|
||||
}
|
||||
|
||||
vec![background, frame.into_geometry()]
|
||||
}
|
||||
iced_tetris::tetris_main()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user