From aff03114849c57de48332a77a2158479444af62b Mon Sep 17 00:00:00 2001 From: dani <> Date: Wed, 9 Aug 2023 14:04:55 +0000 Subject: [PATCH] layer system for map edit --- Cargo.toml | 5 +- examples/basic/gfx.gif | Bin 27777 -> 28446 bytes examples/basic/main.rs | 3 +- src/gsa.rs | 19 +++ src/gsa_render_to_screen.rs | 4 +- src/lib.rs | 2 + src/main.rs | 2 + src/mapedit.rs | 254 +++++++++++++++++++++++++----------- src/maps.rs | 10 ++ src/run.rs | 10 +- src/tilemap.rs | 26 ++++ 11 files changed, 253 insertions(+), 82 deletions(-) create mode 100644 src/maps.rs create mode 100644 src/tilemap.rs diff --git a/Cargo.toml b/Cargo.toml index 22e3440..d5af3a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ keywords = ["gamedev"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -glam = "0.24.0" +glam = {version = "0.24.0", features = ["serde"]} ascii = "1.1.0" gilrs = "0.10.2" winit = "0.28.6" @@ -22,7 +22,8 @@ gif = "0.12.0" clap = {version = "4.3.8", features = ["derive", "cargo"]} dunce = "1.0.4" path-slash = "0.2.1" -serde = "1.0.181" +serde = {version = "1.0.181", features = ["derive"]} +postcard = {version = "1.0.6", features = ["alloc"]} [profile.release-dani] inherits = "release" diff --git a/examples/basic/gfx.gif b/examples/basic/gfx.gif index 3bb85d3b61c03b8a354672153e1e691e85274128..47b5ae877a4f49a266c1bfde579bca5ec2426845 100644 GIT binary patch delta 11977 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 diff --git a/examples/basic/main.rs b/examples/basic/main.rs index d302b57..d2f7f04 100644 --- a/examples/basic/main.rs +++ b/examples/basic/main.rs @@ -8,6 +8,7 @@ fn init(gsa: &mut Gsa) -> Game { gsa.sprites[1].tile = 0x0200; gsa.bgs[0].tiles[1][1] = 0x0300; gsa.bgs[1].half_tile = true; + gsa.load_map(1337); gsa.write_string(1, IVec2::ONE, "Hello world nyaa~"); Game {} } @@ -15,7 +16,7 @@ fn init(gsa: &mut Gsa) -> Game { fn update(_game: &mut Game, gsa: &mut Gsa) { gsa.sprites[0].pos.x = (gsa.sprites[0].pos.x + 1) % 300; gsa.sprites[1].pos += gsa.input_dir(); - gsa.bgs[1].scroll.x += 1; + //gsa.bgs[1].scroll.x += 1; if gsa.button_pressed(FACE_DOWN) { gsa.sprites[1].tile += 1; } diff --git a/src/gsa.rs b/src/gsa.rs index 055c66b..6daf297 100644 --- a/src/gsa.rs +++ b/src/gsa.rs @@ -1,4 +1,5 @@ use crate::background::Background; +use crate::maps::Maps; use crate::rgb::Rgb; use crate::sprite::Sprite; use crate::{ @@ -27,6 +28,7 @@ pub struct Gsa { pub(crate) pressed: Buttons, pub(crate) released: Buttons, pub(crate) down: Buttons, + pub(crate) maps: Maps, } impl Gsa { @@ -64,6 +66,23 @@ impl Gsa { } } + /// Loads tilemap into backgrounds + pub fn load_map(&mut self, map: u16) { + for (i, map) in self.maps.maps[&map].iter().enumerate() { + self.bgs[i].size = map.size; + for y in 0..map.size.y as usize { + for x in 0..map.size.x as usize { + self.bgs[i].tiles[x][y] = map.data[x + y * map.size.x as usize] + } + } + } + } + + /// Does a tilemap with this id exist? + pub fn map_exists(&mut self, map: u16) -> bool { + self.maps.maps.contains_key(&map) + } + /// Checks if any of given buttons currently held down pub fn button_down(&self, button: Buttons) -> bool { self.down & button != 0 diff --git a/src/gsa_render_to_screen.rs b/src/gsa_render_to_screen.rs index c550225..9a79a00 100644 --- a/src/gsa_render_to_screen.rs +++ b/src/gsa_render_to_screen.rs @@ -1,8 +1,8 @@ use std::usize; use crate::{ - Background, Gsa, Rgb, BACKGROUND_MAX_SIZE, EMPTY_TILE, HALF_TILE_SIZE, MAX_BACKGROUNDS, - SCREEN_HEIGHT, SCREEN_WIDTH, TILESET_SIZE, TILE_SIZE, TRANSPARENT, + Background, Gsa, Rgb, EMPTY_TILE, HALF_TILE_SIZE, MAX_BACKGROUNDS, TILESET_SIZE, TILE_SIZE, + TRANSPARENT, }; use glam::IVec2; use softbuffer::Buffer; diff --git a/src/lib.rs b/src/lib.rs index b4ba70c..ab0784a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,9 +43,11 @@ mod background; mod buttons; mod gsa; mod gsa_render_to_screen; +mod maps; mod rgb; mod run; mod sprite; +mod tilemap; mod tileset; pub use crate::background::*; diff --git a/src/main.rs b/src/main.rs index 25c933f..4777a3a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,9 +3,11 @@ mod buttons; mod gsa; mod gsa_render_to_screen; mod mapedit; +mod maps; mod rgb; mod run; mod sprite; +mod tilemap; mod tileset; //todo: figure out how to not repeat all the lib.rs stuff :( diff --git a/src/mapedit.rs b/src/mapedit.rs index bf28220..3d1b373 100644 --- a/src/mapedit.rs +++ b/src/mapedit.rs @@ -4,22 +4,31 @@ use std::num::NonZeroU32; use crate::gsa::Gsa; use crate::gsa_render_to_screen::render_to_screen; use crate::gsa_render_to_screen::render_to_window; +use crate::maps::Maps; use crate::sprite::Sprite; +use crate::tilemap::Tilemap; use crate::tileset::*; use crate::*; use clap::crate_version; use glam::IVec2; use winit::{ dpi::LogicalSize, - event::{Event, KeyboardInput, VirtualKeyCode, WindowEvent}, + event::{Event, VirtualKeyCode, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, }; const SPR_CURSOR: usize = 0x01; -const TILE_CURSOR: u16 = 0x7308; -const TILE_MARKER: u16 = 0x7309; -const TILE_BG: u16 = 0x730a; +const TILE_CURSOR: u16 = 0x7110; +const TILE_MARKER: u16 = 0x7210; +//const TILE_BG: u16 = 0x730a; + +const BUT_SAVE: usize = 0; +const BUT_LAYER1: usize = 2; +const BUT_LAYER2: usize = 3; +const BUT_LAYER3: usize = 4; +const BUT_LAYERS: usize = 5; +const BUT_EXIT: usize = 7; struct Surface<'a> { pub data: &'a mut [u8], @@ -40,12 +49,40 @@ impl<'a> Surface<'a> { } } +enum State { + Edit, + SelectTile, +} + +fn update_layer_state(gsa: &mut Gsa, gsa2: &mut Gsa, layer: usize, all: bool) { + gsa2.bgs[2].tiles[0][BUT_LAYER1] = if layer == 0 {0x7111} else {0x7011}; + gsa2.bgs[2].tiles[0][BUT_LAYER2] = if layer == 1 {0x7112} else {0x7012}; + gsa2.bgs[2].tiles[0][BUT_LAYER3] = if layer == 2 {0x7113} else {0x7013}; + gsa2.bgs[2].tiles[0][BUT_LAYERS] = if all {0x7114} else {0x7014}; + if all { + gsa.bgs[0].active = true; + gsa.bgs[1].active = true; + gsa.bgs[2].active = true; + } else { + gsa.bgs[0].active = layer == 0; + gsa.bgs[1].active = layer == 1; + gsa.bgs[2].active = layer == 2; + } +} + pub(crate) fn run_mapedit() { println!("running map edit"); let tileset_path = "examples/basic/gfx.gif"; let (tileset, palette) = load_tileset(&fs::read(tileset_path).unwrap()); + let maps_path = "examples/basic/maps.dat"; + let maps = if Path::new(maps_path).exists() { + postcard::from_bytes(&fs::read(maps_path).unwrap()).unwrap() + } else { + Maps::default() + }; + let mut gsa = Gsa { sprites: [Sprite::default(); MAX_SPRITES], palette, @@ -54,15 +91,25 @@ pub(crate) fn run_mapedit() { pressed: 0, released: 0, down: 0, + maps, }; gsa.reset_bgs(); gsa.reset_sprites(); + + if gsa.map_exists(1337) { + gsa.load_map(1337); + } + for i in 0..3 { - gsa.bgs[i].scroll = IVec2 { x: -16, y: 0 }; + gsa.bgs[i].scroll = IVec2 { + x: -16 - 32, + y: -32, + }; } gsa.sprites[SPR_CURSOR].tile = TILE_CURSOR; + gsa.sprites[SPR_CURSOR].priority = 3; let mut gsa2 = Gsa { sprites: [Sprite::default(); MAX_SPRITES], palette, @@ -71,11 +118,15 @@ pub(crate) fn run_mapedit() { pressed: 0, released: 0, down: 0, + maps: Maps::default(), }; gsa2.reset_bgs(); gsa2.reset_sprites(); for i in 0..2 { - gsa2.bgs[i].scroll = IVec2 { x: -16, y: 0 }; + gsa2.bgs[i].scroll = IVec2 { + x: -16 - 32, + y: -32, + }; } for y in 0..TILESET_SIZE { @@ -89,10 +140,11 @@ pub(crate) fn run_mapedit() { gsa2.bgs[2].size = IVec2 { x: 120, y: 68 }; //enough to cover 4k monitors? <_< for y in 0..BACKGROUND_MAX_SIZE { - gsa2.bgs[2].tiles[0][y] = 0x7408; + gsa2.bgs[2].tiles[0][y] = 0x7010; } - gsa2.bgs[2].tiles[0][0] = 0x7409; - gsa2.bgs[2].tiles[0][2] = 0x740a; + gsa2.bgs[2].tiles[0][BUT_SAVE] = 0x7211; + // layer buttons set up later + gsa2.bgs[2].tiles[0][BUT_EXIT] = 0x7212; let event_loop = EventLoop::new(); let size = LogicalSize::new(1280, 720); @@ -116,6 +168,10 @@ pub(crate) fn run_mapedit() { let mut right_down = false; let mut selected_tile = IVec2::ZERO; gsa2.bgs[1].tiles[0][0] = TILE_MARKER; + let mut state = State::Edit; + let mut current_layer = 0usize; + let mut all_layers = true; + update_layer_state(&mut gsa, &mut gsa2, current_layer, all_layers); event_loop.run(move |event, _, control_flow| { let mouse_pos = &mut mouse_pos; let tile_pos = &mut tile_pos; @@ -124,6 +180,9 @@ pub(crate) fn run_mapedit() { let middle_down = &mut middle_down; let right_down = &mut right_down; let selected_tile = &mut selected_tile; + let state = &mut state; + let current_layer = &mut current_layer; + let all_layers = &mut all_layers; match event { Event::WindowEvent { event, .. } => match event { @@ -143,6 +202,7 @@ pub(crate) fn run_mapedit() { gsa2.bgs[1].active = true; gsa.sprites[SPR_CURSOR].tile = EMPTY_TILE; gsa2.sprites[SPR_CURSOR].tile = TILE_CURSOR; + *state = State::SelectTile; } (winit::event::ElementState::Released, VirtualKeyCode::LShift) => { gsa.bgs[0].active = true; @@ -152,13 +212,46 @@ pub(crate) fn run_mapedit() { gsa2.bgs[1].active = false; gsa.sprites[SPR_CURSOR].tile = TILE_CURSOR; gsa2.sprites[SPR_CURSOR].tile = EMPTY_TILE; + *state = State::Edit; } _ => {} } } WindowEvent::MouseInput { state, button, .. } => match (state, button) { (winit::event::ElementState::Pressed, winit::event::MouseButton::Left) => { - *left_down = true; + if mouse_pos.x < 16 { + match (mouse_pos.y / 16) as usize { + BUT_SAVE => { + println!("saving"); + gsa.maps.maps.insert(1337, [Tilemap::from_bg(&gsa.bgs[0]), Tilemap::from_bg(&gsa.bgs[1]), Tilemap::from_bg(&gsa.bgs[2])]); + fs::write( + maps_path, + postcard::to_allocvec(&gsa.maps).unwrap(), + ) + .unwrap(); + } + BUT_LAYER1 => { + *current_layer = 0; + } + BUT_LAYER2 => { + *current_layer = 1; + } + BUT_LAYER3 => { + *current_layer = 2; + } + BUT_LAYERS => { + *all_layers = !*all_layers; + } + BUT_EXIT => { + println!("exit"); + *control_flow = ControlFlow::Exit; + } + _ => {} + } + update_layer_state(&mut gsa, &mut gsa2, *current_layer, *all_layers); + } else { + *left_down = true; + } } (winit::event::ElementState::Released, winit::event::MouseButton::Left) => { *left_down = false; @@ -184,16 +277,20 @@ pub(crate) fn run_mapedit() { }; let delta = new_pos - *mouse_pos; if *middle_down { - if gsa.bgs[0].active { - // normal mode - gsa.bgs[0].scroll -= delta; - gsa.bgs[1].scroll -= delta; - gsa.bgs[2].scroll -= delta; - } else { - // tile select mode - gsa2.bgs[0].scroll -= delta; - gsa2.bgs[1].scroll -= delta; - //gsa2.bgs[2].scroll -= delta; + match *state { + State::Edit => { + // normal mode + gsa.bgs[0].scroll -= delta; + gsa.bgs[1].scroll -= delta; + gsa.bgs[2].scroll -= delta; + } + State::SelectTile => { + // tile select mode + gsa2.bgs[0].scroll -= delta; + gsa2.bgs[1].scroll -= delta; + //gsa2.bgs[2].scroll -= delta; + } + _ => {} } } *mouse_pos = new_pos; @@ -214,42 +311,44 @@ pub(crate) fn run_mapedit() { }, Event::MainEventsCleared => { - if gsa.bgs[0].active { - // normal mode - if *left_down { - if tile_pos.x >= 0 - && tile_pos.y >= 0 - && tile_pos.x < BACKGROUND_MAX_SIZE as i32 - && tile_pos.y < BACKGROUND_MAX_SIZE as i32 - { - let tile = (selected_tile.x + (selected_tile.y << 8)) as u16; - gsa.bgs[0].tiles[tile_pos.x as usize][tile_pos.y as usize] = tile; - } - } else if *right_down { - if tile_pos.x >= 0 - && tile_pos.y >= 0 - && tile_pos.x < BACKGROUND_MAX_SIZE as i32 - && tile_pos.y < BACKGROUND_MAX_SIZE as i32 - { - gsa.bgs[0].tiles[tile_pos.x as usize][tile_pos.y as usize] = EMPTY_TILE; + match *state { + State::Edit => { + if *left_down { + if tile_pos.x >= 0 + && tile_pos.y >= 0 + && tile_pos.x < BACKGROUND_MAX_SIZE as i32 + && tile_pos.y < BACKGROUND_MAX_SIZE as i32 + { + let tile = (selected_tile.x + (selected_tile.y << 8)) as u16; + gsa.bgs[*current_layer].tiles[tile_pos.x as usize][tile_pos.y as usize] = tile; + } + } else if *right_down { + if tile_pos.x >= 0 + && tile_pos.y >= 0 + && tile_pos.x < BACKGROUND_MAX_SIZE as i32 + && tile_pos.y < BACKGROUND_MAX_SIZE as i32 + { + gsa.bgs[*current_layer].tiles[tile_pos.x as usize][tile_pos.y as usize] = + EMPTY_TILE; + } } } - } else { - // tile select mode - if *left_down { - if tile_pos2.x >= 0 - && tile_pos2.y >= 0 - && tile_pos2.x < BACKGROUND_MAX_SIZE as i32 - && tile_pos2.y < BACKGROUND_MAX_SIZE as i32 - { - gsa2.bgs[1].tiles[selected_tile.x as usize][selected_tile.y as usize] = - EMPTY_TILE; - *selected_tile = *tile_pos2; - gsa2.bgs[1].tiles[selected_tile.x as usize][selected_tile.y as usize] = - TILE_MARKER; + State::SelectTile => { + if *left_down { + if tile_pos2.x >= 0 + && tile_pos2.y >= 0 + && tile_pos2.x < BACKGROUND_MAX_SIZE as i32 + && tile_pos2.y < BACKGROUND_MAX_SIZE as i32 + { + gsa2.bgs[1].tiles[selected_tile.x as usize] + [selected_tile.y as usize] = EMPTY_TILE; + *selected_tile = *tile_pos2; + gsa2.bgs[1].tiles[selected_tile.x as usize] + [selected_tile.y as usize] = TILE_MARKER; + } } } - } + }; // render let size = window.inner_size(); @@ -272,31 +371,34 @@ pub(crate) fn run_mapedit() { data: &mut screen_buffer, size: screen_size, }; - if gsa.bgs[0].active { - let xs = -gsa.bgs[0].scroll.x - 1; - let ys = -gsa.bgs[0].scroll.y - 1; - let xe = xs + gsa.bgs[0].size.x * TILE_SIZE as i32 + 1; - let ye = ys + gsa.bgs[0].size.y * TILE_SIZE as i32 + 1; - if xs >= 16 && xs < screen_size.x { - let starty = (ys + 1).max(0); - let len = ye.min(screen_size.y) - starty; - screen.draw_vline(IVec2 { x: xs, y: starty }, len, 0xfc); - } - if xe >= 16 && xe < screen_size.x { - let starty = (ys + 1).max(0); - let len = ye.min(screen_size.y) - starty; - screen.draw_vline(IVec2 { x: xe, y: starty }, len, 0xfc); - } - if ys >= 0 && ys < screen_size.y { - let startx = (xs + 1).max(16); - let len = xe.min(screen_size.x) - startx; - screen.draw_hline(IVec2 { x: startx, y: ys }, len, 0xfc); - } - if ye >= 0 && ye < screen_size.y { - let startx = (xs + 1).max(16); - let len = xe.min(screen_size.x) - startx; - screen.draw_hline(IVec2 { x: startx, y: ye }, len, 0xfc); + match *state { + State::Edit => { + let xs = -gsa.bgs[0].scroll.x - 1; + let ys = -gsa.bgs[0].scroll.y - 1; + let xe = xs + gsa.bgs[0].size.x * TILE_SIZE as i32 + 1; + let ye = ys + gsa.bgs[0].size.y * TILE_SIZE as i32 + 1; + if xs >= 16 && xs < screen_size.x { + let starty = (ys + 1).max(0); + let len = ye.min(screen_size.y) - starty; + screen.draw_vline(IVec2 { x: xs, y: starty }, len, 0xfc); + } + if xe >= 16 && xe < screen_size.x { + let starty = (ys + 1).max(0); + let len = ye.min(screen_size.y) - starty; + screen.draw_vline(IVec2 { x: xe, y: starty }, len, 0xfc); + } + if ys >= 0 && ys < screen_size.y { + let startx = (xs + 1).max(16); + let len = xe.min(screen_size.x) - startx; + screen.draw_hline(IVec2 { x: startx, y: ys }, len, 0xfc); + } + if ye >= 0 && ye < screen_size.y { + let startx = (xs + 1).max(16); + let len = xe.min(screen_size.x) - startx; + screen.draw_hline(IVec2 { x: startx, y: ye }, len, 0xfc); + } } + _ => {} } render_to_window( diff --git a/src/maps.rs b/src/maps.rs new file mode 100644 index 0000000..71e8112 --- /dev/null +++ b/src/maps.rs @@ -0,0 +1,10 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use crate::tilemap::Tilemap; + +#[derive(Default, Deserialize, Serialize)] +pub(crate) struct Maps { + pub(crate) maps: HashMap, +} diff --git a/src/run.rs b/src/run.rs index 33464b1..3ac66dc 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,5 +1,6 @@ use crate::buttons::{button_from_gilrs, button_from_scancode}; use crate::gsa_render_to_screen::{render_to_screen, render_to_window}; +use crate::maps::Maps; use crate::tileset::load_tileset; use crate::{ Buttons, Gsa, Sprite, FONT_BOLD, MAX_SPRITES, SCREEN_HEIGHT, SCREEN_WIDTH, TRANSPARENT, @@ -27,7 +28,12 @@ use winit::window::WindowBuilder; macro_rules! run { ($init: ident, $update: ident) => { fn main() { - run($init, $update, include_bytes!("gfx.gif")); + run( + $init, + $update, + include_bytes!("gfx.gif"), + include_bytes!("maps.dat"), + ); } }; } @@ -37,6 +43,7 @@ pub fn run( init_fn: fn(gsa: &mut Gsa) -> TGame, update_fn: fn(game: &mut TGame, gsa: &mut Gsa), image_data: &[u8], + maps_data: &[u8], ) { let (tileset, palette) = load_tileset(image_data); @@ -48,6 +55,7 @@ pub fn run( pressed: 0, released: 0, down: 0, + maps: postcard::from_bytes(maps_data).unwrap(), }; gsa.reset_bgs(); diff --git a/src/tilemap.rs b/src/tilemap.rs new file mode 100644 index 0000000..705b33d --- /dev/null +++ b/src/tilemap.rs @@ -0,0 +1,26 @@ +use glam::IVec2; +use serde::{Deserialize, Serialize}; + +use crate::Background; + +#[derive(Serialize, Deserialize)] +pub(crate) struct Tilemap { + pub(crate) data: Vec, + pub(crate) size: IVec2, +} + +impl Tilemap { + pub(crate) fn from_bg(bg: &Background) -> Self { + let mut data = vec![0u16; (bg.size.x * bg.size.y) as usize]; + for y in 0..bg.size.y as usize { + for x in 0..bg.size.x as usize { + data[x + y * bg.size.x as usize] = bg.tiles[x][y]; + } + } + + Self { + data, + size: bg.size, + } + } +}