Improved research display and added ResearchState.

This commit is contained in:
2026-05-08 11:45:46 +02:00
parent 192620fad3
commit 032836b9ec
6 changed files with 191 additions and 29 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ public partial class GameData
public static float tileWidth = 6; public static float tileWidth = 6;
public static float tileHeight = 4; public static float tileHeight = 4;
public static SortedDictionary<string, ItemData> availableItems = ResourceLoader.LoadItems(); public static SortedDictionary<string, ItemData> availableItems = ResourceLoader.LoadItems();
public static Dictionary<string, ResearchData> availableResearch = ResourceLoader.LoadResearch(); public static Dictionary<string, Research> availableResearch = ResourceLoader.LoadResearch();
//--- PLAYER ADJUSTABLE VALUES --- //--- PLAYER ADJUSTABLE VALUES ---
//Color used in primary objects (e.g. Robots) //Color used in primary objects (e.g. Robots)
+3 -3
View File
@@ -102,18 +102,18 @@ public partial class ResourceLoader
return result; return result;
} }
public static Dictionary<string, ResearchData> LoadResearch() public static Dictionary<string, Research> LoadResearch()
{ {
FileAccess file = FileAccess.Open("res://Assets/Research.json", FileAccess.ModeFlags.Read); FileAccess file = FileAccess.Open("res://Assets/Research.json", FileAccess.ModeFlags.Read);
string json = file.GetAsText(); string json = file.GetAsText();
Dictionary<string, ResearchData> result = new(); Dictionary<string, Research> result = new();
List<ResearchData> researches = JsonSerializer.Deserialize<List<ResearchData>>(json); List<ResearchData> researches = JsonSerializer.Deserialize<List<ResearchData>>(json);
foreach (ResearchData research in researches) foreach (ResearchData research in researches)
{ {
result.Add(research.Id, research); result.Add(research.Id, new Research(research));
} }
return result; return result;
+8 -2
View File
@@ -3,9 +3,15 @@ using Godot;
public class Research public class Research
{ {
public ResearchData data; public ResearchData data;
public bool isResearched = false;
public double elapsedResearchTime = 0; public double elapsedResearchTime = 0;
public bool paidResources = false; public bool paidResources = false;
public ResearchState state;
public Research(ResearchData data)
{
this.data = data;
state = ResearchState.UNDEFINED;
}
public ResearchResult Execute(double delta) public ResearchResult Execute(double delta)
{ {
@@ -20,7 +26,7 @@ public class Research
elapsedResearchTime += delta; elapsedResearchTime += delta;
if (elapsedResearchTime >= data.CraftTime) if (elapsedResearchTime >= data.CraftTime)
{ {
isResearched = true; state = ResearchState.RESEARCHED;
return ResearchResult.FINISHED; return ResearchResult.FINISHED;
} }
return ResearchResult.RESEARCHING; return ResearchResult.RESEARCHING;
+170 -22
View File
@@ -1,49 +1,118 @@
using System.Collections.Generic;
using System.Linq;
using Godot; using Godot;
using Godot.Collections;
public partial class ResearchList : PanelContainer public partial class ResearchList : PanelContainer
{ {
[Export] GraphEdit researchGraph; [Export] private GraphEdit researchGraph;
private const float StartXDivisor = 32f;
private const float StartYDivisor = 4f;
private const float NodeSpacingMultiplier = 10f;
private List<string> reloadKeys = new List<string>();
public override void _Ready() public override void _Ready()
{ {
foreach (ResearchData research in GameData.availableResearch.Values) RecalculateResearchStates();
SetupGraph();
}
public void SetupGraph()
{
reloadKeys = new List<string>();
ClearGraph();
CreateResearchNodes();
CreateResearchConnections();
}
private void ClearGraph()
{
foreach (Dictionary connection in researchGraph.GetConnectionList())
{ {
researchGraph.AddChild(CreateItemNode(research.Id, research.Texture)); researchGraph.DisconnectNode(
connection["from_node"].AsStringName(),
(int)connection["from_port"],
connection["to_node"].AsStringName(),
(int)connection["to_port"]
);
} }
foreach (ResearchData research in GameData.availableResearch.Values)
foreach (Node child in researchGraph.GetChildren())
{ {
if (child is GraphNode)
{
researchGraph.RemoveChild(child);
child.QueueFree();
}
}
}
private void CreateResearchNodes()
{
foreach (Research research in GameData.availableResearch.Values)
{
GD.Print(research.state);
GraphNode node = CreateResearchNode(
research.data.Id,
research.data.Texture,
research.state
);
researchGraph.AddChild(node);
}
}
private void CreateResearchConnections()
{
foreach (Research research in GameData.availableResearch.Values)
{
string prerequisite = research.data.Research;
string current = research.data.Id;
if (string.IsNullOrEmpty(prerequisite))
continue;
if (!researchGraph.HasNode(prerequisite) || !researchGraph.HasNode(current))
continue;
researchGraph.ConnectNode( researchGraph.ConnectNode(
research.Research, prerequisite,
0, 0,
research.Id, current,
0 0
); );
} }
} }
public override void _Process(double delta) private GraphNode CreateResearchNode(string id, string texturePath, ResearchState state)
{ {
Texture2D texture = GD.Load<Texture2D>(texturePath);
Color stateColor = GetColorByState(state);
}
private GraphNode CreateItemNode(string id, string texturePath)
{
Vector2 viewportSize = GetViewport().GetVisibleRect().Size;
TextureRect icon = new TextureRect TextureRect icon = new TextureRect
{ {
Texture = GD.Load<Texture2D>(texturePath), Texture = texture,
StretchMode = TextureRect.StretchModeEnum.KeepAspectCentered StretchMode = TextureRect.StretchModeEnum.KeepAspectCentered,
CustomMinimumSize = new Vector2(64, 64),
SelfModulate = stateColor
}; };
//Step 1: Place the node in the visible field for the player
Vector2 nodePosition = new Vector2(viewportSize.X / 32, viewportSize.Y / 4); Button button = new Button
//Step 2: Modify position by nodeIndex {
nodePosition = nodePosition + new Vector2(GameData.availableResearch.Count * -icon.Texture.GetWidth() + researchGraph.GetChildCount() * icon.Texture.GetWidth() * 10, 0); Text = "Research",
Disabled = state != ResearchState.AVAILABLE
};
button.Pressed += () => OnResearchPressed(id);
GraphNode node = new GraphNode GraphNode node = new GraphNode
{ {
Name = id, Name = id,
Title = id, Title = id,
PositionOffset = nodePosition PositionOffset = GetNodePosition(texture),
SelfModulate = stateColor
}; };
node.SetSlot( node.SetSlot(
@@ -57,7 +126,86 @@ public partial class ResearchList : PanelContainer
); );
node.AddChild(icon); node.AddChild(icon);
node.AddChild(button);
return node; return node;
} }
private Vector2 GetNodePosition(Texture2D texture)
{
Vector2 viewportSize = GetViewport().GetVisibleRect().Size;
float textureWidth = texture?.GetWidth() ?? 64f;
Vector2 startPosition = new Vector2(
viewportSize.X / StartXDivisor,
viewportSize.Y / StartYDivisor
);
float xOffset =
GameData.availableResearch.Count * -textureWidth +
researchGraph.GetChildCount() * textureWidth * NodeSpacingMultiplier;
return startPosition + new Vector2(xOffset, 0);
}
private void OnResearchPressed(string id)
{
GameData.availableResearch[id].state = ResearchState.RESEARCHED;
RecalculateResearchStates();
SetupGraph();
}
private void RecalculateResearchStates()
{
bool changedState;
foreach (string key in GameData.availableResearch.Keys)
{
changedState = false;
if (reloadKeys.Contains(key)) continue;
reloadKeys.Add(key);
//Already researched
if (GameData.availableResearch[key].state == ResearchState.RESEARCHED)
{
changedState = true;
}
//No previous research needed
if (GameData.availableResearch[key].data.Research.Length <= 0)
{
GameData.availableResearch[key].state = ResearchState.RESEARCHED;
changedState = true;
}
//Previous research is unlocked
if (!changedState && GameData.availableResearch[GameData.availableResearch[key].data.Research].state == ResearchState.RESEARCHED)
{
GameData.availableResearch[key].state = ResearchState.AVAILABLE;
changedState = true;
}
if (!changedState)
{
//All others are locked
GameData.availableResearch[key].state = ResearchState.LOCKED;
}
if (reloadKeys.Count != GameData.availableResearch.Keys.Count)
{
RecalculateResearchStates();
}
}
}
private Color GetColorByState(ResearchState state)
{
return state switch
{
ResearchState.AVAILABLE => Colors.White,
ResearchState.LOCKED => new Color(0.6f, 0.6f, 0.6f, 0.5f),
ResearchState.RESEARCHED => new Color(0.7f, 1f, 0.7f, 1f),
_ => Colors.Red
};
}
} }
+7
View File
@@ -0,0 +1,7 @@
public enum ResearchState
{
UNDEFINED,
RESEARCHED,
AVAILABLE,
LOCKED
}
+1
View File
@@ -0,0 +1 @@
uid://b57yhucbav37c