-
-
Notifications
You must be signed in to change notification settings - Fork 380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/radar improvements #5984
base: master
Are you sure you want to change the base?
Feat/radar improvements #5984
Conversation
Commit 678d46e added crossfading, but accidentally swapped two parameters when invoking "PlayMusic()".
Ensure that a targeted object will always remain visible on the radar when switching from automatic to manual zoom.
Instead of increasing/decreasing the manual zoom level by powers of 10, use a semi-logarithmic scale of 1,2,5,10... when manually zooming in or out.
The 2D radar is trivial as it is a circle, but the 3D scanner is an ellipse. For now we check if the mouse is in a rectangle surrounding the scanner, which is an improvement but not a complete fix. TODO: if the mouse leaves the radar area while the popup for selecting between the radar modes is displayed, the popup disappears. The mouse-area-check should be disabled while the popup is displayed.
When the radar selection popup is open and the mouse leaves the radar area, the popup automatically closes even if the mouse is over the popup. Detect when the popup is open and only close it after it has been clicked on.
Left-clicking on a "pip" sets it as the navigation target. TODO: When there are multiple targets represented by a single "pip", the first is automatically chosen. If there are multiple targets in a single "pip", a popup should be displayed allowing the player to select which target to set.
Display a popup to allow the player to select a target if there are multiple targets over a "pip". Also fix issue if the player clicks outside a popup which could get mouse handling confused.
d16c081
to
229c3aa
Compare
data/pigui/modules/radar.lua
Outdated
if radar_popup_displayed or isMouseOverRadar() then | ||
ui.popup("radarselector", function() | ||
if ui.selectable(lui.HUD_2D_RADAR, shouldDisplay2DRadar, {}) then | ||
toggle_radar = true | ||
if not shouldDisplay2DRadar then | ||
toggle_radar = true | ||
end | ||
radar_popup_displayed = false | ||
end | ||
if ui.selectable(lui.HUD_3D_RADAR, not shouldDisplay2DRadar, {}) then | ||
toggle_radar = true | ||
if shouldDisplay2DRadar then | ||
toggle_radar = true | ||
end | ||
radar_popup_displayed = false | ||
end | ||
end) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: Now that we have the icon button to switch the radar between 2d and 3d modes, do we still want to support the right-click popup? The code is a bit messy and I don't really see the utility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend "no". The only reason to keep the right-click menu is to not break existing muscle memory / tutorials, which is kind of a moot point with the significant UI additions to the radar widget.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Muscle-memory for right-click popups is pretty poor anyway..
Thanks, so unless someone else is going to step in with a strong argument "for" I'll remove it.
Double-clicking on the radar will clear the current navigation target.
-- Generate the next in a sequence of 1 2 5 10 20 ... | ||
local function nextZoomSeq(currZoom, maxZoom) | ||
local newZoom = 0 | ||
if getDigits(currZoom) == 2 then | ||
newZoom = currZoom * 2.5 | ||
else | ||
newZoom = currZoom * 2 | ||
end | ||
return math.min(newZoom, maxZoom) | ||
end | ||
|
||
-- Generate the previous in a sequence of 1 2 5 10 20 ... | ||
local function prevZoomSeq(currZoom, minZoom) | ||
local newZoom = 0 | ||
if getDigits(currZoom) == 5 then | ||
newZoom = currZoom / 2.5 | ||
else | ||
newZoom = currZoom / 2 | ||
end | ||
return math.max(newZoom, minZoom) | ||
end | ||
|
||
-- Normalize a number into the zoom sequence (1, 2, 5, 10, 20, ...), rounding | ||
-- it up or down to the next item in the sequence (default: down). | ||
local function normalizeToZoomSeq(number, up) | ||
if up == nil then | ||
up = false | ||
end | ||
|
||
local firstDigits = getDigits(number, 1, 2) | ||
if firstDigits > 50 then | ||
firstDigits = up and 10 or 5 | ||
elseif firstDigits == 50 then | ||
firstDigits = 5 | ||
elseif firstDigits > 20 then | ||
firstDigits = up and 5 or 2 | ||
elseif firstDigits == 20 then | ||
firstDigits = 2 | ||
elseif firstDigits > 10 then | ||
firstDigits = up and 2 or 1 | ||
else | ||
firstDigits = 1 | ||
end | ||
|
||
local numDigits = #tostring(number) | ||
return firstDigits * 10^(numDigits-1) | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These functions are possibly of general use and could be placed into a utility library?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the normalizeToZoomSeq
function can be generalized by taking the log10 of the zoom and snapping the fractional part to one of 0, ~0.3, or ~0.7 (for 1, 2, 5 respectively). The particular values should likely be precomputed as math.log10(2)
etc. as they have a significant number of digits.
I'll leave the particulars of the implementation to you, but that's how I'd approach the problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have a look, although I daresay floating-point arithmetic is going to result in rather imprecise results. I guess performance is moot since it's not going to be calculated every frame..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, the core question here was whether these functions should be part of a utility library, and if so where, instead of being in "radar.lua"..
Vector2(center.x - ui.reticuleCircleRadius * 0.9, | ||
center.y - ui.reticuleCircleRadius * 0.7), | ||
Vector2(center.x + ui.reticuleCircleRadius * 0.9, | ||
center.y + ui.reticuleCircleRadius * 0.7)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably move the window size definitions (below) to the top, and re-use the sizes here.
local function onTargetClicked(target) | ||
-- TODO: Should ships be set as nav or combat targets? | ||
Game.player:SetNavTarget(target.body) | ||
end | ||
|
||
-- display either the 3D or the 2D radar, show a popup on right click to select | ||
local function displayRadar() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally I'd like to split this function into multiple functions, but that would require moving a LOT of variables into the file scope. Is there another way?
What is the best practise in Lua for doing this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depends - what are you trying to split out of the function? You have a few options:
- Pass read-only parameters via function arguments, granularize function actions such that they can return "changed values" as needed. This allows one "master function" to own the local functions and pass them around. If needed, the master function can pass a table value wrapping multiple variables into sub-functions, but that's basically option 2:
- Convert the radar display into a module (see
data/pigui/libs/module.lua
, and how it's used in e.g. the save/load window) and implement most of your drawing functions as methods on the "radar module". If you do this route, I'd strongly recommend attempting to make your "display" functions non-mutating and use the built-inmessage()
facilities to handle state changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking input handling and actually drawing the radar are two rather different logical tasks which should be split.. so yeah, I guess I can put the entire state of the radar module into a table and pass that around (I forgot about tables..).
It's a shame the 3d radar is partially in C++ otherwise it would be much neater to refactor this thing. If/when we upgrade to the next version of ImGUi we could move this into Lua as well since the next version of ImGui has native ellipse drawing primitives.
I'm thinking the next step will be to actually define multiple pieces of radar equipment and then have functionality depending on what equipment is installed - range, target identification, etc. So any refactoring here should take this into account. Or possibly require further refactoring, in which case, might as well leave this as-is for now and leave the refactoring to when the next step is done.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add double-click to clear the navigation target
General thought - it might be better to have a "reject/unlock target" keybinding which unsets combat then navigation targets in that order. Nav/combat target is generally a state which is managed (by the player) at a higher level than the radar widget.
local click_on_radar = false | ||
local function onTargetClicked(target) | ||
-- TODO: Should ships be set as nav or combat targets? | ||
Game.player:SetNavTarget(target.body) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ships are always combat targets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ships are always combat targets.
Not really - rescue missions, for example.
radar_popup_displayed = false | ||
click_on_radar = false | ||
end | ||
elseif isMouseOverRadar() then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that instead of calling isMouseOverRadar()
, you can instead potentially submit a ui.invisibleButton
with the appropriate button flags (might need to expose a few more in src/lua/LuaPiGui.cpp
) before drawing the radars and test ui.isItemClicked()
/ ui.isItemHovered()
etc.
This would allow for each radar to define its own "click area" and potentially unify some of the "clicked on radar" handling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you draw circular buttons? And how will this invisible button affect the other buttons because I don't think I'll be able to make an elliptical button!
@@ -50,7 +50,7 @@ namespace Sound { | |||
current = &m_eventTwo; | |||
next = &m_eventOne; | |||
} | |||
next->PlayMusic(name.c_str(), m_volume, repeat, fadeDelta, current); | |||
next->PlayMusic(name.c_str(), m_volume, fadeDelta, repeat, current); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, thank you!
It helps to compile with BOTH clang and gcc... :)
We -should- set "-Wall, -Weverything, -Werror", at least for release builds, except the "contrib" folder.
No excuse to have a warning in our code. If the code can really not be modified to fix a warning (compilers aren't infallible either), can always set a #pragma with documentation explaining why.
Sure - I just thought it poor that being able to click on a target to set nav-target (can use RMB to set combat target now that we're getting rid of the RMB popup) there was no way to undo that. Pressing "Y" already resets the nav target, not sure about combat.. |
I suspect most players don't even know about the 2D vs 3D radar. |
Yeah, that button will definitely help with the discoverability |
I didn't.. (but then again I'm newly back to Pioneer..) |
NOTE: The code could probably do with some tidying up...
Additionally fix an issue introduced in 678d46e where a couple of parameters are swapped when calling "PlayMusic" (found due to compiler warning).
TODO: