Core Game Loop Additions

This commit is contained in:
2026-06-03 22:41:27 -07:00
parent 79ff06a7df
commit 8e9b4412ce
70 changed files with 3084 additions and 2 deletions
@@ -24,6 +24,9 @@ namespace ProjectM.Client
RectTransform _cooldownFill;
Text _healthText;
Text _threatText;
Text _phaseText;
Text _resourceText;
Text _locationText;
GameObject _respawnOverlay;
EntityQuery _huskQuery;
@@ -48,6 +51,55 @@ namespace ProjectM.Client
bool haveTick = SystemAPI.TryGetSingleton<NetworkTime>(out var nt);
// Macro-loop HUD (phase + cycle + countdown + location), read before the per-player early-out so it persists pre-spawn.
bool haveCycle = SystemAPI.TryGetSingleton<CycleState>(out var cyc);
if (_phaseText != null && haveCycle)
{
var endTick = new NetworkTick(cyc.PhaseEndTick);
string detail;
if (cyc.Phase == CyclePhase.Defend)
detail = _huskQuery.CalculateEntityCount() + " HUSKS";
else if (haveTick && cyc.PhaseEndTick != 0 && endTick.IsValid && endTick.IsNewerThan(nt.ServerTick))
detail = (endTick.TicksSince(nt.ServerTick) / 60) + "s";
else
detail = "";
_phaseText.text = PhaseLabel(cyc.Phase) + (detail.Length > 0 ? " - " + detail : "") + " CYCLE " + cyc.CycleNumber;
_phaseText.color = PhaseColor(cyc.Phase);
}
else if (_phaseText != null)
{
_phaseText.text = "";
}
if (_locationText != null)
{
var cam = Camera.main;
bool onExpedition = cam != null && cam.transform.position.x > 500f;
_locationText.text = onExpedition
? "ON EXPEDITION - return through the gate"
: "AT BASE" + (haveCycle && cyc.Phase == CyclePhase.Expedition ? " - step into the gate to deploy" : "");
_locationText.color = onExpedition ? new Color(1f, 0.8f, 0.4f) : new Color(0.6f, 0.85f, 1f);
}
if (_resourceText != null)
{
string res = "";
if (SystemAPI.TryGetSingletonEntity<ResourceLedger>(out var ledgerE))
{
var buf = SystemAPI.GetBuffer<StorageEntry>(ledgerE);
int aether = 0, ore = 0, bio = 0;
for (int i = 0; i < buf.Length; i++)
{
var en = buf[i];
if (en.ItemId == ResourceId.Aether) aether = en.Count;
else if (en.ItemId == ResourceId.Ore) ore = en.Count;
else if (en.ItemId == ResourceId.Biomass) bio = en.Count;
}
res = "AETHER " + aether + " ORE " + ore + " BIO " + bio;
}
_resourceText.text = res;
}
bool found = false;
float hp = 0f, maxHp = 1f, cdFrac = 1f;
bool dead = false, shielded = false;
@@ -77,7 +129,7 @@ namespace ProjectM.Client
break;
}
_canvas.enabled = found;
_canvas.enabled = found || haveCycle;
if (!found) return;
float frac = maxHp > 0f ? Mathf.Clamp01(hp / maxHp) : 0f;
@@ -139,6 +191,27 @@ namespace ProjectM.Client
trt.anchorMin = new Vector2(1, 1); trt.anchorMax = new Vector2(1, 1); trt.pivot = new Vector2(1, 1);
trt.anchoredPosition = new Vector2(-40, -30); trt.sizeDelta = new Vector2(380, 50);
// Cycle phase + number (top-center).
_phaseText = MakeText("PhaseText", _canvas.transform, "EXPEDITION CYCLE 1", 34, TextAnchor.UpperCenter,
new Color(0.55f, 0.9f, 1f), font);
var prt = _phaseText.rectTransform;
prt.anchorMin = new Vector2(0.5f, 1f); prt.anchorMax = new Vector2(0.5f, 1f); prt.pivot = new Vector2(0.5f, 1f);
prt.anchoredPosition = new Vector2(0, -24); prt.sizeDelta = new Vector2(600, 50);
// Resource ledger counts (top-center, below phase).
_resourceText = MakeText("ResourceText", _canvas.transform, "", 24, TextAnchor.UpperCenter,
new Color(0.7f, 0.95f, 0.8f), font);
var rrt = _resourceText.rectTransform;
rrt.anchorMin = new Vector2(0.5f, 1f); rrt.anchorMax = new Vector2(0.5f, 1f); rrt.pivot = new Vector2(0.5f, 1f);
rrt.anchoredPosition = new Vector2(0, -64); rrt.sizeDelta = new Vector2(600, 40);
// Location + gate hint (top-center, below resources).
_locationText = MakeText("LocationText", _canvas.transform, "", 22, TextAnchor.UpperCenter,
new Color(0.6f, 0.85f, 1f), font);
var lrt = _locationText.rectTransform;
lrt.anchorMin = new Vector2(0.5f, 1f); lrt.anchorMax = new Vector2(0.5f, 1f); lrt.pivot = new Vector2(0.5f, 1f);
lrt.anchoredPosition = new Vector2(0, -96); lrt.sizeDelta = new Vector2(760, 36);
// Downed / respawning overlay (full screen, toggled by Dead).
_respawnOverlay = new GameObject("RespawnOverlay", typeof(RectTransform));
_respawnOverlay.transform.SetParent(_canvas.transform, false);
@@ -211,5 +284,27 @@ namespace ProjectM.Client
if (f == null) f = Font.CreateDynamicFontFromOSFont(new[] { "Arial", "Liberation Sans", "DejaVu Sans" }, 28);
return f;
}
static Color PhaseColor(byte phase)
{
switch (phase)
{
case CyclePhase.Expedition: return new Color(0.45f, 0.85f, 1f);
case CyclePhase.Defend: return new Color(1f, 0.5f, 0.3f);
case CyclePhase.Build: return new Color(0.45f, 0.95f, 0.6f);
default: return Color.white;
}
}
static string PhaseLabel(byte phase)
{
switch (phase)
{
case CyclePhase.Expedition: return "EXPEDITION";
case CyclePhase.Defend: return "DEFEND";
case CyclePhase.Build: return "BUILD";
default: return "";
}
}
}
}