initial commit
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32617aa2b651b1e4eb9c501aff76fe02
|
||||
@@ -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 => "---";
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc520ccb22d47d74c966b0afdb95d4fe
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35252881317d17142ae810fe0cad00a3
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c06e7972b6bac34468cda352d1c07c7a
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0015370abb0b1af488c2de94bf042002
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user