... did all the things

This commit is contained in:
dani 2023-07-22 22:36:53 +00:00
parent 40d4ba4574
commit 41189401ab
11 changed files with 381 additions and 262 deletions

View File

@ -3,6 +3,7 @@
name = "gsa" name = "gsa"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
description = "Game development library modelled after an imaginary console"
# 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
@ -11,7 +12,6 @@ lazy_static = "1.4.0"
glam = "0.24.0" glam = "0.24.0"
ascii = "1.1.0" ascii = "1.1.0"
gilrs = "0.10.2" gilrs = "0.10.2"
cpal = "0.15.2"
winit = "0.28.6" winit = "0.28.6"
softbuffer = "0.3.0" softbuffer = "0.3.0"
gif = "0.12.0" gif = "0.12.0"

View File

@ -1,12 +1,12 @@
use glam::IVec2; use glam::IVec2;
use gsa::{run, Gsa}; use gsa::{run, Gsa, FACE_DOWN};
struct Game {} struct Game {}
fn init(gsa: &mut Gsa) -> Game { fn init(gsa: &mut Gsa) -> Game {
gsa.sprites[0].tile = 0x0300; gsa.sprites[0].tile = 0x0300;
gsa.sprites[1].tile = 0x0200; gsa.sprites[1].tile = 0x0200;
gsa.maps[0].tiles[0][0] = 0x0300; gsa.maps[0].tiles[1][1] = 0x0300;
gsa.maps[1].half_tile = true; gsa.maps[1].half_tile = true;
gsa.write_string(1, IVec2::ONE, "Hello world nyaa~"); gsa.write_string(1, IVec2::ONE, "Hello world nyaa~");
Game {} Game {}
@ -14,8 +14,9 @@ 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();
if gsa.input.pressed.face_down { gsa.maps[1].scroll.x += 1;
if gsa.button_pressed(FACE_DOWN) {
gsa.sprites[1].tile += 1; gsa.sprites[1].tile += 1;
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,47 +1,70 @@
/// State of all GSA buttons use gilrs::Button;
#[derive(Default, Copy, Clone)] use winit::event::ScanCode;
pub struct Buttons {
/// UP on dpad
pub dpad_up: bool,
/// DOWN on dpad
pub dpad_down: bool,
/// LEFT on dpad
pub dpad_left: bool,
/// RIGHT on dpad
pub dpad_right: bool,
/// X on nintendo, Y on microsoft, TRIANGLE on sony
pub face_up: bool,
/// B on nintendo, A on microsoft, CROSS on sony
pub face_down: bool,
/// Y on nintendo, X on microsoft, SQUARE on sony
pub face_left: bool,
/// A on nintendo, B on microsoft, CIRCLE on sony
pub face_right: bool,
/// left shoulder button
pub l: bool,
/// right shoulder button
pub r: bool,
/// start button
pub start: bool,
/// select button
pub select: bool,
}
impl Buttons { /// UP on dpad
pub(crate) fn pressed(old: &Buttons, new: &Buttons) -> Buttons { pub const DPAD_UP: Buttons = 0x0001;
Buttons { /// DOWN on dpad
dpad_up: !old.dpad_up && new.dpad_up, pub const DPAD_DOWN: Buttons = 0x0002;
dpad_down: !old.dpad_down && new.dpad_down, /// LEFT on dpad
dpad_left: !old.dpad_left && new.dpad_left, pub const DPAD_LEFT: Buttons = 0x0004;
dpad_right: !old.dpad_right && new.dpad_right, /// RIGHT on dpad
face_up: !old.face_up && new.face_up, pub const DPAD_RIGHT: Buttons = 0x008;
face_down: !old.face_down && new.face_down, /// X on nintendo, Y on microsoft, TRIANGLE on sony
face_left: !old.face_left && new.face_left, pub const FACE_UP: Buttons = 0x0010;
face_right: !old.face_right && new.face_right, /// B on nintendo, A on microsoft, CROSS on sony
l: !old.l && new.l, pub const FACE_DOWN: Buttons = 0x0020;
r: !old.r && new.r, /// Y on nintendo, X on microsoft, SQUARE on sony
start: !old.start && new.start, pub const FACE_LEFT: Buttons = 0x0040;
select: !old.select && new.select, /// A on nintendo, B on microsoft, CIRCLE on sony
} pub const FACE_RIGHT: Buttons = 0x0080;
/// left shoulder button
pub const L: Buttons = 0x0100;
/// right shoulder button
pub const R: Buttons = 0x0200;
/// start button
pub const START: Buttons = 0x0400;
/// select button
pub const SELECT: Buttons = 0x0800;
/// Bitmask of button states
///
/// GSA pretends all input is a snes-like gamepad
/// d-pad, 4 face buttons, l and r shoulder buttons, start and select
pub type Buttons = u16;
pub(crate) fn button_from_scancode(scancode: ScanCode) -> Buttons {
//todo: currently windows only? check
match scancode {
0x0010 => L,
0x0011 => FACE_UP,
0x0012 => R,
0x001C => START,
0x001E => FACE_LEFT,
0x001F => FACE_DOWN,
0x0020 => FACE_RIGHT,
0x0039 => SELECT,
0xE048 => DPAD_UP,
0xE04B => DPAD_LEFT,
0xE04D => DPAD_RIGHT,
0xE050 => DPAD_DOWN,
_ => 0,
}
}
pub(crate) fn button_from_gilrs(button: Button) -> Buttons {
match button {
Button::South => FACE_DOWN,
Button::East => FACE_RIGHT,
Button::North => FACE_UP,
Button::West => FACE_LEFT,
Button::LeftTrigger | Button::LeftTrigger2 => L,
Button::RightTrigger | Button::RightTrigger2 => R,
Button::Select => SELECT,
Button::Start => START,
Button::DPadUp => DPAD_UP,
Button::DPadDown => DPAD_DOWN,
Button::DPadLeft => DPAD_LEFT,
Button::DPadRight => DPAD_RIGHT,
_ => 0,
} }
} }

View File

@ -1,8 +1,9 @@
use crate::input::Input;
use crate::rgb::Rgb; use crate::rgb::Rgb;
use crate::sprite::Sprite; use crate::sprite::Sprite;
use crate::tilemap::Tilemap; use crate::tilemap::Tilemap;
use crate::{MAX_SPRITES, MAX_TILEMAPS, TILEMAP_MAX_SIZE}; use crate::{
Buttons, DPAD_DOWN, DPAD_LEFT, DPAD_RIGHT, DPAD_UP, MAX_SPRITES, MAX_TILEMAPS, TILEMAP_MAX_SIZE,
};
use ascii::{AsciiChar, AsciiStr}; use ascii::{AsciiChar, AsciiStr};
use glam::IVec2; use glam::IVec2;
@ -22,8 +23,9 @@ pub struct Gsa {
/// Chosen as half-size tile index, extends 16x16 half tiles in x and y /// Chosen as half-size tile index, extends 16x16 half tiles in x and y
pub font: u16, pub font: u16,
/// Current input state pub(crate) pressed: Buttons,
pub input: Input, pub(crate) released: Buttons,
pub(crate) down: Buttons,
} }
impl Gsa { impl Gsa {
@ -41,6 +43,31 @@ impl Gsa {
} }
} }
/// Checks if any of given buttons currently held down
pub fn button_down(&self, button: Buttons) -> bool {
self.down & button != 0
}
/// Checks if any of given buttons been pressed in the current frame
pub fn button_pressed(&self, button: Buttons) -> bool {
self.pressed & button != 0
}
/// Checks if any of given buttons been released in the current frame
pub fn button_released(&self, button: Buttons) -> bool {
self.released & button != 0
}
/// Directional vector (-1 to 1) from current dpad state
pub fn input_dir(&self) -> IVec2 {
IVec2 {
x: if self.button_down(DPAD_LEFT) { -1 } else { 0 }
+ if self.button_down(DPAD_RIGHT) { 1 } else { 0 },
y: if self.button_down(DPAD_UP) { -1 } else { 0 }
+ if self.button_down(DPAD_DOWN) { 1 } else { 0 },
}
}
/// Write given string on given map, at given position, with font [Gsa::font] /// Write given string on given map, at given position, with font [Gsa::font]
pub fn write_string(&mut self, map: usize, pos: IVec2, str: &str) { pub fn write_string(&mut self, map: usize, pos: IVec2, str: &str) {
let str = AsciiStr::from_ascii(str).unwrap(); let str = AsciiStr::from_ascii(str).unwrap();

View File

@ -1,23 +1,158 @@
use crate::{Gsa, MAX_SPRITES, TILE_SIZE}; use crate::{
Gsa, Rgb, Tilemap, HALF_TILE_SIZE, MAX_TILEMAPS, SCREEN_HEIGHT, SCREEN_WIDTH, TILEMAP_MAX_SIZE,
TILESET_SIZE, TILE_SIZE,
};
use glam::IVec2; use glam::IVec2;
use softbuffer::Buffer; use softbuffer::Buffer;
pub(crate) fn render_to_window(target: &mut Buffer, gsa: &Gsa, window_size: IVec2) { fn draw_tile(target: &mut [u8], pos: IVec2, tile: u16, tileset: &[u8], half: bool) {
for (y, row) in target.chunks_exact_mut(window_size.x as usize).enumerate() { let tilesize = if half { HALF_TILE_SIZE } else { TILE_SIZE };
let y = y as i32; let tx = tile as usize % 0x100 * tilesize;
for x in 0..window_size.x { let ty = tile as usize / 0x100 * tilesize;
let mut p = 0; let startx = pos.x.max(0).min(SCREEN_WIDTH as i32);
for sprite in &gsa.sprites { let starty = pos.y.max(0).min(SCREEN_HEIGHT as i32);
if sprite.tile > 0 let endx = (pos.x + tilesize as i32).max(0).min(SCREEN_WIDTH as i32);
&& x >= sprite.pos.x let endy = (pos.y + tilesize as i32).max(0).min(SCREEN_HEIGHT as i32);
&& y >= sprite.pos.y for y in (starty - pos.y)..(endy - pos.y) {
&& x < sprite.pos.x + TILE_SIZE as i32 for x in (startx - pos.x)..(endx - pos.x) {
&& y < sprite.pos.y + TILE_SIZE as i32 let p = tileset[(x as usize + tx) + (y as usize + ty) * (TILESET_SIZE * TILE_SIZE)];
{ if p > 0 {
p = 1; target[(x as usize + pos.x as usize)
} + (y as usize + pos.y as usize) * SCREEN_WIDTH] = p;
} }
row[x as usize] = gsa.palette[p].to_u32(); }
}
}
fn render_map(target: &mut [u8], map: &Tilemap, tileset: &[u8]) {
let tcmult = if map.half_tile { 2 } else { 1 };
let tilesize = if map.half_tile {
HALF_TILE_SIZE
} else {
TILE_SIZE
} as i32;
let mut startx = map.scroll.x / tilesize;
let mut starty = map.scroll.y / tilesize;
let endx = (TILEMAP_MAX_SIZE as i32).min(startx + 20 * tcmult);
let endy = (TILEMAP_MAX_SIZE as i32).min(starty + 12 * tcmult);
startx = 0.max(startx);
starty = 0.max(starty);
for x in startx..endx {
for y in starty..endy {
let tile = map.tiles[x as usize][y as usize];
if tile > 0 {
draw_tile(
target,
IVec2 {
x: x * tilesize - map.scroll.x,
y: y * tilesize - map.scroll.y,
},
tile,
tileset,
map.half_tile,
);
}
}
}
}
pub(crate) fn render_to_screen(target: &mut [u8], gsa: &Gsa, tileset: &[u8]) {
for i in 0..MAX_TILEMAPS {
render_map(target, &gsa.maps[i], tileset);
for sprite in &gsa.sprites {
if sprite.tile > 0 && sprite.priority == i as u8 {
draw_tile(target, sprite.pos, sprite.tile, tileset, false);
}
}
}
}
pub(crate) fn render_to_window(
target: &mut Buffer,
src: &mut [u8],
palette: &[Rgb; 256],
window_size: IVec2,
scale: usize,
off_x: usize,
off_y: usize,
) {
let start = window_size.x as usize * off_y;
let end = start + window_size.x as usize * SCREEN_HEIGHT * scale;
for (y, row) in target[start..end]
.chunks_exact_mut(window_size.x as usize * scale)
.enumerate()
{
let y = y as i32;
for x in 0..SCREEN_WIDTH {
let p = src[x + y as usize * SCREEN_WIDTH];
for scaley in 0..scale {
for scalex in 0..scale {
let sx = x * scale + scalex;
row[sx + off_x + scaley * window_size.x as usize] =
palette[p as usize].to_u32();
}
}
//unrolled is faster benchmarked... <_<
/*
let ww = window_size.x as usize;
match scale {
1 => {
row[x + off_x] = palette[p as usize].to_u32();
}
2 => {
row[x * 2 + off_x] = palette[p as usize].to_u32();
row[x * 2 + off_x + 1] = palette[p as usize].to_u32();
row[x * 2 + off_x + ww] = palette[p as usize].to_u32();
row[x * 2 + off_x + ww + 1] = palette[p as usize].to_u32();
}
6 => {
row[x * 6 + off_x + ww * 0] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 0 + 1] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 0 + 2] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 0 + 3] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 0 + 4] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 0 + 5] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 1] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 1 + 1] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 1 + 2] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 1 + 3] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 1 + 4] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 1 + 5] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 2] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 2 + 1] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 2 + 2] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 2 + 3] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 2 + 4] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 2 + 5] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 3] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 3 + 1] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 3 + 2] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 3 + 3] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 3 + 4] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 3 + 5] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 4] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 4 + 1] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 4 + 2] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 4 + 3] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 4 + 4] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 4 + 5] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 5] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 5 + 1] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 5 + 2] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 5 + 3] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 5 + 4] = palette[p as usize].to_u32();
row[x * 6 + off_x + ww * 5 + 5] = palette[p as usize].to_u32();
}
_ => {}
}
*/
} }
} }
} }

View File

@ -1,18 +0,0 @@
use crate::buttons::Buttons;
use glam::IVec2;
/// Input State
///
/// GSA pretends all input is a snes-like gamepad
/// d-pad, 4 face buttons, l and r shoulder buttons, start and select
#[derive(Default)]
pub struct Input {
/// Buttons that are currentle held down
pub down: Buttons,
/// Buttons that have been pressed in the current frame
pub pressed: Buttons,
/// Directional vector (-1 to 1) from current dpad state
pub dir: IVec2,
}

View File

@ -12,7 +12,14 @@
//! - Tilemaps: 4 of size 1024x1024, scrollable //! - Tilemaps: 4 of size 1024x1024, scrollable
//! //!
//! ## Features not yet implemented //! ## Features not yet implemented
//! - Sound (no samples //! - Tilemap effects
//! - Rotation? Scaling?
//! - Mosaic?
//! - Mode7?
//! - Sprite Effects
//! - Rotation? Scaling?
//! - Mosaic?
//! - Sound (no samples)
//! - Synth //! - Synth
//! - Speech //! - Speech
//! - Savegames //! - Savegames
@ -23,21 +30,18 @@
mod buttons; mod buttons;
mod gsa; mod gsa;
mod gsa_render_to_screen; mod gsa_render_to_screen;
mod input;
mod rgb; mod rgb;
mod run; mod run;
mod sprite; mod sprite;
mod state;
mod tilemap; mod tilemap;
mod tileset; mod tileset;
pub use crate::buttons::Buttons; pub use crate::buttons::*;
pub use crate::gsa::Gsa; pub use crate::gsa::*;
pub use crate::input::Input; pub use crate::rgb::*;
pub use crate::rgb::Rgb;
pub use crate::run::run; pub use crate::run::run;
pub use crate::sprite::Sprite; pub use crate::sprite::*;
pub use crate::tilemap::Tilemap; pub use crate::tilemap::*;
/// Amount of sprites in [Gsa::sprites] /// Amount of sprites in [Gsa::sprites]
pub const MAX_SPRITES: usize = 0xff; pub const MAX_SPRITES: usize = 0xff;

View File

@ -1,14 +1,15 @@
use crate::gsa_render_to_screen::render_to_window; use crate::buttons::{button_from_gilrs, button_from_scancode};
use crate::state::State; use crate::gsa_render_to_screen::{render_to_screen, render_to_window};
use crate::tileset::load_tileset; use crate::tileset::load_tileset;
use crate::{Gsa, Rgb, Sprite, MAX_SPRITES, SCREEN_HEIGHT, SCREEN_WIDTH}; use crate::{Buttons, Gsa, Sprite, MAX_SPRITES, SCREEN_HEIGHT, SCREEN_WIDTH};
use gilrs::Gilrs; use gilrs::EventType;
use glam::IVec2; use glam::IVec2;
use std::cmp::min; use std::cmp::min;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use winit::dpi::LogicalSize; use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
use winit::event::{Event, VirtualKeyCode, WindowEvent}; use winit::event;
use winit::event::{ElementState, Event, VirtualKeyCode, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop}; use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder; use winit::window::WindowBuilder;
@ -41,7 +42,9 @@ pub fn run<TGame: 'static>(
maps: Default::default(), maps: Default::default(),
palette, palette,
font: 0x1010, font: 0x1010,
input: Default::default(), pressed: 0,
released: 0,
down: 0,
}; };
let mut game = init_fn(&mut gsa); let mut game = init_fn(&mut gsa);
/*let state = State::<TGame> { /*let state = State::<TGame> {
@ -64,6 +67,23 @@ pub fn run<TGame: 'static>(
.build(&event_loop) .build(&event_loop)
.unwrap(); .unwrap();
{
let monitor_size = window.primary_monitor().unwrap().size();
let scale_factor = 0.9;
let window_scale = ((monitor_size.width as f32 * scale_factor) as u32
/ SCREEN_WIDTH as u32)
.min((monitor_size.height as f32 * scale_factor) as u32 / SCREEN_HEIGHT as u32);
window.set_inner_size(PhysicalSize {
width: window_scale * SCREEN_WIDTH as u32,
height: window_scale * SCREEN_HEIGHT as u32,
});
let outer_size = window.outer_size();
window.set_outer_position(PhysicalPosition {
x: (monitor_size.width - outer_size.width) / 2,
y: (monitor_size.height - outer_size.height) / 2,
});
}
let context = unsafe { softbuffer::Context::new(&window) }.unwrap(); let context = unsafe { softbuffer::Context::new(&window) }.unwrap();
let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap(); let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap();
@ -71,34 +91,97 @@ pub fn run<TGame: 'static>(
let mut last_second = Instant::now(); let mut last_second = Instant::now();
let mut last_frame = last_second; let mut last_frame = last_second;
let target_frame_duration = Duration::from_secs(1).div_f64(6000.0); let target_frame_duration = Duration::from_secs(1).div_f64(60.0);
let mut scale = 1usize; let mut scale = 1usize;
let mut off_x = 0usize; let mut off_x = 0usize;
let mut off_y = 0usize; let mut off_y = 0usize;
let mut new_buttons = Buttons::default();
// in case button gets pressed and released within the same frame need to catch them
// seperately from the last-now comparison to catch it
let mut new_pressed = Buttons::default();
let mut new_released = Buttons::default();
let mut gilrs = gilrs::Gilrs::new().unwrap();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
let scale = &mut scale; let scale = &mut scale;
let off_x = &mut off_x; let off_x = &mut off_x;
let off_y = &mut off_y; let off_y = &mut off_y;
let new_buttons = &mut new_buttons;
let new_pressed = &mut new_pressed;
let new_released = &mut new_released;
let gilrs = &mut gilrs;
if Instant::now() - last_second > Duration::from_secs(1) { if Instant::now() - last_second > Duration::from_secs(1) {
println!("fps: {}", frames_since_last_second); println!("fps: {}", frames_since_last_second);
frames_since_last_second = 0; frames_since_last_second = 0;
last_second += Duration::from_secs(1); last_second += Duration::from_secs(1);
} }
let mut screen_buffer = [0u8; SCREEN_WIDTH * SCREEN_HEIGHT];
match event { match event {
Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
input:
event::KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Escape),
..
},
..
},
..
} => {
*control_flow = ControlFlow::Exit;
}
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::KeyboardInput { input, .. }, event: WindowEvent::KeyboardInput { input, .. },
.. ..
} => match input.virtual_keycode { } => {
Some(VirtualKeyCode::Escape) => { let button = button_from_scancode(input.scancode);
*control_flow = ControlFlow::Exit; match input.state {
} ElementState::Pressed => {
_ => {} *new_buttons |= button;
}, *new_pressed |= button;
}
ElementState::Released => {
*new_buttons &= !button;
*new_released |= button;
}
};
}
Event::MainEventsCleared {} => { Event::MainEventsCleared {} => {
if Instant::now() - last_frame >= target_frame_duration { if Instant::now() - last_frame >= target_frame_duration {
//input
while let Some(event) = gilrs.next_event() {
match event.event {
EventType::ButtonPressed(button, ..) => {
let button = button_from_gilrs(button);
*new_buttons |= button;
*new_pressed |= button;
}
EventType::ButtonReleased(button, ..) => {
let button = button_from_gilrs(button);
*new_buttons &= !button;
*new_released |= button;
}
_ => {}
}
}
gsa.down = *new_buttons;
gsa.released = *new_released;
gsa.pressed = *new_pressed;
*new_released = 0;
*new_pressed = 0;
//update
update_fn(&mut game, &mut gsa); update_fn(&mut game, &mut gsa);
//graphics
let size = window.inner_size(); let size = window.inner_size();
surface surface
.resize( .resize(
@ -114,16 +197,21 @@ pub fn run<TGame: 'static>(
*off_x = (size.width as usize - SCREEN_WIDTH * *scale) / 2; *off_x = (size.width as usize - SCREEN_WIDTH * *scale) / 2;
*off_y = (size.height as usize - SCREEN_HEIGHT * *scale) / 2; *off_y = (size.height as usize - SCREEN_HEIGHT * *scale) / 2;
let mut buf = surface.buffer_mut().unwrap(); let mut window_buffer = surface.buffer_mut().unwrap();
render_to_screen(&mut screen_buffer, &gsa, &tileset);
render_to_window( render_to_window(
&mut buf, &mut window_buffer,
&gsa, &mut screen_buffer,
&palette,
IVec2 { IVec2 {
x: size.width as i32, x: size.width as i32,
y: size.height as i32, y: size.height as i32,
}, },
*scale,
*off_x,
*off_y,
); );
buf.present().unwrap(); window_buffer.present().unwrap();
frames_since_last_second += 1; frames_since_last_second += 1;
last_frame += target_frame_duration; last_frame += target_frame_duration;
} }

View File

@ -8,10 +8,16 @@ pub struct Sprite {
pub pos: IVec2, pub pos: IVec2,
/// Tile index /// Tile index
pub tile: u16, pub tile: u16,
/// Priority, this sprite will be drawn above map of idx priority
pub priority: u8,
} }
impl Display for Sprite { impl Display for Sprite {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "[pos: {}, tile: {}]", self.pos, self.tile) write!(
f,
"[pos: {}, tile: {}, priority: {}]",
self.pos, self.tile, self.priority
)
} }
} }

View File

@ -1,147 +0,0 @@
use crate::buttons::Buttons;
use crate::{Gsa, TILEMAP_MAX_SIZE};
use gilrs::{Button, EventType, Gilrs};
use glam::IVec2;
use std::rc::Rc;
pub struct State<TGame> {
pub(crate) gsa: Gsa,
pub(crate) game: TGame,
pub(crate) update_fn: fn(game: &mut TGame, gsa: &mut Gsa),
pub(crate) tileset: Vec<u8>,
pub(crate) first: bool,
pub(crate) gilrs: Gilrs,
}
impl<TGame> State<TGame> {
fn update(&mut self) {
let mut new_buttons = self.gsa.input.down;
while let Some(event) = self.gilrs.next_event() {
match event {
gilrs::Event {
event: EventType::ButtonPressed(button, _),
..
} => match button {
Button::South => new_buttons.face_down = true,
Button::East => new_buttons.face_left = true,
Button::North => new_buttons.face_up = true,
Button::West => new_buttons.face_right = true,
Button::LeftTrigger | Button::LeftTrigger2 => new_buttons.l = true,
Button::RightTrigger | Button::RightTrigger2 => new_buttons.r = true,
Button::Select => new_buttons.select = true,
Button::Start => new_buttons.start = true,
Button::DPadUp => new_buttons.dpad_up = true,
Button::DPadDown => new_buttons.dpad_down = true,
Button::DPadLeft => new_buttons.dpad_left = true,
Button::DPadRight => new_buttons.dpad_right = true,
_ => {}
},
gilrs::Event {
event: EventType::ButtonReleased(button, _),
..
} => match button {
Button::South => new_buttons.face_down = false,
Button::East => new_buttons.face_left = false,
Button::North => new_buttons.face_up = false,
Button::West => new_buttons.face_right = false,
Button::LeftTrigger | Button::LeftTrigger2 => new_buttons.l = false,
Button::RightTrigger | Button::RightTrigger2 => new_buttons.r = false,
Button::Select => new_buttons.select = false,
Button::Start => new_buttons.start = false,
Button::DPadUp => new_buttons.dpad_up = false,
Button::DPadDown => new_buttons.dpad_down = false,
Button::DPadLeft => new_buttons.dpad_left = false,
Button::DPadRight => new_buttons.dpad_right = false,
_ => {}
},
_ => (),
}
}
self.gsa.input.pressed = Buttons::pressed(&self.gsa.input.down, &new_buttons);
self.gsa.input.down = new_buttons;
self.gsa.input.dir = IVec2 {
x: if self.gsa.input.down.dpad_left { -1 } else { 0 }
+ if self.gsa.input.down.dpad_right { 1 } else { 0 },
y: if self.gsa.input.down.dpad_up { -1 } else { 0 }
+ if self.gsa.input.down.dpad_down { 1 } else { 0 },
};
//todo: don't if not updated... how check? <_<
/*
for i in 0..=255 {
window_state.set_palette(
i,
self.gsa.palette[i as usize].r,
self.gsa.palette[i as usize].g,
self.gsa.palette[i as usize].b,
);
}
*/
(self.update_fn)(&mut self.game, &mut self.gsa);
}
fn draw(&self) {
//target.clear();
for map in &self.gsa.maps {
let tcmult = if map.half_tile { 2 } else { 1 };
let tilesize = if map.half_tile { 8 } else { 16 };
let mut startx = map.scroll.x / tilesize;
let mut starty = map.scroll.y / tilesize;
let endx = (TILEMAP_MAX_SIZE as i32).min(startx + 20 * tcmult);
let endy = (TILEMAP_MAX_SIZE as i32).min(starty + 12 * tcmult);
startx = 0.max(startx);
starty = 0.max(starty);
for x in startx..endx {
for y in starty..endy {
let tile = map.tiles[x as usize][y as usize];
if tile > 0 {
let ty = tile / 0x100;
let tx = tile % 0x100;
/*
target.draw_image_partial(
IVec2 {
x: x * tilesize - map.scroll.x,
y: y * tilesize - map.scroll.y,
},
&self.tileset,
IRect {
pos: IVec2 {
x: tx as i32 * tilesize,
y: ty as i32 * tilesize,
},
size: IVec2 {
x: tilesize,
y: tilesize,
},
},
)
*/
}
}
}
}
for sprite in &self.gsa.sprites {
if sprite.tile > 0 {
let ty = sprite.tile / 0x100;
let tx = sprite.tile % 0x100;
/*
target.draw_image_partial(
sprite.pos,
&self.tileset,
IRect {
pos: IVec2 {
x: tx as i32 * 16,
y: ty as i32 * 16,
},
size: IVec2 { x: 16, y: 16 },
},
);
*/
}
}
}
}