feat: ivpeek ui
parent
ffbcea507b
commit
baf64181ec
|
|
@ -1,4 +1,8 @@
|
|||
use std::collections::HashMap;
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use bevy::prelude::*;
|
||||
use json::JsonValue;
|
||||
|
|
@ -49,3 +53,17 @@ fn database_setup(
|
|||
pokemon_database.populate_from_json(&read_pokedex());
|
||||
characteristic_database.populate_from_json(&read_characteristics());
|
||||
}
|
||||
|
||||
pub fn load_url_asset(
|
||||
url: String,
|
||||
path: PathBuf,
|
||||
assets: &Res<AssetServer>,
|
||||
) -> Result<Handle<Image>, Box<dyn std::error::Error>> {
|
||||
let system_path = Path::new("assets").join(&path);
|
||||
if Path::exists(&path) {
|
||||
return Ok(assets.load(path));
|
||||
}
|
||||
let data = reqwest::blocking::get(&url)?.bytes()?;
|
||||
fs::write(&system_path, data).unwrap();
|
||||
Ok(assets.load(path))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_egui::EguiContexts;
|
||||
|
||||
|
|
@ -112,17 +107,3 @@ fn request_handler(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_url_asset(
|
||||
url: String,
|
||||
path: PathBuf,
|
||||
assets: &Res<AssetServer>,
|
||||
) -> Result<Handle<Image>, Box<dyn std::error::Error>> {
|
||||
let system_path = Path::new("assets").join(&path);
|
||||
if Path::exists(&path) {
|
||||
return Ok(assets.load(path));
|
||||
}
|
||||
let data = reqwest::blocking::get(&url)?.bytes()?;
|
||||
fs::write(&system_path, data).unwrap();
|
||||
Ok(assets.load(path))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ pub fn run() {
|
|||
.set(ImagePlugin::default_nearest()),
|
||||
)
|
||||
.add_plugin(crate::database::DatabasePlugin)
|
||||
.add_plugin(inspector::InspectorPlugin)
|
||||
.add_plugin(ui::UiPlugin)
|
||||
.run()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,22 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_egui::EguiContexts;
|
||||
|
||||
use crate::pokemon::*;
|
||||
use crate::{
|
||||
database::{load_url_asset, Database},
|
||||
pokemon::*,
|
||||
};
|
||||
|
||||
use super::ui::UiAssets;
|
||||
|
||||
pub struct InspectorPlugin;
|
||||
|
||||
impl Plugin for InspectorPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.insert_resource(Inspector::default());
|
||||
app.insert_resource(Inspector::default())
|
||||
.add_system(state_changed)
|
||||
.add_startup_system(test_init);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -32,3 +40,68 @@ pub struct PokemonInstance {
|
|||
pub ivs: HashMap<BaseStat, u8>,
|
||||
pub evs: HashMap<BaseStat, u8>,
|
||||
}
|
||||
|
||||
fn test_init(mut inspector: ResMut<Inspector>, pokemon_database: Res<Database<Pokemon>>) {
|
||||
for name in vec![
|
||||
"baltoy",
|
||||
"claydol",
|
||||
"regirock",
|
||||
"flygon",
|
||||
"shuckle",
|
||||
"swampert",
|
||||
"forretress",
|
||||
"shedinja",
|
||||
"blissey",
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
inspector.enemies.push(PokemonInstance {
|
||||
pokemon: pokemon_database.map.get(*name).unwrap().clone(),
|
||||
ivs: {
|
||||
let mut result = HashMap::new();
|
||||
for stat in BaseStat::all().iter() {
|
||||
result.insert(
|
||||
*stat,
|
||||
match stat {
|
||||
BaseStat::Hp => 31,
|
||||
BaseStat::Attack => 27,
|
||||
BaseStat::Defense => 26,
|
||||
BaseStat::SpecialAttack => 0,
|
||||
BaseStat::SpecialDefense => 21,
|
||||
BaseStat::Speed => 15,
|
||||
},
|
||||
);
|
||||
}
|
||||
result
|
||||
},
|
||||
..default()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn state_changed(
|
||||
inspector: Res<Inspector>,
|
||||
assets: Res<AssetServer>,
|
||||
mut ui_assets: ResMut<UiAssets>,
|
||||
mut contexts: EguiContexts,
|
||||
) {
|
||||
if inspector.is_changed() {
|
||||
for instance in inspector.enemies.iter().chain(inspector.allies.iter()) {
|
||||
let pokemon = instance.pokemon.clone();
|
||||
|
||||
if !ui_assets.sprite_map.contains_key(&pokemon.key()) {
|
||||
let handle = load_url_asset(
|
||||
pokemon.sprite_url(),
|
||||
format!("cache/{name}.png", name = pokemon.key()).into(),
|
||||
&assets,
|
||||
);
|
||||
if let Ok(handle) = handle {
|
||||
let weak = handle.clone_weak();
|
||||
ui_assets
|
||||
.sprite_map
|
||||
.insert(pokemon.key(), (handle, contexts.add_image(weak)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
201
src/ivpeek/ui.rs
201
src/ivpeek/ui.rs
|
|
@ -3,14 +3,14 @@ use bevy_egui::{egui, EguiContexts, EguiPlugin};
|
|||
use lazy_static::lazy_static;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{database::Database, pokemon::*};
|
||||
use crate::pokemon::*;
|
||||
|
||||
use super::inspector::{Inspector, PokemonInstance};
|
||||
use super::inspector::Inspector;
|
||||
|
||||
const BAR_HEIGHT: f32 = 12.0;
|
||||
const BASE_STAT_WIDTH_MULT: f32 = 1.0;
|
||||
const BASE_STAT_WIDTH_MULT: f32 = 0.8;
|
||||
const IV_WIDTH_MULT: f32 = 4.0;
|
||||
const EV_WIDTH_MULT: f32 = 1.0;
|
||||
// const EV_WIDTH_MULT: f32 = 1.0;
|
||||
|
||||
lazy_static! {
|
||||
static ref BASE_STAT_COLOR_RANGES: Vec<(u8, egui::Color32)> = vec![
|
||||
|
|
@ -33,10 +33,10 @@ lazy_static! {
|
|||
25.0, // Base stat
|
||||
255.0 * BASE_STAT_WIDTH_MULT, // Base stat bar
|
||||
60.0, // Stat name
|
||||
40.0, // IV value
|
||||
25.0, // IV value
|
||||
32.0 * IV_WIDTH_MULT, // IV bar
|
||||
40.0, // EV value
|
||||
255.0 * EV_WIDTH_MULT, // EV bar
|
||||
// 40.0, // EV value
|
||||
// 255.0 * EV_WIDTH_MULT, // EV bar
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -45,21 +45,12 @@ pub struct UiPlugin;
|
|||
impl Plugin for UiPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_plugin(EguiPlugin)
|
||||
.insert_resource(Inspector::default())
|
||||
.insert_resource(UiAssets::default())
|
||||
.add_startup_system(load_assets)
|
||||
.add_system(ui_system)
|
||||
.add_startup_system(test_init);
|
||||
.add_system(ui_system);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_init(mut inspector: ResMut<Inspector>, pokemon_database: Res<Database<Pokemon>>) {
|
||||
inspector.enemies.push(PokemonInstance {
|
||||
pokemon: pokemon_database.map.get("baltoy").unwrap().clone(),
|
||||
..default()
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
pub struct UiAssets {
|
||||
pub bar_handle: Handle<Image>,
|
||||
|
|
@ -84,20 +75,163 @@ fn ui_system(
|
|||
|
||||
egui::CentralPanel::default().show(contexts.ctx_mut(), |ui| {
|
||||
let sprite_size = egui::Vec2::new(128., 128.);
|
||||
for instance in inspector.enemies.iter().chain(inspector.allies.iter()) {
|
||||
let pokemon = instance.pokemon.clone();
|
||||
|
||||
// Sprite
|
||||
ui.horizontal(|ui| {
|
||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||
for instance in inspector.enemies.iter().chain(inspector.allies.iter()) {
|
||||
let pokemon = instance.pokemon.clone();
|
||||
let nature = instance.nature.clone();
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_min_size(sprite_size);
|
||||
if let Some((_, rendered_texture_id)) = ui_assets.sprite_map.get(&pokemon.key())
|
||||
{
|
||||
ui.add(egui::Image::new(*rendered_texture_id, sprite_size));
|
||||
}
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_min_width(sprite_size.x + 32.);
|
||||
ui.set_max_width(sprite_size.x + 32.);
|
||||
// Name
|
||||
ui.label(
|
||||
egui::RichText::new(&pokemon.full_name)
|
||||
.color(egui::Color32::LIGHT_GRAY),
|
||||
);
|
||||
|
||||
// Types
|
||||
ui.label(format!(
|
||||
"{} / {}",
|
||||
pokemon.type1.as_ref().map_or("-", |t| t.name.as_str()),
|
||||
pokemon.type2.as_ref().map_or("-", |t| t.name.as_str())
|
||||
));
|
||||
});
|
||||
|
||||
// Headings
|
||||
ui.horizontal(|ui| {
|
||||
for (i, width) in COLUMNS.iter().enumerate() {
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_width(*width);
|
||||
match i {
|
||||
1 => {
|
||||
ui.label(egui::RichText::new("Base stat"));
|
||||
}
|
||||
3 => {
|
||||
ui.label(egui::RichText::new("IV"));
|
||||
}
|
||||
4 => {
|
||||
ui.label(egui::RichText::new("IV range"));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
// Sprite
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_min_size(sprite_size);
|
||||
ui.set_max_size(sprite_size);
|
||||
if let Some((_, rendered_texture_id)) =
|
||||
ui_assets.sprite_map.get(&pokemon.key())
|
||||
{
|
||||
ui.add(egui::Image::new(*rendered_texture_id, sprite_size));
|
||||
}
|
||||
});
|
||||
|
||||
ui.add_space(32.);
|
||||
|
||||
ui.vertical(|ui| {
|
||||
for stat in BaseStat::all() {
|
||||
ui.horizontal(|ui| {
|
||||
let mut column_size = COLUMNS.iter();
|
||||
|
||||
// Base stat number
|
||||
ui.horizontal(|ui| {
|
||||
if let Some(width) = column_size.next() {
|
||||
ui.set_width(*width);
|
||||
}
|
||||
let base_stat = &pokemon.base_value(stat).to_string();
|
||||
ui.label(egui::RichText::new(base_stat));
|
||||
});
|
||||
|
||||
// Base stat bar
|
||||
ui.horizontal(|ui| {
|
||||
if let Some(width) = column_size.next() {
|
||||
ui.set_width(*width);
|
||||
}
|
||||
let base_value = pokemon.base_value(stat);
|
||||
let bar_length = base_value as f32 * BASE_STAT_WIDTH_MULT;
|
||||
let color = base_stat_color(base_value);
|
||||
|
||||
let image = egui::Image::new(
|
||||
*rendered_texture_id,
|
||||
[bar_length, BAR_HEIGHT],
|
||||
)
|
||||
.tint(color);
|
||||
ui.add(image);
|
||||
});
|
||||
|
||||
// Stat name
|
||||
ui.horizontal(|ui| {
|
||||
if let Some(width) = column_size.next() {
|
||||
ui.set_width(*width);
|
||||
}
|
||||
ui.label(
|
||||
egui::RichText::new(format!("{stat}"))
|
||||
.color(nature_color(stat, nature.as_ref())),
|
||||
);
|
||||
});
|
||||
|
||||
// IV stat
|
||||
ui.horizontal(|ui| {
|
||||
if let Some(width) = column_size.next() {
|
||||
ui.set_width(*width);
|
||||
}
|
||||
if let Some(iv) = instance.ivs.get(&stat) {
|
||||
ui.label(
|
||||
egui::RichText::new(format!("{iv}"))
|
||||
.color(iv_color(*iv)),
|
||||
);
|
||||
} else {
|
||||
ui.label("-");
|
||||
}
|
||||
});
|
||||
|
||||
// IV stat bar
|
||||
ui.horizontal(|ui| {
|
||||
if let Some(width) = column_size.next() {
|
||||
ui.set_width(*width);
|
||||
}
|
||||
if let Some(iv) = instance.ivs.get(&stat) {
|
||||
let bar_length = *iv as f32 * IV_WIDTH_MULT;
|
||||
let track_length = 31. * IV_WIDTH_MULT - bar_length;
|
||||
let color = iv_color(*iv);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.spacing_mut().item_spacing = egui::Vec2::ZERO;
|
||||
|
||||
// Bar
|
||||
ui.add(
|
||||
egui::Image::new(
|
||||
*rendered_texture_id,
|
||||
[bar_length, BAR_HEIGHT],
|
||||
)
|
||||
.tint(color),
|
||||
);
|
||||
// Track
|
||||
ui.add(
|
||||
egui::Image::new(
|
||||
*rendered_texture_id,
|
||||
[track_length, BAR_HEIGHT],
|
||||
)
|
||||
.tint(egui::Color32::from_rgb(64, 64, 64)),
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -115,6 +249,17 @@ fn nature_color(stat: BaseStat, nature: Option<&Nature>) -> egui::Color32 {
|
|||
}
|
||||
}
|
||||
|
||||
fn base_stat_color(base_stat: u8) -> egui::Color32 {
|
||||
for (treshold, color) in BASE_STAT_COLOR_RANGES.iter().rev() {
|
||||
if base_stat >= *treshold {
|
||||
return color.clone();
|
||||
}
|
||||
}
|
||||
BASE_STAT_COLOR_RANGES
|
||||
.first()
|
||||
.map_or(egui::Color32::LIGHT_GRAY, |(_, color)| color.clone())
|
||||
}
|
||||
|
||||
fn iv_color(iv: u8) -> egui::Color32 {
|
||||
for (treshold, color) in IV_COLOR_RANGES.iter().rev() {
|
||||
if iv >= *treshold {
|
||||
|
|
|
|||
Loading…
Reference in New Issue