sprites for entities, with text glyph fallback
This commit is contained in:
parent
2c4b4ca143
commit
d6ba6c628c
17 changed files with 1486 additions and 1397 deletions
|
|
@ -168,7 +168,7 @@ pub fn render_camera(ecs: &World, ctx: &mut BTerm) {
|
|||
}
|
||||
}
|
||||
if draw {
|
||||
if let Some(sprite) = render.sprite {
|
||||
/* if let Some(sprite) = render.sprite {
|
||||
ctx.set_active_console(0);
|
||||
ctx.add_sprite(
|
||||
Rect::with_size(
|
||||
|
|
@ -182,7 +182,7 @@ pub fn render_camera(ecs: &World, ctx: &mut BTerm) {
|
|||
sprite
|
||||
);
|
||||
ctx.set_active_console(ENTITY_LAYER);
|
||||
} else {
|
||||
} else */ {
|
||||
ctx.set(
|
||||
entity_offset_x + bounds.x_offset,
|
||||
entity_offset_y + bounds.y_offset,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ pub struct OtherLevelPosition {
|
|||
#[derive(Component, ConvertSaveload, Clone)]
|
||||
pub struct Renderable {
|
||||
pub glyph: FontCharType,
|
||||
pub sprite: Option<usize>,
|
||||
pub sprite: Option<String>,
|
||||
pub colour_sprite: bool,
|
||||
pub fg: RGB,
|
||||
pub bg: RGB,
|
||||
pub render_order: i32,
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ pub fn render(draw: bool, gfx: &mut Graphics, font: ¬an::draw::Font) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Render with specific params.
|
||||
/// Render with specificied params.
|
||||
pub fn render_log(gfx: &mut Graphics, font: ¬an::draw::Font, pos: &(f32, f32), width: f32) {
|
||||
let mut text = gfx.create_text();
|
||||
let log = LOG.lock().unwrap();
|
||||
let latest: Vec<_> = log.iter().rev().take(5).collect();
|
||||
let mut init = false;
|
||||
let mut initialised = false;
|
||||
let mut y = pos.1;
|
||||
for (_, entries) in latest {
|
||||
let mut written_on_line = false;
|
||||
|
|
@ -37,14 +37,14 @@ pub fn render_log(gfx: &mut Graphics, font: ¬an::draw::Font, pos: &(f32, f32)
|
|||
.color(Color::from_rgb(frag.colour.r, frag.colour.g, frag.colour.b))
|
||||
.v_align_bottom();
|
||||
written_on_line = true;
|
||||
init = true;
|
||||
initialised = true;
|
||||
} else {
|
||||
text.chain(&frag.text)
|
||||
.color(Color::from_rgb(frag.colour.r, frag.colour.g, frag.colour.b))
|
||||
.size(FONTSIZE);
|
||||
}
|
||||
}
|
||||
if init {
|
||||
if initialised {
|
||||
y = text.last_bounds().min_y();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,6 +275,7 @@ 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,
|
||||
|
|
@ -287,6 +288,7 @@ 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,
|
||||
|
|
@ -313,6 +315,7 @@ 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,
|
||||
|
|
|
|||
101
src/main.rs
101
src/main.rs
|
|
@ -253,34 +253,82 @@ fn draw_camera(
|
|||
}
|
||||
// TODO: Use sprites here, not text drawing. Put bitmap font into atlas.
|
||||
let renderable = renderables.get(entry.1.e).unwrap();
|
||||
draw.text(
|
||||
&font,
|
||||
&format!("{}", bracket_lib::terminal::to_char(renderable.glyph as u8))
|
||||
)
|
||||
.position(
|
||||
((entry.0.x as f32) + 0.5) * TILESIZE,
|
||||
((entry.0.y as f32) + 0.5) * TILESIZE
|
||||
if let Some(sprite_id) = &renderable.sprite {
|
||||
let sprite = if let Some(sprite) = atlas.get(sprite_id) {
|
||||
sprite
|
||||
} else {
|
||||
panic!("No entity sprite found for ID: {}", sprite_id);
|
||||
};
|
||||
draw.image(sprite)
|
||||
.position((entry.0.x as f32) * TILESIZE, (entry.0.y as f32) * TILESIZE)
|
||||
.color(
|
||||
if renderable.colour_sprite {
|
||||
Color::from_rgb(
|
||||
renderable.fg.r,
|
||||
renderable.fg.g,
|
||||
renderable.fg.b
|
||||
)
|
||||
} else {
|
||||
Color::WHITE
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// Fallback to drawing text.
|
||||
draw.text(
|
||||
&font,
|
||||
&format!("{}", bracket_lib::terminal::to_char(renderable.glyph as u8))
|
||||
)
|
||||
.color(Color::from_rgb(renderable.fg.r, renderable.fg.g, renderable.fg.b))
|
||||
.size(FONTSIZE)
|
||||
.h_align_center()
|
||||
.v_align_middle();
|
||||
// Draw entity
|
||||
.position(
|
||||
((entry.0.x as f32) + 0.5) * TILESIZE,
|
||||
((entry.0.y as f32) + 0.5) * TILESIZE
|
||||
)
|
||||
.color(
|
||||
Color::from_rgb(renderable.fg.r, renderable.fg.g, renderable.fg.b)
|
||||
)
|
||||
.size(FONTSIZE)
|
||||
.h_align_center()
|
||||
.v_align_middle();
|
||||
}
|
||||
}
|
||||
DrawType::VisibleAndRemember => {
|
||||
// TODO: PUT THIS INTO A FUNCTION!
|
||||
let renderable = renderables.get(entry.1.e).unwrap();
|
||||
draw.text(
|
||||
&font,
|
||||
&format!("{}", bracket_lib::terminal::to_char(renderable.glyph as u8))
|
||||
)
|
||||
.position(
|
||||
((entry.0.x as f32) + 0.5) * TILESIZE,
|
||||
((entry.0.y as f32) + 0.5) * TILESIZE
|
||||
if let Some(sprite_id) = &renderable.sprite {
|
||||
let sprite = if let Some(sprite) = atlas.get(sprite_id) {
|
||||
sprite
|
||||
} else {
|
||||
panic!("No entity sprite found for ID: {}", sprite_id);
|
||||
};
|
||||
draw.image(sprite)
|
||||
.position((entry.0.x as f32) * TILESIZE, (entry.0.y as f32) * TILESIZE)
|
||||
.color(
|
||||
if renderable.colour_sprite {
|
||||
Color::from_rgb(
|
||||
renderable.fg.r,
|
||||
renderable.fg.g,
|
||||
renderable.fg.b
|
||||
)
|
||||
} else {
|
||||
Color::WHITE
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// Fallback to drawing text.
|
||||
draw.text(
|
||||
&font,
|
||||
&format!("{}", bracket_lib::terminal::to_char(renderable.glyph as u8))
|
||||
)
|
||||
.color(Color::from_rgb(renderable.fg.r, renderable.fg.g, renderable.fg.b))
|
||||
.size(FONTSIZE)
|
||||
.h_align_center()
|
||||
.v_align_middle();
|
||||
.position(
|
||||
((entry.0.x as f32) + 0.5) * TILESIZE,
|
||||
((entry.0.y as f32) + 0.5) * TILESIZE
|
||||
)
|
||||
.color(
|
||||
Color::from_rgb(renderable.fg.r, renderable.fg.g, renderable.fg.b)
|
||||
)
|
||||
.size(FONTSIZE)
|
||||
.h_align_center()
|
||||
.v_align_middle();
|
||||
}
|
||||
// TODO: Update map memory.
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -318,7 +366,12 @@ fn render_map_in_view(
|
|||
&*map,
|
||||
Some(*ecs.fetch::<Point>())
|
||||
);
|
||||
draw.image(atlas.get(id).unwrap())
|
||||
let sprite = if let Some(sprite) = atlas.get(id) {
|
||||
sprite
|
||||
} else {
|
||||
panic!("No sprite found for ID: {}", id);
|
||||
};
|
||||
draw.image(sprite)
|
||||
.position(
|
||||
((x + bounds.x_offset) as f32) * TILESIZE,
|
||||
((y + bounds.y_offset) as f32) * TILESIZE
|
||||
|
|
|
|||
|
|
@ -7,14 +7,11 @@ use std::ops::{ Add, Mul };
|
|||
use notan::prelude::*;
|
||||
|
||||
pub fn get_sprite_for_id(idx: usize, map: &Map, other_pos: Option<Point>) -> (&str, Color) {
|
||||
let x = (idx as i32) % map.width;
|
||||
let y = (idx as i32) / map.width;
|
||||
let sprite = map.tiles[idx].sprite();
|
||||
/*let base = match tile {
|
||||
TileType::Wall => wall_sprite(tile.sprite(), map, x, y),
|
||||
_ => tile.sprite(),
|
||||
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),
|
||||
_ => map.tiles[idx].sprite(false, f),
|
||||
};
|
||||
let sprite_id = pick_variant(base, tile.variants(), idx, map);*/
|
||||
let tint = if !map.visible_tiles[idx] {
|
||||
Color::from_rgb(0.75, 0.75, 0.75)
|
||||
} else {
|
||||
|
|
@ -159,18 +156,13 @@ fn is_revealed_and_wall(map: &Map, x: i32, y: i32, debug: Option<bool>) -> bool
|
|||
(if debug.is_none() { map.revealed_tiles[idx] } else { true })
|
||||
}
|
||||
|
||||
fn wall_sprite(id: usize, map: &Map, x: i32, y: i32) -> usize {
|
||||
if y > map.height - (2 as i32) {
|
||||
return id;
|
||||
}
|
||||
fn check_if_base(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) {
|
||||
return id + 6;
|
||||
return false;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
fn pick_variant(base: usize, variants: usize, idx: usize, map: &Map) -> usize {
|
||||
return base + ((map.colour_offset[idx].0.0 * (variants as f32)) as usize);
|
||||
return true;
|
||||
}
|
||||
|
||||
fn wall_glyph(map: &Map, x: i32, y: i32, debug: Option<bool>) -> FontCharType {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use serde::{ Deserialize, Serialize };
|
||||
use crate::consts::sprites::*;
|
||||
use bracket_lib::random::RandomNumberGenerator;
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize, Debug)]
|
||||
pub enum TileType {
|
||||
|
|
@ -30,52 +30,84 @@ pub enum TileType {
|
|||
}
|
||||
|
||||
impl TileType {
|
||||
pub fn sprite(&self) -> &str {
|
||||
match self {
|
||||
TileType::ImpassableMountain => "statue_warrior",
|
||||
TileType::Wall => "wall_cave_h_a",
|
||||
TileType::DeepWater => "water",
|
||||
TileType::Fence => "wall_cave_h_a",
|
||||
TileType::Bars => "wall_cave_h_a",
|
||||
TileType::Floor => "floor_cobble_a",
|
||||
TileType::WoodFloor => "floor_wood_a",
|
||||
TileType::Gravel => "floor_cobble_b",
|
||||
TileType::Road => "floor_cobble_c",
|
||||
TileType::Grass => "floor_grass_a",
|
||||
TileType::Foliage => "floor_grass_b",
|
||||
TileType::HeavyFoliage => "floor_grass_c",
|
||||
TileType::Sand => "floor_cobble_c",
|
||||
TileType::ShallowWater => "water",
|
||||
TileType::Bridge => "floor_cobble_a",
|
||||
TileType::DownStair => "wall_cave_stair_down",
|
||||
TileType::UpStair => "wall_cave_stair_up",
|
||||
TileType::ToLocal(_) => "wall_crypt_stair_down",
|
||||
TileType::ToOvermap(_) => "wall_crypt_stair_up",
|
||||
pub fn sprite(&self, base: bool, float: f32) -> &str {
|
||||
if base {
|
||||
return self.h(float);
|
||||
}
|
||||
return self.v(float);
|
||||
}
|
||||
|
||||
pub fn variants(&self) -> usize {
|
||||
match self {
|
||||
TileType::ImpassableMountain => 1,
|
||||
TileType::Wall => 4,
|
||||
TileType::DeepWater => 2,
|
||||
TileType::Fence => 1,
|
||||
TileType::Bars => 1,
|
||||
TileType::Floor => 6,
|
||||
TileType::WoodFloor => 3,
|
||||
TileType::Gravel => 1,
|
||||
TileType::Road => 4,
|
||||
TileType::Grass => 6,
|
||||
TileType::Foliage => 1,
|
||||
TileType::HeavyFoliage => 1,
|
||||
TileType::Sand => 1,
|
||||
TileType::ShallowWater => 2,
|
||||
TileType::Bridge => 1,
|
||||
TileType::DownStair => 1,
|
||||
TileType::UpStair => 1,
|
||||
TileType::ToLocal(_) => 1,
|
||||
TileType::ToOvermap(_) => 1,
|
||||
}
|
||||
fn h(&self, float: f32) -> &str {
|
||||
let options = match self {
|
||||
TileType::Wall =>
|
||||
vec![
|
||||
"wall_cave_h_a",
|
||||
"wall_cave_h_b",
|
||||
"wall_cave_h_c",
|
||||
"wall_cave_h_d",
|
||||
"wall_cave_h_crack"
|
||||
],
|
||||
_ => unreachable!("Tried to get a h (base) sprite for a non-wall tile."),
|
||||
};
|
||||
return options[(float * (options.len() as f32)) as usize];
|
||||
}
|
||||
fn v(&self, float: f32) -> &str {
|
||||
let options = match self {
|
||||
TileType::ImpassableMountain => vec!["statue_warrior"],
|
||||
TileType::Wall =>
|
||||
vec![
|
||||
"wall_cave_v_a",
|
||||
"wall_cave_v_b",
|
||||
"wall_cave_v_c",
|
||||
"wall_cave_v_d",
|
||||
"wall_cave_v_crack"
|
||||
],
|
||||
TileType::DeepWater => vec!["water", "water_a1", "water_a2"],
|
||||
TileType::Fence => vec!["wall_cave_h_a"],
|
||||
TileType::Bars => vec!["wall_cave_h_a"],
|
||||
TileType::Floor =>
|
||||
vec![
|
||||
"floor_cobble_a",
|
||||
"floor_cobble_b",
|
||||
"floor_cobble_c",
|
||||
"floor_cobble_d",
|
||||
"floor_cobble_e",
|
||||
"floor_cobble_f"
|
||||
],
|
||||
TileType::WoodFloor =>
|
||||
vec!["floor_wood_a", "floor_wood_b", "floor_wood_c", "floor_wood_d"],
|
||||
TileType::Gravel => vec!["floor_cobble_b"],
|
||||
TileType::Road =>
|
||||
vec![
|
||||
"floor_tile_a",
|
||||
"floor_tile_b",
|
||||
"floor_tile_c",
|
||||
"floor_tile_d",
|
||||
"floor_mossy_a",
|
||||
"floor_mossy_b",
|
||||
"floor_mossy_c",
|
||||
"floor_mossy_d",
|
||||
"floor_mossy_e"
|
||||
],
|
||||
TileType::Grass =>
|
||||
vec![
|
||||
"floor_grass_a",
|
||||
"floor_grass_b",
|
||||
"floor_grass_c",
|
||||
"floor_grass_d",
|
||||
"floor_grass_e",
|
||||
"floor_grass_f"
|
||||
],
|
||||
TileType::Foliage => vec!["floor_grass_b"],
|
||||
TileType::HeavyFoliage => vec!["floor_grass_c"],
|
||||
TileType::Sand => vec!["floor_cobble_c"],
|
||||
TileType::ShallowWater => vec!["water"],
|
||||
TileType::Bridge => vec!["floor_cobble_a"],
|
||||
TileType::DownStair => vec!["wall_cave_stair_down"],
|
||||
TileType::UpStair => vec!["wall_cave_stair_up"],
|
||||
TileType::ToLocal(_) => vec!["wall_crypt_stair_down"],
|
||||
TileType::ToOvermap(_) => vec!["wall_crypt_stair_up"],
|
||||
};
|
||||
return options[(float * (options.len() as f32)) as usize];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ 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,6 +310,7 @@ impl<'a> System<'a> for ParticleSpawnSystem {
|
|||
renderables
|
||||
.insert(p, Renderable {
|
||||
sprite: None, // TODO: Particle sprite
|
||||
colour_sprite: false,
|
||||
fg: new_particle.fg,
|
||||
bg: new_particle.bg,
|
||||
glyph: new_particle.glyph,
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState {
|
|||
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(17); // TODO: Enum
|
||||
render_data.sprite = Some("door_wood_h_closed".to_string()); // TODO: Enum
|
||||
door_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y));
|
||||
}
|
||||
result = RunState::Ticking;
|
||||
|
|
@ -234,7 +234,7 @@ pub fn open(i: i32, j: i32, ecs: &mut World) -> RunState {
|
|||
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(18); // TODO: Enum
|
||||
render_data.sprite = Some("door_wood_h_open".to_string()); // TODO: Enum
|
||||
door_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y));
|
||||
}
|
||||
result = RunState::Ticking;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ pub struct Equippable {
|
|||
#[derive(Deserialize, Debug)]
|
||||
pub struct Renderable {
|
||||
pub glyph: String,
|
||||
pub sprite: Option<usize>,
|
||||
pub sprite: Option<String>,
|
||||
pub colour_sprite: Option<bool>,
|
||||
pub fg: String,
|
||||
pub bg: String,
|
||||
pub order: i32,
|
||||
|
|
|
|||
|
|
@ -691,10 +691,11 @@ fn get_renderable_component(
|
|||
) -> crate::components::Renderable {
|
||||
crate::components::Renderable {
|
||||
glyph: to_cp437(renderable.glyph.chars().next().unwrap()),
|
||||
sprite: if let Some(sprite) = &renderable.sprite {
|
||||
Some(sprite.clone())
|
||||
sprite: renderable.sprite.clone(),
|
||||
colour_sprite: if renderable.colour_sprite.is_some() {
|
||||
renderable.colour_sprite.clone().unwrap()
|
||||
} else {
|
||||
None
|
||||
true
|
||||
},
|
||||
fg: RGB::from_hex(&renderable.fg).expect("Invalid RGB"),
|
||||
bg: RGB::from_hex(&renderable.bg).expect("Invalid RGB"),
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
|||
.with(BlocksTile {})
|
||||
.with(Renderable {
|
||||
glyph: to_cp437('@'),
|
||||
sprite: None, // TODO: Player sprite
|
||||
sprite: Some("@".to_string()), // TODO: Player sprite
|
||||
colour_sprite: true,
|
||||
fg: RGB::named(YELLOW),
|
||||
bg: RGB::named(BLACK),
|
||||
render_order: 0,
|
||||
|
|
|
|||
|
|
@ -362,7 +362,10 @@ impl State {
|
|||
)
|
||||
);
|
||||
self.mapgen_timer += ctx.timer.delta_f32();
|
||||
if self.mapgen_timer > 10.0 / (self.mapgen_history.len() as f32) {
|
||||
if
|
||||
self.mapgen_timer > 10.0 / (self.mapgen_history.len() as f32) ||
|
||||
self.mapgen_timer > 1.0
|
||||
{
|
||||
self.mapgen_timer = 0.0;
|
||||
self.mapgen_index += 1;
|
||||
if self.mapgen_index >= self.mapgen_history.len() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue