layer system for map edit

This commit is contained in:
dani 2023-08-09 14:04:55 +00:00
parent 8f78bbdca1
commit aff0311484
11 changed files with 253 additions and 82 deletions

View File

@ -13,7 +13,7 @@ keywords = ["gamedev"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
glam = "0.24.0" glam = {version = "0.24.0", features = ["serde"]}
ascii = "1.1.0" ascii = "1.1.0"
gilrs = "0.10.2" gilrs = "0.10.2"
winit = "0.28.6" winit = "0.28.6"
@ -22,7 +22,8 @@ gif = "0.12.0"
clap = {version = "4.3.8", features = ["derive", "cargo"]} clap = {version = "4.3.8", features = ["derive", "cargo"]}
dunce = "1.0.4" dunce = "1.0.4"
path-slash = "0.2.1" 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] [profile.release-dani]
inherits = "release" inherits = "release"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -8,6 +8,7 @@ fn init(gsa: &mut Gsa) -> Game {
gsa.sprites[1].tile = 0x0200; gsa.sprites[1].tile = 0x0200;
gsa.bgs[0].tiles[1][1] = 0x0300; gsa.bgs[0].tiles[1][1] = 0x0300;
gsa.bgs[1].half_tile = true; gsa.bgs[1].half_tile = true;
gsa.load_map(1337);
gsa.write_string(1, IVec2::ONE, "Hello world nyaa~"); gsa.write_string(1, IVec2::ONE, "Hello world nyaa~");
Game {} Game {}
} }
@ -15,7 +16,7 @@ fn init(gsa: &mut Gsa) -> Game {
fn update(_game: &mut Game, gsa: &mut Gsa) { fn update(_game: &mut Game, gsa: &mut Gsa) {
gsa.sprites[0].pos.x = (gsa.sprites[0].pos.x + 1) % 300; gsa.sprites[0].pos.x = (gsa.sprites[0].pos.x + 1) % 300;
gsa.sprites[1].pos += gsa.input_dir(); 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) { if gsa.button_pressed(FACE_DOWN) {
gsa.sprites[1].tile += 1; gsa.sprites[1].tile += 1;
} }

View File

@ -1,4 +1,5 @@
use crate::background::Background; use crate::background::Background;
use crate::maps::Maps;
use crate::rgb::Rgb; use crate::rgb::Rgb;
use crate::sprite::Sprite; use crate::sprite::Sprite;
use crate::{ use crate::{
@ -27,6 +28,7 @@ pub struct Gsa {
pub(crate) pressed: Buttons, pub(crate) pressed: Buttons,
pub(crate) released: Buttons, pub(crate) released: Buttons,
pub(crate) down: Buttons, pub(crate) down: Buttons,
pub(crate) maps: Maps,
} }
impl Gsa { 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 /// Checks if any of given buttons currently held down
pub fn button_down(&self, button: Buttons) -> bool { pub fn button_down(&self, button: Buttons) -> bool {
self.down & button != 0 self.down & button != 0

View File

@ -1,8 +1,8 @@
use std::usize; use std::usize;
use crate::{ use crate::{
Background, Gsa, Rgb, BACKGROUND_MAX_SIZE, EMPTY_TILE, HALF_TILE_SIZE, MAX_BACKGROUNDS, Background, Gsa, Rgb, EMPTY_TILE, HALF_TILE_SIZE, MAX_BACKGROUNDS, TILESET_SIZE, TILE_SIZE,
SCREEN_HEIGHT, SCREEN_WIDTH, TILESET_SIZE, TILE_SIZE, TRANSPARENT, TRANSPARENT,
}; };
use glam::IVec2; use glam::IVec2;
use softbuffer::Buffer; use softbuffer::Buffer;

View File

@ -43,9 +43,11 @@ mod background;
mod buttons; mod buttons;
mod gsa; mod gsa;
mod gsa_render_to_screen; mod gsa_render_to_screen;
mod maps;
mod rgb; mod rgb;
mod run; mod run;
mod sprite; mod sprite;
mod tilemap;
mod tileset; mod tileset;
pub use crate::background::*; pub use crate::background::*;

View File

@ -3,9 +3,11 @@ mod buttons;
mod gsa; mod gsa;
mod gsa_render_to_screen; mod gsa_render_to_screen;
mod mapedit; mod mapedit;
mod maps;
mod rgb; mod rgb;
mod run; mod run;
mod sprite; mod sprite;
mod tilemap;
mod tileset; mod tileset;
//todo: figure out how to not repeat all the lib.rs stuff :( //todo: figure out how to not repeat all the lib.rs stuff :(

View File

@ -4,22 +4,31 @@ use std::num::NonZeroU32;
use crate::gsa::Gsa; use crate::gsa::Gsa;
use crate::gsa_render_to_screen::render_to_screen; use crate::gsa_render_to_screen::render_to_screen;
use crate::gsa_render_to_screen::render_to_window; use crate::gsa_render_to_screen::render_to_window;
use crate::maps::Maps;
use crate::sprite::Sprite; use crate::sprite::Sprite;
use crate::tilemap::Tilemap;
use crate::tileset::*; use crate::tileset::*;
use crate::*; use crate::*;
use clap::crate_version; use clap::crate_version;
use glam::IVec2; use glam::IVec2;
use winit::{ use winit::{
dpi::LogicalSize, dpi::LogicalSize,
event::{Event, KeyboardInput, VirtualKeyCode, WindowEvent}, event::{Event, VirtualKeyCode, WindowEvent},
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
window::WindowBuilder, window::WindowBuilder,
}; };
const SPR_CURSOR: usize = 0x01; const SPR_CURSOR: usize = 0x01;
const TILE_CURSOR: u16 = 0x7308; const TILE_CURSOR: u16 = 0x7110;
const TILE_MARKER: u16 = 0x7309; const TILE_MARKER: u16 = 0x7210;
const TILE_BG: u16 = 0x730a; //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> { struct Surface<'a> {
pub data: &'a mut [u8], 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() { pub(crate) fn run_mapedit() {
println!("running map edit"); println!("running map edit");
let tileset_path = "examples/basic/gfx.gif"; let tileset_path = "examples/basic/gfx.gif";
let (tileset, palette) = load_tileset(&fs::read(tileset_path).unwrap()); 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 { let mut gsa = Gsa {
sprites: [Sprite::default(); MAX_SPRITES], sprites: [Sprite::default(); MAX_SPRITES],
palette, palette,
@ -54,15 +91,25 @@ pub(crate) fn run_mapedit() {
pressed: 0, pressed: 0,
released: 0, released: 0,
down: 0, down: 0,
maps,
}; };
gsa.reset_bgs(); gsa.reset_bgs();
gsa.reset_sprites(); gsa.reset_sprites();
if gsa.map_exists(1337) {
gsa.load_map(1337);
}
for i in 0..3 { 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].tile = TILE_CURSOR;
gsa.sprites[SPR_CURSOR].priority = 3;
let mut gsa2 = Gsa { let mut gsa2 = Gsa {
sprites: [Sprite::default(); MAX_SPRITES], sprites: [Sprite::default(); MAX_SPRITES],
palette, palette,
@ -71,11 +118,15 @@ pub(crate) fn run_mapedit() {
pressed: 0, pressed: 0,
released: 0, released: 0,
down: 0, down: 0,
maps: Maps::default(),
}; };
gsa2.reset_bgs(); gsa2.reset_bgs();
gsa2.reset_sprites(); gsa2.reset_sprites();
for i in 0..2 { 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 { 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? <_< gsa2.bgs[2].size = IVec2 { x: 120, y: 68 }; //enough to cover 4k monitors? <_<
for y in 0..BACKGROUND_MAX_SIZE { 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][BUT_SAVE] = 0x7211;
gsa2.bgs[2].tiles[0][2] = 0x740a; // layer buttons set up later
gsa2.bgs[2].tiles[0][BUT_EXIT] = 0x7212;
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
let size = LogicalSize::new(1280, 720); let size = LogicalSize::new(1280, 720);
@ -116,6 +168,10 @@ pub(crate) fn run_mapedit() {
let mut right_down = false; let mut right_down = false;
let mut selected_tile = IVec2::ZERO; let mut selected_tile = IVec2::ZERO;
gsa2.bgs[1].tiles[0][0] = TILE_MARKER; 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| { event_loop.run(move |event, _, control_flow| {
let mouse_pos = &mut mouse_pos; let mouse_pos = &mut mouse_pos;
let tile_pos = &mut tile_pos; let tile_pos = &mut tile_pos;
@ -124,6 +180,9 @@ pub(crate) fn run_mapedit() {
let middle_down = &mut middle_down; let middle_down = &mut middle_down;
let right_down = &mut right_down; let right_down = &mut right_down;
let selected_tile = &mut selected_tile; let selected_tile = &mut selected_tile;
let state = &mut state;
let current_layer = &mut current_layer;
let all_layers = &mut all_layers;
match event { match event {
Event::WindowEvent { event, .. } => match event { Event::WindowEvent { event, .. } => match event {
@ -143,6 +202,7 @@ pub(crate) fn run_mapedit() {
gsa2.bgs[1].active = true; gsa2.bgs[1].active = true;
gsa.sprites[SPR_CURSOR].tile = EMPTY_TILE; gsa.sprites[SPR_CURSOR].tile = EMPTY_TILE;
gsa2.sprites[SPR_CURSOR].tile = TILE_CURSOR; gsa2.sprites[SPR_CURSOR].tile = TILE_CURSOR;
*state = State::SelectTile;
} }
(winit::event::ElementState::Released, VirtualKeyCode::LShift) => { (winit::event::ElementState::Released, VirtualKeyCode::LShift) => {
gsa.bgs[0].active = true; gsa.bgs[0].active = true;
@ -152,14 +212,47 @@ pub(crate) fn run_mapedit() {
gsa2.bgs[1].active = false; gsa2.bgs[1].active = false;
gsa.sprites[SPR_CURSOR].tile = TILE_CURSOR; gsa.sprites[SPR_CURSOR].tile = TILE_CURSOR;
gsa2.sprites[SPR_CURSOR].tile = EMPTY_TILE; gsa2.sprites[SPR_CURSOR].tile = EMPTY_TILE;
*state = State::Edit;
} }
_ => {} _ => {}
} }
} }
WindowEvent::MouseInput { state, button, .. } => match (state, button) { WindowEvent::MouseInput { state, button, .. } => match (state, button) {
(winit::event::ElementState::Pressed, winit::event::MouseButton::Left) => { (winit::event::ElementState::Pressed, winit::event::MouseButton::Left) => {
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; *left_down = true;
} }
}
(winit::event::ElementState::Released, winit::event::MouseButton::Left) => { (winit::event::ElementState::Released, winit::event::MouseButton::Left) => {
*left_down = false; *left_down = false;
} }
@ -184,17 +277,21 @@ pub(crate) fn run_mapedit() {
}; };
let delta = new_pos - *mouse_pos; let delta = new_pos - *mouse_pos;
if *middle_down { if *middle_down {
if gsa.bgs[0].active { match *state {
State::Edit => {
// normal mode // normal mode
gsa.bgs[0].scroll -= delta; gsa.bgs[0].scroll -= delta;
gsa.bgs[1].scroll -= delta; gsa.bgs[1].scroll -= delta;
gsa.bgs[2].scroll -= delta; gsa.bgs[2].scroll -= delta;
} else { }
State::SelectTile => {
// tile select mode // tile select mode
gsa2.bgs[0].scroll -= delta; gsa2.bgs[0].scroll -= delta;
gsa2.bgs[1].scroll -= delta; gsa2.bgs[1].scroll -= delta;
//gsa2.bgs[2].scroll -= delta; //gsa2.bgs[2].scroll -= delta;
} }
_ => {}
}
} }
*mouse_pos = new_pos; *mouse_pos = new_pos;
*tile_pos = IVec2 { *tile_pos = IVec2 {
@ -214,8 +311,8 @@ pub(crate) fn run_mapedit() {
}, },
Event::MainEventsCleared => { Event::MainEventsCleared => {
if gsa.bgs[0].active { match *state {
// normal mode State::Edit => {
if *left_down { if *left_down {
if tile_pos.x >= 0 if tile_pos.x >= 0
&& tile_pos.y >= 0 && tile_pos.y >= 0
@ -223,7 +320,7 @@ pub(crate) fn run_mapedit() {
&& tile_pos.y < BACKGROUND_MAX_SIZE as i32 && tile_pos.y < BACKGROUND_MAX_SIZE as i32
{ {
let tile = (selected_tile.x + (selected_tile.y << 8)) as u16; 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; gsa.bgs[*current_layer].tiles[tile_pos.x as usize][tile_pos.y as usize] = tile;
} }
} else if *right_down { } else if *right_down {
if tile_pos.x >= 0 if tile_pos.x >= 0
@ -231,25 +328,27 @@ pub(crate) fn run_mapedit() {
&& tile_pos.x < BACKGROUND_MAX_SIZE as i32 && tile_pos.x < BACKGROUND_MAX_SIZE as i32
&& tile_pos.y < 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; gsa.bgs[*current_layer].tiles[tile_pos.x as usize][tile_pos.y as usize] =
EMPTY_TILE;
} }
} }
} else { }
// tile select mode State::SelectTile => {
if *left_down { if *left_down {
if tile_pos2.x >= 0 if tile_pos2.x >= 0
&& tile_pos2.y >= 0 && tile_pos2.y >= 0
&& tile_pos2.x < BACKGROUND_MAX_SIZE as i32 && tile_pos2.x < BACKGROUND_MAX_SIZE as i32
&& tile_pos2.y < 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] = gsa2.bgs[1].tiles[selected_tile.x as usize]
EMPTY_TILE; [selected_tile.y as usize] = EMPTY_TILE;
*selected_tile = *tile_pos2; *selected_tile = *tile_pos2;
gsa2.bgs[1].tiles[selected_tile.x as usize][selected_tile.y as usize] = gsa2.bgs[1].tiles[selected_tile.x as usize]
TILE_MARKER; [selected_tile.y as usize] = TILE_MARKER;
} }
} }
} }
};
// render // render
let size = window.inner_size(); let size = window.inner_size();
@ -272,7 +371,8 @@ pub(crate) fn run_mapedit() {
data: &mut screen_buffer, data: &mut screen_buffer,
size: screen_size, size: screen_size,
}; };
if gsa.bgs[0].active { match *state {
State::Edit => {
let xs = -gsa.bgs[0].scroll.x - 1; let xs = -gsa.bgs[0].scroll.x - 1;
let ys = -gsa.bgs[0].scroll.y - 1; let ys = -gsa.bgs[0].scroll.y - 1;
let xe = xs + gsa.bgs[0].size.x * TILE_SIZE as i32 + 1; let xe = xs + gsa.bgs[0].size.x * TILE_SIZE as i32 + 1;
@ -298,6 +398,8 @@ pub(crate) fn run_mapedit() {
screen.draw_hline(IVec2 { x: startx, y: ye }, len, 0xfc); screen.draw_hline(IVec2 { x: startx, y: ye }, len, 0xfc);
} }
} }
_ => {}
}
render_to_window( render_to_window(
&mut window_buffer, &mut window_buffer,

10
src/maps.rs Normal file
View File

@ -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<u16, [Tilemap; 3]>,
}

View File

@ -1,5 +1,6 @@
use crate::buttons::{button_from_gilrs, button_from_scancode}; use crate::buttons::{button_from_gilrs, button_from_scancode};
use crate::gsa_render_to_screen::{render_to_screen, render_to_window}; use crate::gsa_render_to_screen::{render_to_screen, render_to_window};
use crate::maps::Maps;
use crate::tileset::load_tileset; use crate::tileset::load_tileset;
use crate::{ use crate::{
Buttons, Gsa, Sprite, FONT_BOLD, MAX_SPRITES, SCREEN_HEIGHT, SCREEN_WIDTH, TRANSPARENT, Buttons, Gsa, Sprite, FONT_BOLD, MAX_SPRITES, SCREEN_HEIGHT, SCREEN_WIDTH, TRANSPARENT,
@ -27,7 +28,12 @@ use winit::window::WindowBuilder;
macro_rules! run { macro_rules! run {
($init: ident, $update: ident) => { ($init: ident, $update: ident) => {
fn main() { 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<TGame: 'static>(
init_fn: fn(gsa: &mut Gsa) -> TGame, init_fn: fn(gsa: &mut Gsa) -> TGame,
update_fn: fn(game: &mut TGame, gsa: &mut Gsa), update_fn: fn(game: &mut TGame, gsa: &mut Gsa),
image_data: &[u8], image_data: &[u8],
maps_data: &[u8],
) { ) {
let (tileset, palette) = load_tileset(image_data); let (tileset, palette) = load_tileset(image_data);
@ -48,6 +55,7 @@ pub fn run<TGame: 'static>(
pressed: 0, pressed: 0,
released: 0, released: 0,
down: 0, down: 0,
maps: postcard::from_bytes(maps_data).unwrap(),
}; };
gsa.reset_bgs(); gsa.reset_bgs();

26
src/tilemap.rs Normal file
View File

@ -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<u16>,
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,
}
}
}