initial commit

This commit is contained in:
Aggtaa
2026-01-20 10:02:31 +03:00
commit 17e2c3ab8b
125 changed files with 18236 additions and 0 deletions
+67
View File
@@ -0,0 +1,67 @@
using UnityEngine;
using UnityEngine.UIElements;
public static class Collider2DHelper
{
public static Vector2 TopCenter(this Collider2D collider)
{
Vector2 center = collider.bounds.center;
Vector2 extents = collider.bounds.extents; // half-size
return new Vector2(center.x, center.y + extents.y);
}
}
[RequireComponent(typeof(Collider2D))]
[RequireComponent(typeof(ResourceSource))]
[RequireComponent(typeof(UIDocument))]
[RequireComponent(typeof(ResourceGenerator))]
public class FactoryInfo : MonoBehaviour
{
[SerializeField()]
private new Camera camera;
[SerializeField]
private string title;
private new Collider2D collider;
private ResourceSource source;
private ResourceGenerator generator;
private UIDocument uiDocument;
private VisualElement rootElement;
private VisualElement panelElement;
private Label titleLabel;
private ProgressBar progressBar;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
collider = GetComponent<Collider2D>();
source = GetComponent<ResourceSource>();
generator = GetComponent<ResourceGenerator>();
uiDocument = GetComponent<UIDocument>();
rootElement = uiDocument.rootVisualElement;
panelElement = rootElement.Q<VisualElement>("Panel");
titleLabel = rootElement.Q<Label>("Title");
progressBar = rootElement.Q<ProgressBar>("Progress");
}
[ExecuteInEditMode]
void Update()
{
if (panelElement != null)
{
Vector3 screenPos = camera.WorldToScreenPoint(collider.TopCenter());
panelElement.style.left = screenPos.x;
panelElement.style.top = Screen.height - screenPos.y;
}
else
Debug.Log("No panel");
titleLabel.text = title;
progressBar.title = source?.Resource.Name;
progressBar.value = generator.Progress * 100;
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 32617aa2b651b1e4eb9c501aff76fe02
+52
View File
@@ -0,0 +1,52 @@
using System;
using Unity.VisualScripting;
using UnityEngine;
[Serializable]
public abstract class Resource
{
[Inspectable]
public abstract string Name { get; }
public abstract string SourceLabel { get; }
public override string ToString()
{
return this.Name;
}
}
[Serializable]
// [CreateAssetMenu(fileName = "Metal", menuName = "Resources/Metal")]
public class Metal : Resource
{
public override string Name => "Metal";
public override string SourceLabel => "Metal source";
}
[Serializable]
// [CreateAssetMenu(fileName = "Electronics", menuName = "Resources/Electronics")]
public class Electronics : Resource
{
public override string Name => "Electronics";
public override string SourceLabel => "Electronics Factory";
}
[Serializable]
// [CreateAssetMenu(fileName = "Energy", menuName = "Resources/Energy")]
public class Energy : Resource
{
public override string Name => "Energy";
public override string SourceLabel => "Power Plant";
}
[Serializable]
// [CreateAssetMenu(fileName = "Metal", menuName = "Resources/Metal")]
public class Money : Resource
{
public override string Name => "Money";
public override string SourceLabel => "---";
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: dc520ccb22d47d74c966b0afdb95d4fe
+107
View File
@@ -0,0 +1,107 @@
using System;
using Unity.VisualScripting;
using UnityEngine;
[RequireComponent(typeof(ResourceSource))]
public class ResourceGenerator : MonoBehaviour
{
public int Interval;
public int Power = 0;
private ResourceSource source;
private long lastTime;
[ContextMenu("Clear Last Generation Time")]
public void ResetTime()
{
source = GetComponent<ResourceSource>();
PlayerPrefs.DeleteKey(GetLastTimePrefName());
PlayerPrefs.Save();
}
private void Start()
{
source = GetComponent<ResourceSource>();
// PlayerPrefs.DeleteKey(GetLastTimePrefName());
// PlayerPrefs.Save();
lastTime = long.Parse(
PlayerPrefs.GetString(GetLastTimePrefName(), GetCurrentTime().ToSafeString())
);
GenerateToNow(false);
}
private long GetCurrentTime()
{
return DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;
}
private string GetPrefName(string suffix)
{
return $"ResourceGenerator_{source.Resource.Name}_{suffix}";
}
private string GetLastTimePrefName()
{
return GetPrefName("LastTime");
}
private void Update()
{
GenerateToNow(true);
PlayerPrefs.SetString(GetLastTimePrefName(), lastTime.ToSafeString());
}
private void GenerateToNow(bool online)
{
var now = GetCurrentTime();
GenerateToTime(now);
}
private void GenerateToTime(long time)
{
if (Interval == 0)
return;
var delta = time - lastTime;
if (delta > 1e8)
{
Debug.Log($"Too much time has passed: {time - lastTime}");
lastTime = time;
return;
}
// Debug.Log($"{time} - {lastTime} = {delta} since last generation");
long times = delta / Interval;
if (times > 0)
{
Generate((int)times);
lastTime += times * Interval;
}
}
private void Generate(int times)
{
// Debug.Log($"+{Power}x{times} {source.Resource.Name}");
ResourceStorage.Instance.AddResource(source.Resource, Power * times);
}
public float Progress
{
get
{
if (Interval == 0)
return 0;
var delta = GetCurrentTime() - lastTime;
return Math.Clamp(delta * 1.0f / Interval, 0, 1);
}
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 35252881317d17142ae810fe0cad00a3
+12
View File
@@ -0,0 +1,12 @@
using System;
using Unity.VisualScripting;
using UnityEngine;
public class ResourceSource : MonoBehaviour
{
[field: SerializeField]
public string Label { get; private set; }
[SerializeReference]
public Resource Resource;
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c06e7972b6bac34468cda352d1c07c7a
+126
View File
@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
public class StoredResource
{
public Resource Resource { get; private set; }
public int Amount { get; internal set; }
public bool Unlocked { get; internal set; }
public StoredResource(Resource resource)
{
Resource = resource;
Amount = 0;
Unlocked = false;
}
}
public class ResourceStorage : MonoBehaviour
{
public static ResourceStorage Instance { get; private set; }
private Dictionary<string, StoredResource> resources = new Dictionary<string, StoredResource>();
private List<Action> changeCallbacks = new List<Action>();
public static readonly Metal Metal = new Metal();
public static readonly Electronics Electronics = new Electronics();
public static readonly Energy Energy = new Energy();
public static readonly Money Money = new Money();
public static Resource[] RegisteredResources
{
get
{
var list = new List<Resource>();
list.Add(Metal);
list.Add(Electronics);
list.Add(Energy);
list.Add(Money);
return list.ToArray();
}
}
public static Type[] RegisteredResourceTypes =>
RegisteredResources.Select(r => r.GetType()).ToArray();
public ResourceStorage()
{
AddResource(Metal, true);
AddResource(Electronics, true); // TODO lock back
AddResource(Energy, true); // TODO lock back
AddResource(Money, true); // TODO lock back
Instance = this;
}
private void AddResource(Resource resource, bool unlocked = false)
{
resources.Add(resource.Name, new StoredResource(resource) { Unlocked = unlocked });
}
public StoredResource GetResource(Resource resource)
{
return resources[resource.Name];
}
public void AddResource(Resource resource, int amount)
{
var res = GetResource(resource);
if (res != null)
{
res.Amount += amount;
InvokeOnChange();
}
}
public void RemoveResource(Resource resource, int amount)
{
var res = GetResource(resource);
if (res != null && res.Amount >= amount)
{
res.Amount -= amount;
InvokeOnChange();
}
}
public void UnlockResource(Resource resource)
{
var res = GetResource(resource);
if (res != null)
{
res.Unlocked = true;
InvokeOnChange();
}
}
private void InvokeOnChange()
{
// Debug.Log(
// $"Resources: {String.Join("; ", resources.Values.ToArray().Select(r => r.Resource.Name + "=" + r.Amount + (r.Unlocked ? "" : "(locked)")))}"
// );
changeCallbacks.ForEach(a =>
{
try
{
a.Invoke();
}
catch { }
});
}
public void RegisterOnChangeCallback(Action callback)
{
changeCallbacks.Add(callback);
}
public void UnregisterOnChangeCallback(Action callback)
{
changeCallbacks.Remove(callback);
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0015370abb0b1af488c2de94bf042002
+72
View File
@@ -0,0 +1,72 @@
using System;
using UnityEngine;
using UnityEngine.UIElements;
internal class SlotInfo
{
public VisualElement slotElement { get; private set; }
public Label amountLabel { get; private set; }
public SlotInfo(VisualElement slotElement)
{
this.slotElement = slotElement;
amountLabel = slotElement.Q<Label>(className: "amount");
}
}
[RequireComponent(typeof(UIDocument))]
[RequireComponent(typeof(ResourceStorage))]
public class ResourceStorageView : MonoBehaviour
{
private UIDocument uiDocument;
private ResourceStorage storage;
private SlotInfo metalSlot;
private SlotInfo electronicsSlot;
private SlotInfo energySlot;
private SlotInfo moneySlot;
void OnEnable()
{
storage = GetComponent<ResourceStorage>();
storage.RegisterOnChangeCallback(OnStorageChange);
}
void OnDisable()
{
storage.UnregisterOnChangeCallback(OnStorageChange);
}
private void OnStorageChange()
{
UpdateVisuals();
}
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
uiDocument = GetComponent<UIDocument>();
var rootElement = uiDocument.rootVisualElement;
metalSlot = new SlotInfo(rootElement.Q<VisualElement>("MetalSlot"));
electronicsSlot = new SlotInfo(rootElement.Q<VisualElement>("ElectronicsSlot"));
energySlot = new SlotInfo(rootElement.Q<VisualElement>("EnergySlot"));
moneySlot = new SlotInfo(rootElement.Q<VisualElement>("MoneySlot"));
UpdateVisuals();
}
private void UpdateVisuals()
{
UpdateSlotVisuals(metalSlot, storage.GetResource(ResourceStorage.Metal));
UpdateSlotVisuals(electronicsSlot, storage.GetResource(ResourceStorage.Electronics));
UpdateSlotVisuals(energySlot, storage.GetResource(ResourceStorage.Energy));
UpdateSlotVisuals(moneySlot, storage.GetResource(ResourceStorage.Money));
}
private void UpdateSlotVisuals(SlotInfo slot, StoredResource resource)
{
slot.slotElement.style.display = resource.Unlocked ? DisplayStyle.Flex : DisplayStyle.None;
slot.amountLabel.text = resource.Amount.ToString();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f1800dcf0fff37844991b2b5c8e5405f