layer system for map edit
This commit is contained in:
parent
8f78bbdca1
commit
aff0311484
|
@ -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"
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 28 KiB |
|
@ -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;
|
||||
}
|
||||
|
|
19
src/gsa.rs
19
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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 :(
|
||||
|
|
146
src/mapedit.rs
146
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,14 +212,47 @@ 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) => {
|
||||
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,17 +277,21 @@ pub(crate) fn run_mapedit() {
|
|||
};
|
||||
let delta = new_pos - *mouse_pos;
|
||||
if *middle_down {
|
||||
if gsa.bgs[0].active {
|
||||
match *state {
|
||||
State::Edit => {
|
||||
// normal mode
|
||||
gsa.bgs[0].scroll -= delta;
|
||||
gsa.bgs[1].scroll -= delta;
|
||||
gsa.bgs[2].scroll -= delta;
|
||||
} else {
|
||||
}
|
||||
State::SelectTile => {
|
||||
// tile select mode
|
||||
gsa2.bgs[0].scroll -= delta;
|
||||
gsa2.bgs[1].scroll -= delta;
|
||||
//gsa2.bgs[2].scroll -= delta;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
*mouse_pos = new_pos;
|
||||
*tile_pos = IVec2 {
|
||||
|
@ -214,8 +311,8 @@ pub(crate) fn run_mapedit() {
|
|||
},
|
||||
|
||||
Event::MainEventsCleared => {
|
||||
if gsa.bgs[0].active {
|
||||
// normal mode
|
||||
match *state {
|
||||
State::Edit => {
|
||||
if *left_down {
|
||||
if tile_pos.x >= 0
|
||||
&& tile_pos.y >= 0
|
||||
|
@ -223,7 +320,7 @@ pub(crate) fn run_mapedit() {
|
|||
&& 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;
|
||||
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
|
||||
|
@ -231,25 +328,27 @@ pub(crate) fn run_mapedit() {
|
|||
&& 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;
|
||||
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 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;
|
||||
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;
|
||||
gsa2.bgs[1].tiles[selected_tile.x as usize]
|
||||
[selected_tile.y as usize] = TILE_MARKER;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// render
|
||||
let size = window.inner_size();
|
||||
|
@ -272,7 +371,8 @@ pub(crate) fn run_mapedit() {
|
|||
data: &mut screen_buffer,
|
||||
size: screen_size,
|
||||
};
|
||||
if gsa.bgs[0].active {
|
||||
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;
|
||||
|
@ -298,6 +398,8 @@ pub(crate) fn run_mapedit() {
|
|||
screen.draw_hline(IVec2 { x: startx, y: ye }, len, 0xfc);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
render_to_window(
|
||||
&mut window_buffer,
|
||||
|
|
|
@ -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]>,
|
||||
}
|
10
src/run.rs
10
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<TGame: 'static>(
|
|||
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<TGame: 'static>(
|
|||
pressed: 0,
|
||||
released: 0,
|
||||
down: 0,
|
||||
maps: postcard::from_bytes(maps_data).unwrap(),
|
||||
};
|
||||
|
||||
gsa.reset_bgs();
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue