improved sprites - spriteinfo and methods
This commit is contained in:
parent
849c400497
commit
bd450e806b
12 changed files with 187 additions and 108 deletions
|
|
@ -38,11 +38,53 @@ pub struct OtherLevelPosition {
|
|||
pub id: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct SpriteInfo {
|
||||
pub id: String,
|
||||
pub recolour: bool,
|
||||
pub alt: Option<String>,
|
||||
pub offset: (f32, f32),
|
||||
pub alt_offset: (f32, f32),
|
||||
}
|
||||
|
||||
impl SpriteInfo {
|
||||
pub fn new(id: &str) -> Self {
|
||||
Self {
|
||||
id: id.to_string(),
|
||||
recolour: false,
|
||||
alt: None,
|
||||
offset: (0.0, 0.0),
|
||||
alt_offset: (0.0, 0.0),
|
||||
}
|
||||
}
|
||||
pub fn colourable(id: &str) -> Self {
|
||||
Self {
|
||||
id: id.to_string(),
|
||||
recolour: true,
|
||||
alt: None,
|
||||
offset: (0.0, 0.0),
|
||||
alt_offset: (0.0, 0.0),
|
||||
}
|
||||
}
|
||||
pub fn swap(&self) -> Self {
|
||||
if let Some(alt_sprite) = &self.alt {
|
||||
Self {
|
||||
id: alt_sprite.clone(),
|
||||
recolour: self.recolour,
|
||||
alt: Some(self.id.clone()),
|
||||
offset: self.alt_offset,
|
||||
alt_offset: self.offset,
|
||||
}
|
||||
} else {
|
||||
unreachable!("Tried to call .swap() on a sprite with no alt: {:?}", self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component, ConvertSaveload, Clone)]
|
||||
pub struct Renderable {
|
||||
pub glyph: FontCharType,
|
||||
pub sprite: Option<String>,
|
||||
pub colour_sprite: bool,
|
||||
pub sprite: Option<SpriteInfo>,
|
||||
pub fg: RGB,
|
||||
pub bg: RGB,
|
||||
pub render_order: i32,
|
||||
|
|
|
|||
|
|
@ -275,7 +275,6 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) {
|
|||
.insert(*player, Renderable {
|
||||
glyph: to_cp437(DWARF_GLYPH),
|
||||
sprite: None, // TODO: Dwarf sprite
|
||||
colour_sprite: true,
|
||||
fg: RGB::named(DWARF_COLOUR),
|
||||
bg: RGB::named(BLACK),
|
||||
render_order: 0,
|
||||
|
|
@ -288,7 +287,6 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) {
|
|||
.insert(*player, Renderable {
|
||||
glyph: to_cp437(ELF_GLYPH),
|
||||
sprite: None, // TODO: Elf sprite
|
||||
colour_sprite: true,
|
||||
fg: RGB::named(ELF_COLOUR),
|
||||
bg: RGB::named(BLACK),
|
||||
render_order: 0,
|
||||
|
|
@ -315,7 +313,6 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) {
|
|||
.insert(*player, Renderable {
|
||||
glyph: to_cp437(CATFOLK_GLYPH),
|
||||
sprite: None, // TODO: Catfolk sprite
|
||||
colour_sprite: true,
|
||||
fg: RGB::named(CATFOLK_COLOUR),
|
||||
bg: RGB::named(BLACK),
|
||||
render_order: 0,
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ fn draw_bar(
|
|||
let fill_width = (percent * (w as f32)) as i32;
|
||||
for x in 0..w {
|
||||
let suffix = if x == 0 { "1" } else if x == w - 1 { "3" } else { "2" };
|
||||
let fill = if x <= fill_width { "full" } else { "empty" };
|
||||
let fill = if x < fill_width { "full" } else { "empty" };
|
||||
let sprite = if let Some(sprite) = atlas.get(&format!("{}_{}_{}", sprite, fill, suffix)) {
|
||||
sprite
|
||||
} else {
|
||||
|
|
|
|||
30
src/main.rs
30
src/main.rs
|
|
@ -253,16 +253,19 @@ fn draw_camera(
|
|||
}
|
||||
// TODO: Use sprites here, not text drawing. Put bitmap font into atlas.
|
||||
let renderable = renderables.get(entry.1.e).unwrap();
|
||||
if let Some(sprite_id) = &renderable.sprite {
|
||||
let sprite = if let Some(sprite) = atlas.get(sprite_id) {
|
||||
if let Some(spriteinfo) = &renderable.sprite {
|
||||
let id = if let Some(sprite) = atlas.get(&spriteinfo.id) {
|
||||
sprite
|
||||
} else {
|
||||
panic!("No entity sprite found for ID: {}", sprite_id);
|
||||
panic!("No entity sprite found for ID: {}", spriteinfo.id);
|
||||
};
|
||||
draw.image(sprite)
|
||||
.position((entry.0.x as f32) * TILESIZE, (entry.0.y as f32) * TILESIZE)
|
||||
draw.image(id)
|
||||
.position(
|
||||
((entry.0.x as f32) + spriteinfo.offset.0) * TILESIZE,
|
||||
((entry.0.y as f32) + spriteinfo.offset.1) * TILESIZE
|
||||
)
|
||||
.color(
|
||||
if renderable.colour_sprite {
|
||||
if spriteinfo.recolour {
|
||||
Color::from_rgb(
|
||||
renderable.fg.r,
|
||||
renderable.fg.g,
|
||||
|
|
@ -293,16 +296,19 @@ fn draw_camera(
|
|||
DrawType::VisibleAndRemember => {
|
||||
// TODO: PUT THIS INTO A FUNCTION!
|
||||
let renderable = renderables.get(entry.1.e).unwrap();
|
||||
if let Some(sprite_id) = &renderable.sprite {
|
||||
let sprite = if let Some(sprite) = atlas.get(sprite_id) {
|
||||
if let Some(spriteinfo) = &renderable.sprite {
|
||||
let id = if let Some(sprite) = atlas.get(&spriteinfo.id) {
|
||||
sprite
|
||||
} else {
|
||||
panic!("No entity sprite found for ID: {}", sprite_id);
|
||||
panic!("No entity sprite found for ID: {}", spriteinfo.id);
|
||||
};
|
||||
draw.image(sprite)
|
||||
.position((entry.0.x as f32) * TILESIZE, (entry.0.y as f32) * TILESIZE)
|
||||
draw.image(id)
|
||||
.position(
|
||||
((entry.0.x as f32) + spriteinfo.offset.0) * TILESIZE,
|
||||
((entry.0.y as f32) + spriteinfo.offset.1) * TILESIZE
|
||||
)
|
||||
.color(
|
||||
if renderable.colour_sprite {
|
||||
if spriteinfo.recolour {
|
||||
Color::from_rgb(
|
||||
renderable.fg.r,
|
||||
renderable.fg.g,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use notan::prelude::*;
|
|||
pub fn get_sprite_for_id(idx: usize, map: &Map, other_pos: Option<Point>) -> (&str, Color) {
|
||||
let f = map.colour_offset[idx].0.0; // Using offset as a source of random.
|
||||
let sprite = match map.tiles[idx] {
|
||||
TileType::Wall => map.tiles[idx].sprite(check_if_base(idx, map), f),
|
||||
TileType::Wall => map.tiles[idx].sprite(check_if_base(TileType::Wall, idx, map), f),
|
||||
_ => map.tiles[idx].sprite(false, f),
|
||||
};
|
||||
let tint = if !map.visible_tiles[idx] {
|
||||
|
|
@ -150,18 +150,23 @@ fn get_forest_theme_renderables(idx:usize, map: &Map, debug: Option<bool>) -> (F
|
|||
return (glyph, fg, bg, offsets, bg_offsets);
|
||||
}
|
||||
|
||||
fn is_revealed_and_wall(map: &Map, x: i32, y: i32, debug: Option<bool>) -> bool {
|
||||
fn is_revealed_and(tt: TileType, map: &Map, x: i32, y: i32, debug: Option<bool>) -> bool {
|
||||
let idx = map.xy_idx(x, y);
|
||||
map.tiles[idx] == TileType::Wall &&
|
||||
(if debug.is_none() { map.revealed_tiles[idx] } else { true })
|
||||
map.tiles[idx] == tt && (if debug.is_none() { map.revealed_tiles[idx] } else { true })
|
||||
}
|
||||
|
||||
fn check_if_base(idx: usize, map: &Map) -> bool {
|
||||
fn check_if_base(tt: TileType, idx: usize, map: &Map) -> bool {
|
||||
let x = (idx as i32) % map.width;
|
||||
let y = (idx as i32) / map.width;
|
||||
if is_revealed_and_wall(map, x, y + 1, None) {
|
||||
// If we're on the edge, it can only be a base sprite.
|
||||
if y > map.height - 2 {
|
||||
return true;
|
||||
}
|
||||
// If the tile below is a revealed wall, we're not the base.
|
||||
if is_revealed_and(tt, map, x, y + 1, None) {
|
||||
return false;
|
||||
}
|
||||
// If the tile below isn't a revealed wall, we're the base.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -179,37 +184,37 @@ fn wall_glyph(map: &Map, x: i32, y: i32, debug: Option<bool>) -> FontCharType {
|
|||
let mut mask: u8 = 0;
|
||||
let diagonals_matter: Vec<u8> = vec![7, 11, 13, 14, 15];
|
||||
|
||||
if is_revealed_and_wall(map, x, y - 1, debug) {
|
||||
if is_revealed_and(TileType::Wall, map, x, y - 1, debug) {
|
||||
// N
|
||||
mask += 1;
|
||||
}
|
||||
if is_revealed_and_wall(map, x, y + 1, debug) {
|
||||
if is_revealed_and(TileType::Wall, map, x, y + 1, debug) {
|
||||
// S
|
||||
mask += 2;
|
||||
}
|
||||
if is_revealed_and_wall(map, x - 1, y, debug) {
|
||||
if is_revealed_and(TileType::Wall, map, x - 1, y, debug) {
|
||||
// W
|
||||
mask += 4;
|
||||
}
|
||||
if is_revealed_and_wall(map, x + 1, y, debug) {
|
||||
if is_revealed_and(TileType::Wall, map, x + 1, y, debug) {
|
||||
// E
|
||||
mask += 8;
|
||||
}
|
||||
|
||||
if diagonals_matter.contains(&mask) {
|
||||
if is_revealed_and_wall(map, x + 1, y - 1, debug) {
|
||||
if is_revealed_and(TileType::Wall, map, x + 1, y - 1, debug) {
|
||||
// Top right
|
||||
mask += 16;
|
||||
}
|
||||
if is_revealed_and_wall(map, x - 1, y - 1, debug) {
|
||||
if is_revealed_and(TileType::Wall, map, x - 1, y - 1, debug) {
|
||||
// Top left
|
||||
mask += 32;
|
||||
}
|
||||
if is_revealed_and_wall(map, x + 1, y + 1, debug) {
|
||||
if is_revealed_and(TileType::Wall, map, x + 1, y + 1, debug) {
|
||||
// Bottom right
|
||||
mask += 64;
|
||||
}
|
||||
if is_revealed_and_wall(map, x - 1, y + 1, debug) {
|
||||
if is_revealed_and(TileType::Wall, map, x - 1, y + 1, debug) {
|
||||
// Bottom left
|
||||
mask += 128;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ fn create_delayed_particles(ecs: &mut World, ctx: &App) {
|
|||
renderables
|
||||
.insert(p, Renderable {
|
||||
sprite: None, // TODO: Particle sprite
|
||||
colour_sprite: false,
|
||||
fg: handled.fg,
|
||||
bg: handled.bg,
|
||||
glyph: handled.glyph,
|
||||
|
|
@ -309,8 +308,7 @@ impl<'a> System<'a> for ParticleSpawnSystem {
|
|||
.expect("Could not insert position");
|
||||
renderables
|
||||
.insert(p, Renderable {
|
||||
sprite: None, // TODO: Particle sprite
|
||||
colour_sprite: false,
|
||||
sprite: None, // TODO: Particle sprites
|
||||
fg: new_particle.fg,
|
||||
bg: new_particle.bg,
|
||||
glyph: new_particle.glyph,
|
||||
|
|
|
|||
|
|
@ -135,8 +135,9 @@ pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState {
|
|||
std::mem::drop(renderables);
|
||||
let mut renderables = ecs.write_storage::<Renderable>();
|
||||
let render_data = renderables.get_mut(potential_target).unwrap();
|
||||
render_data.glyph = to_cp437('+'); // Nethack open door, maybe just use '/' instead.
|
||||
render_data.sprite = Some("door_wood_h_closed".to_string()); // TODO: Enum
|
||||
if let Some(sprite) = &mut render_data.sprite {
|
||||
*sprite = sprite.swap();
|
||||
}
|
||||
door_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y));
|
||||
}
|
||||
result = RunState::Ticking;
|
||||
|
|
@ -233,8 +234,9 @@ pub fn open(i: i32, j: i32, ecs: &mut World) -> RunState {
|
|||
std::mem::drop(renderables);
|
||||
let mut renderables = ecs.write_storage::<Renderable>();
|
||||
let render_data = renderables.get_mut(potential_target).unwrap();
|
||||
render_data.glyph = to_cp437('▓'); // Nethack open door, maybe just use '/' instead.
|
||||
render_data.sprite = Some("door_wood_h_open".to_string()); // TODO: Enum
|
||||
if let Some(sprite) = &mut render_data.sprite {
|
||||
*sprite = sprite.swap();
|
||||
}
|
||||
door_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y));
|
||||
}
|
||||
result = RunState::Ticking;
|
||||
|
|
|
|||
|
|
@ -27,11 +27,21 @@ pub struct Equippable {
|
|||
pub to_hit: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct SpriteInfo {
|
||||
pub id: String,
|
||||
pub alt: Option<String>,
|
||||
pub colour: Option<bool>,
|
||||
pub x: Option<f32>,
|
||||
pub y: Option<f32>,
|
||||
pub alt_x: Option<f32>,
|
||||
pub alt_y: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Renderable {
|
||||
pub glyph: String,
|
||||
pub sprite: Option<String>,
|
||||
pub colour_sprite: Option<bool>,
|
||||
pub sprite: Option<SpriteInfo>,
|
||||
pub fg: String,
|
||||
pub bg: String,
|
||||
pub order: i32,
|
||||
|
|
|
|||
|
|
@ -691,11 +691,24 @@ fn get_renderable_component(
|
|||
) -> crate::components::Renderable {
|
||||
crate::components::Renderable {
|
||||
glyph: to_cp437(renderable.glyph.chars().next().unwrap()),
|
||||
sprite: renderable.sprite.clone(),
|
||||
colour_sprite: if renderable.colour_sprite.is_some() {
|
||||
renderable.colour_sprite.clone().unwrap()
|
||||
sprite: if let Some(spriteinfo) = &renderable.sprite {
|
||||
let x = spriteinfo.x.unwrap_or(0.0);
|
||||
let y = spriteinfo.y.unwrap_or(0.0);
|
||||
let alt_x = spriteinfo.alt_x.unwrap_or(0.0);
|
||||
let alt_y = spriteinfo.alt_y.unwrap_or(0.0);
|
||||
Some(SpriteInfo {
|
||||
id: spriteinfo.id.clone(),
|
||||
recolour: if let Some(colour) = spriteinfo.colour {
|
||||
colour
|
||||
} else {
|
||||
false
|
||||
},
|
||||
alt: spriteinfo.alt.clone(),
|
||||
offset: (x, y),
|
||||
alt_offset: (x, y),
|
||||
})
|
||||
} else {
|
||||
true
|
||||
None
|
||||
},
|
||||
fg: RGB::from_hex(&renderable.fg).expect("Invalid RGB"),
|
||||
bg: RGB::from_hex(&renderable.bg).expect("Invalid RGB"),
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use super::{
|
|||
Intrinsics,
|
||||
HasAncestry,
|
||||
HasClass,
|
||||
SpriteInfo,
|
||||
};
|
||||
use crate::gui::{ Ancestry, Class };
|
||||
use crate::consts::entity;
|
||||
|
|
@ -57,8 +58,7 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
|||
.with(BlocksTile {})
|
||||
.with(Renderable {
|
||||
glyph: to_cp437('@'),
|
||||
sprite: Some("@".to_string()), // TODO: Player sprite
|
||||
colour_sprite: true,
|
||||
sprite: Some(SpriteInfo::colourable("@")),
|
||||
fg: RGB::named(YELLOW),
|
||||
bg: RGB::named(BLACK),
|
||||
render_order: 0,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue