-
Notifications
You must be signed in to change notification settings - Fork 213
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
Spectator Panel Redesign #2302
base: master
Are you sure you want to change the base?
Spectator Panel Redesign #2302
Conversation
…c-panel-experimentation
This is a working demo of a new design for the spectator panels. This is a work-in-progress, presented for early feedback. Features:
Limitations:
Notes:
To Do:
|
Invitation for feedback: @GoogleFrog @sprunk @Kingraptor @Licho1 @dvr333 @Anarchid @Aquanim and anyone else who cares to comment. Please note that I'm aware the code is very messy in places and that I already have plans to clean it up. Much of what's there is scaffolding left over from my experiments with layouts. Regardless, suggestions for improvement are welcome. I have not tested this in live games, only local games and replays. |
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.
The stats display is updated every two seconds so the numbers don't jump around as badly while you're trying to read them
The stats are smoothed over a three-second moving average to better show prevailing trends instead of momentary spikes
I think I'd prefer 1s:
- if you're averaging then they might not be jumping around that much?
- all other displays refresh at 1s so people might assume this one is lagging
- 2 does not divide 3 so there's a minor skew (only really relevant for spikes but still)
I'm unsure about background screenshots. I think I'd prefer if this was something simple, for example a render of the factory or its most iconic unit (with llt/hlt/annihilator or whatever for small/medium/large teams). I generally dislike depicting a specific game scenario with parts of an unrelated map etc (even if it's just a beauty shot). More importantly, this allows the picture to have dynamic teamcolors (to look way more coherent).
function GetWinString(name) | ||
local winTable = WG.WinCounter_currentWinTable | ||
if winTable and winTable[name] and winTable[name].wins then | ||
-- TODO - Do something else to mark the winner of the previous game, not 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.
A laurel wreath perhaps?
return unpack(output_table) | ||
end | ||
|
||
local function Format(input, override) |
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.
There's a ToSI
function that converts to SI units, use it: https://github.com/ZeroK-RTS/Zero-K/blob/master/LuaRules/Utilities/numberfunctions.lua
-- They were taken from the current spec panels. I've probably translated them | ||
-- incorrectly, but what I have here gives results that seem very wrong. | ||
-- | ||
-- For example: Generation 62, Reclaim 0, OD 9 => Income 71. |
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.
OD == 9
means that X
energy went into overdrive and X+9
came back.
This can happen when one's allies have 100% storage yet many unlinked generators, so even though their entire energy net is directed to OD, some is unable to be spent there. It is then not redirected entirely back to the ally - such extra energy is returned to everyone equally.
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.
Do everything in terms of allyTeam. AllyTeam overdrive will always be an expenditure. The trick with overdrive is that energy spent on overdrive never touches the Spring resourcing system. Energy is generated by summing over the energy generators, subtracting some for overdrive and then adding that resource to the various teams. The only way to generate energy via Spring is to reclaim or be gifted some energy from an ally (manually, not within the overdrive system).
for i,side in ipairs({'left', 'right'}) do | ||
local smCurr, smStor, smInco, smOvdr, smRecl, smBase, seCurr, seStor, seInco, seOvdr, seRecl, seBase = unpack(smoothedTables['resources_'..side]) | ||
t[side].resource_stats.metal.total:SetCaption(Format(smInco, "")) | ||
t[side].resource_stats.metal.labels[1]:SetCaption("E:" .. Format(smBase, "")) |
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'd change E
to B
(for Base
) here, and then G
to B
in energy too, for consistency.
local sorted_udids = {} | ||
for n in pairs(unitStats[i].units) do table.insert(sorted_udids, n) end | ||
if #sorted_udids > 0 then | ||
table.sort(sorted_udids, function (a,b) return unitStats[i].units[a].metal > unitStats[i].units[b].metal 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.
Something to consider: have striders compare before regular units regardless of total metal since arguably they are more interesting.
if #sorted_comm_ids > 0 then | ||
table.sort(sorted_comm_ids, function (a,b) return unitStats[i].comms[a].level > unitStats[i].comms[b].level end) | ||
end | ||
for pic = 1,compic_slots do |
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.
Consider extending the unit pic count if the team had less than 3 comms.
Also, perhaps replace com pics with a picture of relevant wreckage as they die.
-- started spectating or the panel was toggled off and on | ||
-- or luaui was reloaded. | ||
-- | ||
-- Alas, the attrition counter will still have to start from |
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.
function widget:Update(dt) | ||
|
||
-- Start the spec panel in the first userframe. Can't do this during widget:Initialize | ||
-- because the option values aren't set yet by epicmenu and they may be wrong. |
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.
Use Initialize
. At some point Epicmenu shows up and updates the options, use OnChange
to take this into account. Note that you have to do this anyway as the user can change settings mid-game.
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 agree, this should be replaced with Initialize because there is no getting around the fact that options can change.
end | ||
|
||
function widget:GameFrame(n) | ||
if panel_is_on 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.
Disable the callin when the panel is not on (see eg https://github.com/ZeroK-RTS/Zero-K/blob/master/LuaUI/Widgets/gui_attrition_counter.lua#L314 )
-------------------------------------------------------------------------------- | ||
-- Unit Stats Call-ins and Processor | ||
|
||
local function ProcessUnit(unitID, unitDefID, unitTeam, remove) |
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.
IMO add the categorized unit values to the stat collector gadget first, then use that here.
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.
Putting it here means that only spectators will feel the performance impact, and only the spectators using the panels.
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.
This version is event-driven, so there's only a small performance hit - just a few local table lookups each time a unit is created or destroyed. On the other hand, if there's no expectation that other widgets would benefit from this information, there's no compelling reason to centralize it in the gadget.
On the gripping hand, putting it in the gadget means that it will be available when a player resigns and begins spectating. Otherwise, the widget will have to iterate through the existing units when first enabled to build the current unit table and then use events for subsequent updates.
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.
According to #2258 these stats would be collected by the graph widget anyway.
|
||
-- hardcoding these for now, will add colourblind options later | ||
local positiveColourStr = GreenStr | ||
local negativeColourStr = RedStr |
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.
There is a full shader for colourblind now. This still may be useful for colourblind friendly streams that don't want to go all the way.
Looks fancy. Some feedback:
|
@sprunk, @GoogleFrog - Thanks for the code review. I'll incorporate your suggestions as I clean up the code. Understanding how the energy stats work will be a challenge; any further pointers would be appreciated. Good idea re not enabling the Wins by default, and auto-detecting when there's a rematch. I'm very sensitive to how much space this layout takes up. I'll be making it thinner, but even so, I think we'll need multiple layouts to support a range of screen sizes. I'm thinking: compact for less than 1080p, standard for 1080p, and large for larger than that. Smaller versions can show less information and have a less interesting design. The presets widget can autodetect the screensize and choose which version to display; users can then override it with an option if they wish. Standard can drop the unit icons, and probably the clock (I think the advantage bars are the most important part of the spec display). Compact can drop the unit icons and clock, drop the background image, drop the names and the top bar, and arrange the advantage bars horizontally in a thin bar across the bottom, plus make the fontsize smaller.
That's more-or-less what I was going for, with each bg image showcasing two iconic units from the factory - one small, one large. Only the top quarter of the image is really visible, and the rest just provides a textural background for the rest of the frame to help distinguish the two sides (I intend to have multiple images for each teamsize and choose them so that each side is always different). But I think I understand what you're suggesting, and I'll try some mockups in that direction and see how it looks.
Even with averaging, a one-second refresh makes it hard to read a large display with lots of stats. The three seconds is a rolling average, i.e. it's always the last three seconds averaged no matter when the update happens, so there's no skew. Thanks for the feedback! I probably won't be able to do any updates for a couple of weeks, but will keep working on it as I'm able. |
NB: To check whether there are wins check WG.WinCounter_currentWinTable.hasWins. I'm going to PR an update to the internal documentation of win_counter.lua to include that info (which needs a rename to api_win_counter.lua) As for aesthetics, while I feel like you took everything I mentioned wanting in a spectator display and mashed it into one, I agree with Googlefrog that it's really tall and should be more modular. Also, what does "G" and "E" mean? I'm not even looking for an answer so much as the realization that these panels are almost more for the audience than the caster, so there should be as much clarity as possible. The current panels showing "Reclaim" is clear, this one showing "R" is not. (within the assumptions that the audience is English-speaking, but that's a localization question, and my casts are in English anyway) |
Let's say update happens on even seconds. Let's say some stat has a constant 0 value except a one-second spike of value If the spike is on second 5: the update on second 6 will take seconds 4, 5 and 6 -> If the spike happens on second 6: the update on second 6 takes 4,5,6 -> shows X for the next 2 seconds, then the update at 8 takes 6,7,8 and again shows X for the next 2 seconds (since both these periods include second 6). In the first case you get shown 2 seconds of X, in the second 4 seconds of X, while in reality there were (the equivalent of) 3 seconds of X. This is a nitpick but it's also trivial to fix (preferably by making the update period 1s, but if you want to stick to 2s you can make the moving average take 4s).
Current panels say |
@sprunk you're right, I'm surprised I didn't notice |
@sprunk: Thanks, I see now what you're getting at. I don't think it's an issue; the display isn't intended to be an accurate gauge of metal accumulated ("last interval it showed X, this interval it showed X, intervals are two seconds, therefore there's been 4X accumulation"). It's intended to be a reasonable estimate of current rate of income with the spikes smoothed out, so you can tell who's doing well and who's falling behind. My intuition is that two seconds of averaging would be too spiky, and four seconds would be too laggy (if updates are on even seconds, and a mex was destroyed at t=0.5, the mex's contribution to income would still be partially included in the t=4 update, not disappearing entirely until the t=6 update). But it's easily adjustable in the code; we can do trials and see what people like. We can even make the update and averaging intervals options so people can override the defaults if they really want to. But of course we should make the defaults whatever we think will be best for most people. @dvr333: Thanks, I'll use that API when I make more fixes. Perhaps the scheme for alternate layouts will provide both the space savings and modularity that you and GF are looking for. I'll work on it. Maybe we can find or make icons for generation/extraction, reclaim, and OD. That way they'll at least be equally difficult to understand for everyone. :) Either way, I think having tooltips showing the details and using the spelled-out words will help. People might be briefly confused, but will quickly learn what they mean if they hover over the bar. Icons would make a nicer-looking presentation, too. |
Base generation can be the ibeam with the plus or perhaps the stylized mex. Overdrive can be the ibeam with the energy icon overlayed, this may have been deleted from the repository. Reclaim can be the reclaim cursor. Perhaps remove the current unit types display and replace it with a collapsible display on the left and right sides of the screen. This display could show many rows of units arranged down each side. This collapsible display could be toggled by clicking on the Unit Value panel and that panel could be its own floating UI component. This would allows the central display to be thinner and fit on smaller screens. I like the four comparison bars and it is good to stack them vertically but they extend too low. Perhaps stack them in a 2x2 grid with income/extraction as one group and military/attrition as another? |
The attrition rate calculation here seems to do a duplicate of what Attrition Counter does. Current state of the Endgame Stats widget is that it also collects the information relevant for calculating attrition rate separately and while respecting visibility. This data is thus now being collected in triplicate. A good idea would be to make both Attrition Counter and Spectator Panel use data provided by Endgame Stats instead of doing their own collection. P.S i really dig the balance bars for attrition and income ratio stats. |
One of the open tasks here is to move much of the stats collecting out of the spec panel widget and into the stats collector gadget, as much as it makes sense to do (which may be all of it). I'll do that when I get back to working on this panel (Sprunk has done a lot of that work on the stats gadget already). |
Don't let the unimportantness discourage you too much. The return on investment here seems low (an improvement in the quality of spectating/casts) but it is positive and worth working on at some point. If this is what you want to do then do it. Quite a bit has been improved by people working on projects like this, it all builds up. Ideally the spectator panels would reach a state where they can be enabled by default and automatically toggled on in the appropriate situation. The current panels are not quite at that point, mostly due to placement issues with the floating economy panels. I've thought a bit about what could be more helpful, since it has come up. You write like a native English speaker and seem to have some common sense regarding PR the most efficient work for you is probably in preparing the text and screenshots for a media pack (I hear it is a good idea to have one). However, if you have preexisting video creation skills then creating an updated trailer is probably the way to go. |
The panel seems to have an error:
|
…c-panel-experimentation
Any recent advances? |
Work in progress.