Added map marker

This commit is contained in:
Joshua Barretto 2021-05-01 16:26:13 +00:00 committed by Monty Marz
parent 4d09180ddb
commit d0953fcab0
9 changed files with 177 additions and 58 deletions

View File

@ -50,6 +50,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- You can now block and parry with melee weapons
- Lift is now calculated for gliders based on dimensions (currently same for all)
- Specific music tracks can now play exclusively in towns.
- Custom map markers can be placed now
### Changed

BIN
assets/voxygen/element/ui/generic/icons/m_click.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/ui/generic/icons/m_scroll.png (Stored with Git LFS) Normal file → Executable file

Binary file not shown.

BIN
assets/voxygen/element/ui/map/buttons/location_marker.png (Stored with Git LFS) Executable file

Binary file not shown.

View File

@ -21,7 +21,10 @@
"hud.map.difficulty_dungeon": "Dungeon\n\nDifficulty: {difficulty}",
"hud.map.drag": "Drag",
"hud.map.zoom": "Zoom",
"hud.map.mid_click": "Set Waypoint",
"hud.map.recenter": "Recenter",
"hud.map.marked_location": "Marked Location",
"hud.map.marked_location_remove": "Click to remove",
},

View File

@ -308,6 +308,7 @@ image_ids! {
m2_ico: "voxygen.element.ui.generic.icons.m2",
m_scroll_ico: "voxygen.element.ui.generic.icons.m_scroll",
m_move_ico: "voxygen.element.ui.generic.icons.m_move",
m_click_ico: "voxygen.element.ui.generic.icons.m_click",
skillbar_slot: "voxygen.element.ui.skillbar.slot",
// Other Icons/Art
@ -337,6 +338,7 @@ image_ids! {
indicator_group: "voxygen.element.ui.map.buttons.group_indicator",
indicator_group_up: "voxygen.element.ui.map.buttons.group_indicator_arrow_up",
indicator_group_down: "voxygen.element.ui.map.buttons.group_indicator_arrow_down",
location_marker: "voxygen.element.ui.map.buttons.location_marker",
map_mode_overlay: "voxygen.element.ui.map.buttons.map_modes",
// MiniMap

View File

@ -1,7 +1,7 @@
use super::{
img_ids::{Imgs, ImgsRot},
QUALITY_COMMON, QUALITY_DEBUG, QUALITY_EPIC, QUALITY_HIGH, QUALITY_LOW, QUALITY_MODERATE,
TEXT_COLOR, TEXT_GRAY_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
Show, QUALITY_COMMON, QUALITY_DEBUG, QUALITY_EPIC, QUALITY_HIGH, QUALITY_LOW, QUALITY_MODERATE,
TEXT_COLOR, TEXT_GRAY_COLOR, TEXT_VELORITE, UI_HIGHLIGHT_0, UI_MAIN,
};
use crate::{
i18n::Localization,
@ -40,6 +40,7 @@ widget_ids! {
site_difs[],
member_indicators[],
member_height_indicators[],
location_marker,
map_settings_align,
show_towns_img,
show_towns_box,
@ -64,6 +65,8 @@ widget_ids! {
drag_ico,
zoom_txt,
zoom_ico,
waypoint_ico,
waypoint_txt,
map_mode_btn,
map_mode_overlay,
}
@ -73,6 +76,7 @@ const SHOW_ECONOMY: bool = false; // turn this display off (for 0.9) until we ha
#[derive(WidgetCommon)]
pub struct Map<'a> {
show: &'a Show,
client: &'a Client,
world_map: &'a (Vec<img_ids::Rotations>, Vec2<u32>),
imgs: &'a Imgs,
@ -84,10 +88,12 @@ pub struct Map<'a> {
global_state: &'a GlobalState,
rot_imgs: &'a ImgsRot,
tooltip_manager: &'a mut TooltipManager,
location_marker: Option<Vec2<f32>>,
}
impl<'a> Map<'a> {
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
pub fn new(
show: &'a Show,
client: &'a Client,
imgs: &'a Imgs,
rot_imgs: &'a ImgsRot,
@ -97,8 +103,10 @@ impl<'a> Map<'a> {
localized_strings: &'a Localization,
global_state: &'a GlobalState,
tooltip_manager: &'a mut TooltipManager,
location_marker: Option<Vec2<f32>>,
) -> Self {
Self {
show,
imgs,
rot_imgs,
world_map,
@ -109,6 +117,7 @@ impl<'a> Map<'a> {
localized_strings,
global_state,
tooltip_manager,
location_marker,
}
}
}
@ -121,6 +130,8 @@ pub enum Event {
SettingsChange(InterfaceChange),
Close,
RequestSiteInfo(SiteId),
SetLocationMarker(Vec2<f32>),
ToggleMarker,
}
fn get_site_economy(site_rich: &SiteInfoRich) -> String {
@ -273,12 +284,6 @@ impl<'a> Widget for Map<'a> {
});
}
Image::new(self.imgs.map_frame_art)
.mid_top_with_margin_on(state.ids.map_align, 5.0)
.w_h(765.0, 765.0)
.parent(state.ids.bg)
.set(state.ids.map_layers[0], ui);
// Map Size
let worldsize = self.world_map.1;
@ -298,6 +303,7 @@ impl<'a> Widget for Map<'a> {
let w_src = max_zoom / zoom;
let h_src = max_zoom / zoom;
// Handle dragging
let drag = self.global_state.settings.interface.map_drag;
let dragged: Vec2<f64> = ui
@ -318,6 +324,20 @@ impl<'a> Widget for Map<'a> {
],
[w_src, h_src],
);
// Handle Location Marking
if let Some(click) = ui
.widget_input(state.ids.map_layers[0])
.clicks()
.middle()
.next()
{
events.push(Event::SetLocationMarker(
(Vec2::<f64>::from(click.xy) / map_size / zoom * max_zoom - drag)
.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e as f32 * sz as f32)
+ player_pos,
));
events.push(Event::ToggleMarker);
}
// X-Button
if Button::image(self.imgs.close_button)
.w_h(24.0, 25.0)
@ -333,14 +353,14 @@ impl<'a> Widget for Map<'a> {
// Map Layer Images
for (index, layer) in self.world_map.0.iter().enumerate() {
if index == 0 {
Image::new(layer.none)
Button::image(layer.none)
.mid_top_with_margin_on(state.ids.map_align, 10.0)
.w_h(map_size.x, map_size.y)
.parent(state.ids.bg)
.source_rectangle(rect_src)
.set(state.ids.map_layers[index], ui);
} else if show_topo_map {
Image::new(layer.none)
Button::image(layer.none)
.mid_top_with_margin_on(state.ids.map_align, 10.0)
.w_h(map_size.x, map_size.y)
.parent(state.ids.bg)
@ -587,10 +607,10 @@ impl<'a> Widget for Map<'a> {
.resize(self.client.sites().len(), &mut ui.widget_id_generator())
});
}
for (i, site_rich) in self.client.sites().values().enumerate() {
let site = &site_rich.site;
let wpos_to_rpos = |wpos: Vec2<f32>| {
// Site pos in world coordinates relative to the player
let rwpos = site.wpos.map(|e| e as f32) - player_pos;
let rwpos = wpos - player_pos;
// Convert to chunk coordinates
let rcpos = rwpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f32)
// Add map dragging
@ -600,14 +620,27 @@ impl<'a> Widget for Map<'a> {
// Convert to relative pixel coordinates from the center of the map
// Accounting for zooming
let rpos = rfpos.map2(map_size, |e, sz| e * sz as f32 * zoom as f32);
let rside = zoom * 6.0;
if rpos
.map2(map_size, |e, sz| e.abs() > sz as f32 / 2.0)
.reduce_or()
{
continue;
None
} else {
Some(rpos)
}
};
for (i, site_rich) in self.client.sites().values().enumerate() {
let site = &site_rich.site;
let rpos = match wpos_to_rpos(site.wpos.map(|e| e as f32)) {
Some(rpos) => rpos,
None => continue,
};
let rside = zoom * 6.0;
let title = site.name.as_deref().unwrap_or_else(|| match &site.kind {
SiteKind::Town => i18n.get("hud.map.town"),
SiteKind::Dungeon { .. } => i18n.get("hud.map.dungeon"),
@ -783,24 +816,11 @@ impl<'a> Widget for Map<'a> {
};
if let Some(member_pos) = member_pos {
// Site pos in world coordinates relative to the player
let rwpos = member_pos.0.xy().map(|e| e as f32) - player_pos;
// Convert to chunk coordinates
let rcpos = rwpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f32)
// Add map dragging
+ drag.map(|e| e as f32);
// Convert to fractional coordinates relative to the worldsize
let rfpos = rcpos / max_zoom as f32;
// Convert to relative pixel coordinates from the center of the map
// Accounting for zooming
let rpos = rfpos.map2(map_size, |e, sz| e * sz as f32 * zoom as f32);
let rpos = match wpos_to_rpos(member_pos.0.xy().map(|e| e as f32)) {
Some(rpos) => rpos,
None => continue,
};
if rpos
.map2(map_size, |e, sz| e.abs() > sz as f32 / 2.0)
.reduce_or()
{
continue;
}
let factor = 1.2;
let z_comparison = (member_pos.0.z - player_pos.z) as i32;
@ -820,6 +840,43 @@ impl<'a> Widget for Map<'a> {
.set(state.ids.member_indicators[i], ui);
}
}
// Location marker
if self.show.map_marker {
if let Some((lm, rpos)) = self
.location_marker
.and_then(|lm| Some(lm).zip(wpos_to_rpos(lm)))
{
let factor = 1.4;
if Button::image(self.imgs.location_marker)
.x_y_position_relative_to(
state.ids.map_layers[0],
position::Relative::Scalar(rpos.x as f64),
position::Relative::Scalar(rpos.y as f64 + 10.0 * factor),
)
.w_h(20.0 * factor, 20.0 * factor)
.floating(true)
.with_tooltip(
self.tooltip_manager,
i18n.get("hud.map.marked_location"),
&format!(
"X: {}, Y: {}\n\n{}",
lm.x as i32,
lm.y as i32,
i18n.get("hud.map.marked_location_remove")
),
&site_tooltip,
TEXT_VELORITE,
)
.set(state.ids.location_marker, ui)
.was_clicked()
{
events.push(Event::ToggleMarker);
}
}
}
// Cursor pos relative to playerpos and widget size
// Cursor stops moving on an axis as soon as it's position exceeds the maximum
// // size of the widget
@ -918,6 +975,18 @@ impl<'a> Widget for Map<'a> {
.graphics_for(state.ids.map_layers[0])
.color(TEXT_COLOR)
.set(state.ids.zoom_txt, ui);
Image::new(self.imgs.m_click_ico)
.right_from(state.ids.zoom_txt, 5.0)
.w_h(icon_size.x, icon_size.y)
.color(Some(UI_HIGHLIGHT_0))
.set(state.ids.waypoint_ico, ui);
Text::new(i18n.get("hud.map.mid_click"))
.right_from(state.ids.waypoint_ico, 5.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.graphics_for(state.ids.map_layers[0])
.color(TEXT_COLOR)
.set(state.ids.waypoint_txt, ui);
// Show topographic map
if Button::image(self.imgs.button)

View File

@ -1,6 +1,6 @@
use super::{
img_ids::{Imgs, ImgsRot},
QUALITY_COMMON, QUALITY_DEBUG, QUALITY_EPIC, QUALITY_HIGH, QUALITY_LOW, QUALITY_MODERATE,
Show, QUALITY_COMMON, QUALITY_DEBUG, QUALITY_EPIC, QUALITY_HIGH, QUALITY_LOW, QUALITY_MODERATE,
TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
};
use crate::{
@ -39,13 +39,14 @@ widget_ids! {
mmap_site_icons_bgs[],
mmap_site_icons[],
member_indicators[],
location_marker,
}
}
#[derive(WidgetCommon)]
pub struct MiniMap<'a> {
show: &'a Show,
client: &'a Client,
imgs: &'a Imgs,
rot_imgs: &'a ImgsRot,
world_map: &'a (Vec<img_ids::Rotations>, Vec2<u32>),
@ -54,10 +55,12 @@ pub struct MiniMap<'a> {
common: widget::CommonBuilder,
ori: Vec3<f32>,
global_state: &'a GlobalState,
location_marker: Option<Vec2<f32>>,
}
impl<'a> MiniMap<'a> {
pub fn new(
show: &'a Show,
client: &'a Client,
imgs: &'a Imgs,
rot_imgs: &'a ImgsRot,
@ -65,8 +68,10 @@ impl<'a> MiniMap<'a> {
fonts: &'a Fonts,
ori: Vec3<f32>,
global_state: &'a GlobalState,
location_marker: Option<Vec2<f32>>,
) -> Self {
Self {
show,
client,
imgs,
rot_imgs,
@ -75,6 +80,7 @@ impl<'a> MiniMap<'a> {
common: widget::CommonBuilder::default(),
ori,
global_state,
location_marker,
}
}
}
@ -289,10 +295,10 @@ impl<'a> Widget for MiniMap<'a> {
.resize(self.client.sites().len(), &mut ui.widget_id_generator())
});
}
for (i, site_rich) in self.client.sites().values().enumerate() {
let site = &site_rich.site;
let wpos_to_rpos = |wpos: Vec2<f32>, limit: bool| {
// Site pos in world coordinates relative to the player
let rwpos = site.wpos.map(|e| e as f32) - player_pos;
let rwpos = wpos - player_pos;
// Convert to chunk coordinates
let rcpos = rwpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f32);
// Convert to fractional coordinates relative to the worldsize
@ -308,8 +314,22 @@ impl<'a> Widget for MiniMap<'a> {
.map2(map_size, |e, sz| e.abs() > sz as f32 / 2.0)
.reduce_or()
{
continue;
limit.then(|| {
let clamped = rpos / rpos.map(|e| e.abs()).reduce_partial_max();
clamped * map_size.map(|e| e as f32) / 2.0
})
} else {
Some(rpos)
}
};
for (i, site_rich) in self.client.sites().values().enumerate() {
let site = &site_rich.site;
let rpos = match wpos_to_rpos(site.wpos.map(|e| e as f32), false) {
Some(rpos) => rpos,
None => continue,
};
Image::new(match &site.kind {
SiteKind::Town => self.imgs.mmap_site_town_bg,
@ -382,25 +402,11 @@ impl<'a> Widget for MiniMap<'a> {
let member_pos = entity.and_then(|entity| member_pos.get(entity));
if let Some(member_pos) = member_pos {
// Site pos in world coordinates relative to the player
let rwpos = member_pos.0.xy().map(|e| e as f32) - player_pos;
// Convert to chunk coordinates
let rcpos = rwpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f32);
// Convert to fractional coordinates relative to the worldsize
let rfpos = rcpos / max_zoom as f32;
// Convert to unrotated pixel coordinates from the player location on the map
// (the center)
// Accounting for zooming
let rpixpos = rfpos.map2(map_size, |e, sz| e * sz as f32 * zoom as f32);
let rpos = Vec2::unit_x().rotated_z(orientation.x) * rpixpos.x
+ Vec2::unit_y().rotated_z(orientation.x) * rpixpos.y;
let rpos = match wpos_to_rpos(member_pos.0.xy().map(|e| e as f32), false) {
Some(rpos) => rpos,
None => continue,
};
if rpos
.map2(map_size, |e, sz| e.abs() > sz as f32 / 2.0)
.reduce_or()
{
continue;
}
let factor = 1.2;
let z_comparison = (member_pos.0.z - player_pos.z) as i32;
Button::image(match z_comparison {
@ -419,6 +425,23 @@ impl<'a> Widget for MiniMap<'a> {
}
}
// Location marker
if self.show.map_marker {
if let Some(rpos) = self.location_marker.and_then(|lm| wpos_to_rpos(lm, true)) {
let factor = 1.2;
Button::image(self.imgs.location_marker)
.x_y_position_relative_to(
state.ids.map_layers[0],
position::Relative::Scalar(rpos.x as f64),
position::Relative::Scalar(rpos.y as f64 + 8.0 * factor),
)
.w_h(16.0 * factor, 16.0 * factor)
//.image_color(Color::Rgba(1.0, 1.0, 1.0, 1.0))
.floating(true)
.set(state.ids.location_marker, ui);
}
}
// Indicator
let ind_scale = 0.4;
let ind_rotation = if is_facing_north {

View File

@ -104,6 +104,7 @@ use std::{
use vek::*;
const TEXT_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
const TEXT_VELORITE: Color = Color::Rgba(0.0, 0.66, 0.66, 1.0);
const TEXT_GRAY_COLOR: Color = Color::Rgba(0.5, 0.5, 0.5, 1.0);
const TEXT_DULL_RED_COLOR: Color = Color::Rgba(0.56, 0.2, 0.2, 1.0);
const TEXT_BG: Color = Color::Rgba(0.0, 0.0, 0.0, 1.0);
@ -511,6 +512,8 @@ pub struct Show {
auto_walk: bool,
camera_clamp: bool,
prompt_dialog: Option<PromptDialogSettings>,
location_marker: Option<Vec2<f32>>,
map_marker: bool,
}
impl Show {
fn bag(&mut self, open: bool) {
@ -876,6 +879,8 @@ impl Hud {
auto_walk: false,
camera_clamp: false,
prompt_dialog: None,
location_marker: None,
map_marker: false,
},
to_focus: None,
//never_show: false,
@ -2289,6 +2294,7 @@ impl Hud {
// MiniMap
for event in MiniMap::new(
&self.show,
client,
&self.imgs,
&self.rot_imgs,
@ -2296,6 +2302,7 @@ impl Hud {
&self.fonts,
camera.get_orientation(),
&global_state,
self.show.location_marker,
)
.set(self.ids.minimap, ui_widgets)
{
@ -2725,6 +2732,7 @@ impl Hud {
// Map
if self.show.map {
for event in Map::new(
&self.show,
client,
&self.imgs,
&self.rot_imgs,
@ -2734,6 +2742,7 @@ impl Hud {
i18n,
&global_state,
tooltip_manager,
self.show.location_marker,
)
.set(self.ids.map, ui_widgets)
{
@ -2749,6 +2758,12 @@ impl Hud {
map::Event::RequestSiteInfo(id) => {
events.push(Event::RequestSiteInfo(id));
},
map::Event::SetLocationMarker(pos) => {
self.show.location_marker = Some(pos);
},
map::Event::ToggleMarker => {
self.show.map_marker = !self.show.map_marker;
},
}
}
} else {