-
-
Notifications
You must be signed in to change notification settings - Fork 520
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
Add dots indicating player population on patch map #5880
base: master
Are you sure you want to change the base?
Conversation
An image would be nice, so we can give graphics feedback. |
I think the dots should be more desaturated to look like more as just background stuff. That would help with them not messing with the readability of the connection lines. |
/// <summary> | ||
/// Dots scattered around patch map nodes, indication population of player species | ||
/// </summary> | ||
public partial class PatchMapPopulationIndicator : Control |
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 going to be a ton of these, so I think that actually this shouldn't be a node type with a script attached. And instead just I'd inline this code to the patch map drawer class (though it should be cleanly put into a separate section as it is already a pretty long file). I think the performance impact will be much less when there's just simple graphics used for the indicators rather than nodes with scripts attached.
/// <summary> | ||
/// Player species ID for player population indicator (dots on patch map) | ||
/// </summary> | ||
public uint PlayerSpeciesID { get; set; } |
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 think this could default to -1 (or uint.MaxValue if C# complains) so that this doesn't accidentally match anything if there's a bug elsewhere in the code that causes a species with ID = 0 to be created.
|
||
for (var i = 0; i < playerPopulation * 0.001; ++i) | ||
{ | ||
var indicator = populationIndicatorScene.Instantiate<PatchMapPopulationIndicator>(); |
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 think it would be worthwhile probably to have a cache of these objects as I think otherwise this will increase the amount of memory allocations quite a lot here.
Overall the architecture isn't far off from being pretty much exactly what I would have done for this feature. So if this is slightly tweaked and the visuals improved a bit, this PR will be good to go.
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.
By cache you mean a list created in this create-patch-node method, a list in the patch map drawer class, or something else completely? I'm not questioning why, since you are much more experienced but I'm curious how it reduces allocations
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 Queue or a Stack in the patch map drawer class, so it can just create them once and then reuse them.
Once the queue is filled up once with unused objects, the next time the dots need to be put in the map, they can be pulled from the queue and refilled. So this way the dots are instantiated just once, instead of being instantiated on each map draw.
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 started to work on this but I realized that indicators are children of patch nodes, which are deleted.
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.
What if they weren't? What if they were added as children to the patch map itself? AFAIK the patch nodes are added as children to the drawer node in order to position them and make them display at the right position on screen.
Seems like pretty normal Godot shutdown errors to me. There's probably an open bug report to godot about those. At least I remember looking up the rendering server error and seeing there was an open bug with it. I think I'm watching it on github and I don't remember seeing an email about it being closed, so the issue is still probably open. |
You can reorder the node that contains the dot in relation to its siblings to control what is drawn on top of what without messing with zindex or draw behind parent properties. |
Oh I just reminded myself that you said tutorial will be needed. It can be done in a seperate PR, or in this. I will be doing else for today though so I won't implement tutorial today. |
As long as the effect is made simple enough, I think we can do without having a tutorial. Well as long as there's some thriveopedia page or something that explains the feature. |
…nary-Games/Thrive.git into player_population_dots
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 think this is in better shape than when I last looked at this. There's still some minor stuff in the code I'd like to see improved.
@@ -11,6 +11,8 @@ public partial class PatchMapDrawer : Control | |||
[Export] | |||
public bool DrawDefaultMapIfEmpty; | |||
|
|||
public uint PlayerSpeciesID = int.MaxValue; |
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.
Non-godot properties shouldn't be mixed in so this field should be after LineContainerPath
@@ -149,6 +157,8 @@ public override void _Ready() | |||
lineContainer = GetNode<Control>(LineContainerPath); | |||
|
|||
nodeScene = GD.Load<PackedScene>("res://src/microbe_stage/editor/PatchMapNode.tscn"); | |||
populationIndicatorScene = GD.Load<PackedScene>( |
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 is just a single node so for performance I don't think this should be made as a separate scene, but just instantiate the nodes with the right texture (load the texture here) in this class.
@@ -1047,6 +1057,13 @@ private void DrawPatchLinks() | |||
/// </summary> | |||
private void RebuildMap() | |||
{ | |||
playerSpeciesPopulationIndicators = new List<Control>(); |
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 list should be stored persistently as otherwise this allocates memory unnecessarily each time the map is drawn.
@@ -1047,6 +1057,13 @@ private void DrawPatchLinks() | |||
/// </summary> | |||
private void RebuildMap() | |||
{ | |||
playerSpeciesPopulationIndicators = new List<Control>(); | |||
foreach (var node in populationIndicatorContainer.GetChildren()) |
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.
GetChildren is still here, this needs to go I think GetChildren is a sign of an architecture problem. Use a persistent list for knowing all the existing indicators that way you can also avoid the type cast on line 1063.
var playerSpecies = patch.FindSpeciesByID(PlayerSpeciesID); | ||
if (playerSpecies != null) | ||
{ | ||
var playerPopulationIndicatorAmount = (int)Math.Ceiling( |
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.
As this whole long block is inside this if, I'd recommend making this as a separate helper method.
|
||
for (int i = 0; i < indicatorExcess; ++i) | ||
{ | ||
playerSpeciesPopulationIndicators.Last().QueueFree(); |
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 think it would be better to just hide the excess indicators, I don't expect us to have so many excess ones that they'd cause an issue during the lifetime of the map drawer node.
if (playerSpecies != null) | ||
{ | ||
var playerPopulationIndicatorAmount = (int)Math.Ceiling( | ||
patch.GetSpeciesSimulationPopulation(playerSpecies) * 0.004); |
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.
Making the constant here into a value in Constants would make it easier for someone else to tweak how many circles appear.
|
||
if (noCached) | ||
{ | ||
populationIndicatorContainer.AddChild(indicator); |
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 could be combined with the above if where this is instantiated for easier reading of this block of code.
Personally I am not really fan of this idea with dots, since it might make patch maps more busy looking in my opinion |
That's why I asked it to be made lower contrast so that it just looks like a bit of background flair and not really anything the player needs to pay attention to. |
The idea was to persuade player to use migration tool more. It's safer for player to spread onto as many patches as possible but migration can be easily forgotten in my opinion as main feature of editor is, well, cell editor. If it gets into RC, we can ask what others think of the visual look and maybe come up with something better. |
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 playtested this now and noticed a bug where on the initial generation (normal and freeplay) the population indicators do not display at all. I think that needs to be fixed. Also using the "move to this patch" button causes an error immediately upon press (I commented the callstack separately). So there's a few gameplay bugs and some quite small remaining code related problems.
simulation_parameters/Constants.cs
Outdated
@@ -1705,6 +1705,9 @@ public static class Constants | |||
|
|||
public const float PATCH_GENERATION_CHANCE_BANANA_BIOME = 0.03f; | |||
|
|||
// Constants for displaying the patch map |
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 comment doesn't seem to match what this is on? This should be an xml summary comment along the lines of "Sets how many population indicator dots appear on the patch map"
simulation_parameters/Constants.cs
Outdated
@@ -1705,6 +1705,9 @@ public static class Constants | |||
|
|||
public const float PATCH_GENERATION_CHANCE_BANANA_BIOME = 0.03f; | |||
|
|||
// Constants for displaying the patch map | |||
public const float PLAYER_POPULATION_POPULATION_FOR_PER_INDICATOR = 1.0f / 300.0f; |
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.
Shouldn't the name of this constant be the inverse? Because this is how many indicators there are per population. That's the difference between population / population per indicator
and population * indicators per population
. So I think this should be renamed for clarity.
{ | ||
indicator = new TextureRect | ||
{ | ||
Texture = GD.Load<Texture2D>("res://assets/textures/gui/bevel/MapDotIndicator.svg"), |
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 texture should be loaded just once in _Ready and not tried to be reloaded for each indicator.
playerSpeciesPopulationIndicators.Count); | ||
|
||
// Hide excess from the end of the list | ||
for (int i = 0; i < indicatorExcess; ++i) |
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.
If you want to keep things this way, I'll accept it, but I think a slightly easier way to program this would be to use a variable like, nextIndicatorIndex
that starts at 0 and goes up for each used indicator. Then the excess indicators can be hidden by looping from the ending nextIndicatorIndex value up to the indicators count. And the noCached
variable can be calculated as nextIndicatorIndex >= playerSpeciesPopulationIndicators.Count
.
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.
Now with the persistent index for used indicators, I think this hiding excess indicators code needs to be put into a single place that is called after the entire map is drawn. Otherwise the last indicators get hidden over and over (and I think your indicatorExcess math was not updated anyway so that would lead to a bug in any case).
indicator.Show(); | ||
} | ||
|
||
indicator.MouseFilter = MouseFilterEnum.Ignore; |
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 should be in the indicator creation as it doesn't seem like this value is ever updated so it wastes time to reapply the value on each loop iteration.
var nodeModifier = node.Position.LengthSquared(); | ||
var modifierSinus = MathF.Sin(i); | ||
|
||
playerSpeciesPopulationIndicators.Add(indicator); |
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.
Isn't this a major bug where the same indicator objects are added again and again to the same list?
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 think this is probably what caused this error when I moved patches in the editor:
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
at System.Collections.Generic.List`1.get_Item(Int32 index)
at PatchMapDrawer.AddPlayerPopulationIndicators(Patch patch, Species playerSpecies, Control node, Vector2 position) in /home/hhyyrylainen/Projects/Thrive/src/microbe_stage/editor/PatchMapDrawer.cs:line 1141
at PatchMapDrawer.AddPatchNode(Patch patch, Vector2 position) in /home/hhyyrylainen/Projects/Thrive/src/microbe_stage/editor/PatchMapDrawer.cs:line 1122
at PatchMapDrawer.RebuildMap() in /home/hhyyrylainen/Projects/Thrive/src/microbe_stage/editor/PatchMapDrawer.cs:line 1069
at PatchMapDrawer._Process(Double delta) in /home/hhyyrylainen/Projects/Thrive/src/microbe_stage/editor/PatchMapDrawer.cs:line 175
at Godot.Node.InvokeGodotClassMethod(godot_string_name& method, NativeVariantPtrArgs args, godot_variant& ret) in /root/godot/modules/mono/glue/GodotSharp/GodotSharp/Generated/GodotObjects/Node.cs:line 2395
at Godot.CanvasItem.InvokeGodotClassMethod(godot_string_name& method, NativeVariantPtrArgs args, godot_variant& ret) in /root/godot/modules/mono/glue/GodotSharp/GodotSharp/Generated/GodotObjects/CanvasItem.cs:line 1505
at Godot.Control.InvokeGodotClassMethod(godot_string_name& method, NativeVariantPtrArgs args, godot_variant& ret) in /root/godot/modules/mono/glue/GodotSharp/GodotSharp/Generated/GodotObjects/Control.cs:line 2912
at PatchMapDrawer.InvokeGodotClassMethod(godot_string_name& method, NativeVariantPtrArgs args, godot_variant& ret) in /home/hhyyrylainen/Projects/Thrive/.godot/mono/temp/obj/Debug/Godot.SourceGenerators/Godot.SourceGenerators.ScriptMethodsGenerator/PatchMapDrawer_ScriptMethods.generated.cs:line 318
at Godot.Bridge.CSharpInstanceBridge.Call(IntPtr godotObjectGCHandle, godot_string_name* method, godot_variant** args, Int32 argCount, godot_variant_call_error* refCallError, godot_variant* ret) in /root/godot/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs:line 24
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 you caught that.
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 think that maybe if the dot was fully filled in and made slightly less in opacity, it would be a lot more subtle effect? That way I think there wouldn't be really any complaining about the added visuals.
// Hide excess from the end of the list | ||
for (int i = 0; i < indicatorExcess; ++i) | ||
{ | ||
playerSpeciesPopulationIndicators[playerSpeciesPopulationIndicators.Count - i].Hide(); |
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.
Also when I'm looking at this code, isn't the math wrong? Because playerSpeciesPopulationIndicators.Count
is not valid index, the first valid index is playerSpeciesPopulationIndicators.Count - 1
but that doesn't happen as i starts off as 0.
Also I think I just realized also another problem: the player being in multiple patches will reset the indicators. There needs to be a persistent nextIndicatorIndex
variable that is only cleared on a full map re-draw not during a map draw when this method can be called multiple times which means that the separate calls for different patches on the map will interfere with each other.
Isn't that again just the usual Godot texture errors on game exit that happen very often? I think it's unlikely any of your changes in this PR would affect that. |
This probably won't make it in for 0.8.1 so I'll push this back to release 0.8.2. |
We are currently in feature freeze until the next release. |
Brief Description of What This PR Does
Might need some visual stuff and other tweaks but it theoretically can be merged.
Related Issues
Progress Checklist
Note: before starting this checklist the PR should be marked as non-draft.
break existing features:
https://wiki.revolutionarygamesstudio.com/wiki/Testing_Checklist
(this is important as to not waste the time of Thrive team
members reviewing this PR)
styleguide.
Before merging all CI jobs should finish on this PR without errors, if
there are automatically detected style issues they should be fixed by
the PR author. Merging must follow our
styleguide.