diff --git a/Cargo.lock b/Cargo.lock index ca86924..d1d6abd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "adler32" version = "1.0.3" diff --git a/Cargo.toml b/Cargo.toml index ce130ed..34b31fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,4 @@ path = "src/app/game.rs" [[bin]] name = "rusty-editor" -path = "src/app/editor.rs" +path = "src/app/editor/main.rs" diff --git a/assets/fonts/sansation.ttf b/assets/fonts/sansation.ttf new file mode 100644 index 0000000..d85fbc8 Binary files /dev/null and b/assets/fonts/sansation.ttf differ diff --git a/assets/levels/level1.lvl b/assets/levels/level1.lvl index a4e4e0a..e579fd8 100644 Binary files a/assets/levels/level1.lvl and b/assets/levels/level1.lvl differ diff --git a/src/app/editor.rs b/src/app/editor.rs deleted file mode 100644 index 0a942ce..0000000 --- a/src/app/editor.rs +++ /dev/null @@ -1,103 +0,0 @@ -use clap::{App, crate_version}; - -use sfml::system::Vector2; -use sfml::window::{Event, Key}; -use sfml::window::mouse::Button; -use sfml::graphics::{RectangleShape, RenderTarget, Transformable, Color, Shape}; - -use rusty::engine::renderer::Renderer; -use rusty::engine::map::{CollisionTile, Map}; -use rusty::engine::texture::SPRITE_SIZE_I32; - -fn main() { - let _ = App::new("Rusty Editor") - .version(crate_version!()) - .get_matches(); - - let mut renderer = Renderer::new(800, 600, false); - - let mut running = true; - - let mut map = Map::new(50, 50);//;Map::load("./assets/levels/level2.lvl").unwrap(); - - loop { - let top_panel_size = Vector2::new(renderer.window().size().x as f32, 50.0); - let left_panel_size = Vector2::new(100.0, renderer.window().size().y as f32 - top_panel_size.y); - - // Manage the events - while let Some(event) = renderer.poll_event() { - match event { - // Quit the game if window is closed - Event::Closed => running = false, - - // Quit the game if escape is pressed - Event::KeyPressed { - code: Key::Escape, .. - } => running = false, - - // A click on the screen - Event::MouseButtonPressed { - button: Button::Left, x, y, - } => { - if x as f32 >= left_panel_size.x && y as f32 >= top_panel_size.y { - let x = ((x - left_panel_size.x as i32) / SPRITE_SIZE_I32) as usize; - let y = ((y - top_panel_size.y as i32) / SPRITE_SIZE_I32) as usize; - - if let Some(tile) = map.collision_tile(y, x) { - if tile.is_empty() { - map.set_tile(y, x, CollisionTile::full()); - } else { - map.set_tile(y, x, CollisionTile::empty()); - } - } - } - }, - - _ => (), - } - } - - // Do the rendering - renderer.clear(); - - // Show the top panel - let mut top_panel = RectangleShape::with_size(top_panel_size); - top_panel.set_fill_color(&Color::rgb(255, 0, 0)); - renderer.window_mut().draw(&top_panel); - - // Show the left panel - let mut left_panel = RectangleShape::with_size(left_panel_size); - left_panel.set_position((0.0, top_panel_size.y)); - left_panel.set_fill_color(&Color::rgb(0, 255, 0)); - renderer.window_mut().draw(&left_panel); - - // Show the map - for i in 0 .. map.rows() { - for j in 0 .. map.cols() { - let tile = map.at(i, j); - if tile.graphic.is_visible() { - renderer.translate_and_draw(&tile, (left_panel_size.x, top_panel_size.y)); - } - } - } - - // Draw the border of the map - let mut border = RectangleShape::new(); - border.set_size((( - map.cols() * SPRITE_SIZE_I32 as usize) as f32, - (map.rows() * SPRITE_SIZE_I32 as usize) as f32 - )); - border.set_position((left_panel_size.x, top_panel_size.y)); - border.set_fill_color(&Color::rgba(0, 0, 0, 0)); - border.set_outline_color(&Color::rgb(0, 0, 0)); - border.set_outline_thickness(2.0); - renderer.window_mut().draw(&border); - - // Display and manage the frame rate - renderer.display(); - - if !running { - break; - } - } -} diff --git a/src/app/editor/main.rs b/src/app/editor/main.rs new file mode 100644 index 0000000..84481f4 --- /dev/null +++ b/src/app/editor/main.rs @@ -0,0 +1,11 @@ +use clap::{App, crate_version}; + +use rusty::app::editor::Editor; + +fn main() { + let _ = App::new("Rusty Editor") + .version(crate_version!()) + .get_matches(); + + Editor::new().run(); +} diff --git a/src/app/editor/mod.rs b/src/app/editor/mod.rs new file mode 100644 index 0000000..cb7f713 --- /dev/null +++ b/src/app/editor/mod.rs @@ -0,0 +1,230 @@ +use sfml::system::Vector2; +use sfml::window::{Event, Key, mouse::Button as MouseButton}; +use sfml::graphics::{Color, RectangleShape, RenderTarget, Transformable, Shape}; + +use crate::engine::renderer::Renderer; +use crate::engine::map::{CollisionTile, Map}; +use crate::engine::texture::SPRITE_SIZE_I32; +use crate::engine::font::Font; +use crate::Result; + +/// An action caused by a button. +#[derive(Copy, Clone)] +pub enum Action { + /// Saves the level. + Save, +} + +/// A button that can be clicked. +pub struct Button { + /// The label of the button. + pub label: String, + + /// The position of the button. + pub position: Vector2, + + /// The size of the button. + pub size: Vector2, + + /// The action of the button. + action: Action, +} + +impl Button { + /// Creates a new button. + pub fn new(label: &str, action: Action, x: f32, y: f32, w: f32, h: f32) -> Button { + Button { + action, + label: label.to_owned(), + position: Vector2::new(x, y), + size: Vector2::new(w, h), + } + } + + /// Returns the shape of the button. + pub fn shape(&self) -> RectangleShape { + let mut shape = RectangleShape::new(); + shape.set_position(self.position + 0.1 * self.size); + shape.set_size(self.size - 0.2 * self.size); + shape.set_fill_color(&Color::rgb(255, 255, 255)); + shape + } + + /// Draws the button on the renderer. + pub fn render_on(&self, renderer: &mut Renderer) { + renderer.window_mut().draw(&self.shape()); + renderer.draw_text( + &self.label, + Font::Sansation, + self.size.y as u32 / 2, + &Color::rgb(0, 0, 0) + ); + } + + /// Returns true if the coordinates fall inside the shape of the button. + pub fn contains(&self, x: f32, y: f32) -> bool { + let shape = self.shape(); + x > shape.position().x && x < shape.position().x + shape.size().x && + y > shape.position().y && y < shape.position().y + shape.size().y + } +} + +/// Represents a level editor. +pub struct Editor { + /// The renderer used by the editor. + renderer: Renderer, + + /// The map being currently edited. + map: Map, + + /// Indicates whether the editor is running or not. + running: bool, + + /// The size of the left panel. + left_panel_size: Vector2, + + /// The size of the top panel. + top_panel_size: Vector2, + + /// The buttons of the menu bar. + menu_bar: Vec