Handbuch Scroll-Listen entfernt. Handbuch offen und tabs eingefügt. Upgrades eingefügt. "Garage" eingefügt. Anbindung eines echten Gameplaymanager möglich (theoretisch)
This commit is contained in:
@@ -11,8 +11,13 @@ namespace DepthsOfGreed.HandbookUI
|
||||
{
|
||||
public bool IsDragging { get; private set; }
|
||||
public bool ConsumedCancelThisFrame => cancelFrame == Time.frameCount;
|
||||
public int TowerCount => placed.Count;
|
||||
public int Energy { get; private set; } = 2000;
|
||||
public int TowerCount => Backend == null ? 0 : Backend.WallCount;
|
||||
public int Energy => Backend == null ? 0 : Backend.Energy;
|
||||
public IHandbookGameplay Backend { get; private set; }
|
||||
public Vector3 AreaCenter => area.position;
|
||||
public float AreaRadius => outerRadius;
|
||||
public string LastFailure { get; private set; }
|
||||
private string failedTypeId;
|
||||
public int MaximumTowers = 8;
|
||||
public float SuccessfulPlacementDelay = 0.5f;
|
||||
public bool IsWaitingForReturn => Time.unscaledTime < returnAfter;
|
||||
@@ -20,26 +25,30 @@ namespace DepthsOfGreed.HandbookUI
|
||||
private int cancelFrame = -1;
|
||||
private RectTransform book;
|
||||
private Vector2 bookHome;
|
||||
[Header("Book position while building")]
|
||||
[Tooltip("Automatic lowering accounts for the book scale. Disable to set an explicit anchored position.")]
|
||||
[SerializeField] private bool automaticLoweredBookPosition = true;
|
||||
[Tooltip("Height of the book left visible above the bottom edge, in parent UI units. Tabs can extend above it.")]
|
||||
[SerializeField, Min(0)] private float visibleBookHeightWhileBuilding = 15f;
|
||||
[SerializeField] private Vector2 loweredBookPosition = new Vector2(0f, -675f);
|
||||
private CanvasGroup bookGroup;
|
||||
private GameObject prefab, preview, controls;
|
||||
private Transform container, area;
|
||||
private SpriteRenderer ghost, footprint;
|
||||
private Sprite ghostPlaceholder;
|
||||
private TMP_Text controlsText, feedback, resources, buildHint;
|
||||
private Image feedbackBox;
|
||||
private RectTransform feedbackBoxRect;
|
||||
private float messageStarted;
|
||||
private Color feedbackBackground;
|
||||
private Camera worldCamera;
|
||||
private float innerRadius, outerRadius, messageUntil;
|
||||
private float innerRadius, outerRadius;
|
||||
private HandbookTowerEntry draggingEntry;
|
||||
private Vector3 target;
|
||||
private readonly List<PlacedRecord> placed = new List<PlacedRecord>();
|
||||
private readonly List<LineRenderer> guides = new List<LineRenderer>();
|
||||
private LineRenderer previewOutline, innerOutline, outerOutline;
|
||||
private Material lineMaterial;
|
||||
private struct PlacedRecord { public Vector3 position; public float radius; public GameObject instance; }
|
||||
private float placementAngle;
|
||||
private GeneralFeedbackController general;
|
||||
|
||||
public void Initialize(HandbookController owner, BuildMenuController menu, RectTransform openBook, GameObject testPrefab)
|
||||
public void Initialize(HandbookController owner, BuildMenuController menu, RectTransform openBook, GameObject testPrefab, MonoBehaviour gameplayBackend = null)
|
||||
{
|
||||
book = openBook;
|
||||
bookHome = book.anchoredPosition;
|
||||
@@ -57,6 +66,7 @@ namespace DepthsOfGreed.HandbookUI
|
||||
container = test.transform.Find("PlacedTowers") ?? test.transform.Find("PlaceTowers");
|
||||
preview = test.transform.Find("PlacementPreview").gameObject;
|
||||
ghost = preview.transform.Find("GhostVisual").GetComponent<SpriteRenderer>();
|
||||
ghostPlaceholder = ghost.sprite;
|
||||
footprint = preview.transform.Find("FootprintVisual").GetComponent<SpriteRenderer>();
|
||||
var controlTransform = transform.Find("PlacementControlBar") ?? transform.Find("PlacementController");
|
||||
if (!area || !container || !controlTransform)
|
||||
@@ -72,8 +82,6 @@ namespace DepthsOfGreed.HandbookUI
|
||||
if (boxTransform)
|
||||
{
|
||||
feedbackBox = boxTransform.GetComponent<Image>();
|
||||
feedbackBoxRect = (RectTransform)boxTransform;
|
||||
feedbackBackground = feedbackBox.color;
|
||||
feedbackBox.raycastTarget = false;
|
||||
feedbackBox.gameObject.SetActive(false);
|
||||
}
|
||||
@@ -81,6 +89,14 @@ namespace DepthsOfGreed.HandbookUI
|
||||
buildHint = menu.transform.Find("BuildHintText").GetComponent<TMP_Text>();
|
||||
innerRadius = RadiusOf("BackgroundTower", 3f);
|
||||
outerRadius = RadiusOf("BackgroundOuterwall", 4f);
|
||||
if (gameplayBackend && gameplayBackend is IHandbookGameplay real) Backend = real;
|
||||
else
|
||||
{
|
||||
var prototype = gameObject.GetComponent<PrototypeHandbookGameplay>();
|
||||
prototype.Initialize(container, area.position, innerRadius, outerRadius, prefab); Backend = prototype;
|
||||
}
|
||||
Backend.StateChanged += RefreshResources;
|
||||
general = gameObject.GetComponent<GeneralFeedbackController>(); general.Initialize(book, controlsText.font);
|
||||
lineMaterial = new Material(Shader.Find("Sprites/Default"));
|
||||
previewOutline = MakeCircle("PlacementOutline", preview.transform, 11);
|
||||
innerOutline = MakeCircle("BuildArea_Inner", area, 8);
|
||||
@@ -103,21 +119,25 @@ namespace DepthsOfGreed.HandbookUI
|
||||
public bool Begin(HandbookTowerEntry entry, Vector2 screenPosition)
|
||||
{
|
||||
if (!enabled || IsDragging || IsWaitingForReturn || entry == null) return false;
|
||||
if (placed.Count >= MaximumTowers) { Message("Turmlimit erreicht"); return false; }
|
||||
if (Energy < entry.energyCost) { Message("Nicht genug Energie"); return false; }
|
||||
draggingEntry = entry;
|
||||
var availability = Backend.CheckAvailability(entry);
|
||||
if (!availability.Allowed) { failedTypeId = entry.id; Message(availability.message); return false; }
|
||||
draggingEntry = entry; placementAngle = 0; LastFailure = null;
|
||||
ghost.sprite = entry.previewSprite ? entry.previewSprite : ghostPlaceholder;
|
||||
Vector2 visualSize = entry.baseShape == BaseShape.Rectangle ? entry.baseSize : Vector2.one * entry.baseRadius * 1.4142136f;
|
||||
ghost.transform.localScale = new Vector3(visualSize.x / ghost.sprite.bounds.size.x, visualSize.y / ghost.sprite.bounds.size.y, 1);
|
||||
IsDragging = true;
|
||||
preview.SetActive(true);
|
||||
footprint.transform.localScale = new Vector3(entry.placementRadius * 2f, entry.placementRadius * 2f, 1f);
|
||||
DrawCircle(previewOutline, entry.placementRadius);
|
||||
controls.SetActive(true);
|
||||
controls.SetActive(false);
|
||||
general.ShowControls("Loslassen: Bauen\nRechtsklick / Esc: Abbrechen" + (entry.allowPlayerRotation ? "\nR: Drehen" : ""));
|
||||
bookGroup.blocksRaycasts = false;
|
||||
ShowGuides(true);
|
||||
foreach (var record in placed)
|
||||
foreach (var record in Backend.BuiltObjects)
|
||||
{
|
||||
var guide = MakeCircle("ExistingTowerRadius", container, 8);
|
||||
guide.transform.position = record.position;
|
||||
DrawCircle(guide, record.radius);
|
||||
DrawCircle(guide, record.type.placementRadius);
|
||||
Tint(guide, new Color(1f, 1f, 1f, 0.5f));
|
||||
guides.Add(guide);
|
||||
}
|
||||
@@ -133,9 +153,9 @@ namespace DepthsOfGreed.HandbookUI
|
||||
if (!plane.Raycast(ray, out float distance)) return;
|
||||
target = ray.GetPoint(distance);
|
||||
target.z = 0;
|
||||
preview.transform.position = target;
|
||||
preview.transform.position = target; preview.transform.rotation = Quaternion.Euler(0, 0, placementAngle);
|
||||
string reason = Check(draggingEntry, target);
|
||||
bool outside = reason == "Außerhalb des Schienenbereichs";
|
||||
bool outside = Backend.CheckBuild(new BuildRequest(draggingEntry, target, placementAngle)).failure == BuildFailure.OutsideRegion;
|
||||
Color color = outside ? Color.gray : reason == null ? Color.green : Color.red;
|
||||
footprint.color = new Color(color.r, color.g, color.b, outside ? 0.08f : 0.18f);
|
||||
ghost.color = new Color(1f, 1f, 1f, outside ? 0.3f : 0.65f);
|
||||
@@ -160,29 +180,11 @@ namespace DepthsOfGreed.HandbookUI
|
||||
}
|
||||
|
||||
public string Check(HandbookTowerEntry entry, Vector3 position)
|
||||
{
|
||||
if (entry == null) return "Kein Turm ausgewählt";
|
||||
float distance = Vector2.Distance(position, area.position);
|
||||
if (distance - entry.baseRadius < innerRadius || distance + entry.baseRadius > outerRadius)
|
||||
return "Außerhalb des Schienenbereichs";
|
||||
foreach (var record in placed)
|
||||
if (Vector2.Distance(position, record.position) < entry.placementRadius + record.radius)
|
||||
return "Zu nah an einem anderen Turm";
|
||||
if (placed.Count >= MaximumTowers) return "Turmlimit erreicht";
|
||||
if (Energy < entry.energyCost) return "Nicht genug Energie";
|
||||
return null;
|
||||
}
|
||||
|
||||
{ return Backend.CheckBuild(new BuildRequest(entry, position, placementAngle)).message; }
|
||||
public bool TryPlaceAt(HandbookTowerEntry entry, Vector3 position, out string reason)
|
||||
{
|
||||
reason = Check(entry, position);
|
||||
if (reason != null) return false;
|
||||
var tower = Instantiate(prefab, position, Quaternion.identity, container);
|
||||
tower.name = entry.displayName + " (Test)";
|
||||
placed.Add(new PlacedRecord { position = position, radius = entry.placementRadius, instance = tower });
|
||||
Energy -= entry.energyCost;
|
||||
RefreshResources();
|
||||
return true;
|
||||
var result = Backend.ExecuteBuild(new BuildRequest(entry, position, placementAngle));
|
||||
reason = result.message; return result.Allowed;
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
@@ -198,6 +200,7 @@ namespace DepthsOfGreed.HandbookUI
|
||||
draggingEntry = null;
|
||||
preview.SetActive(false);
|
||||
controls.SetActive(false);
|
||||
general.HideControls();
|
||||
bookGroup.blocksRaycasts = true;
|
||||
ShowGuides(false);
|
||||
foreach (var guide in guides) Destroy(guide.gameObject);
|
||||
@@ -219,16 +222,20 @@ namespace DepthsOfGreed.HandbookUI
|
||||
{
|
||||
if (Mouse.current.rightButton.wasPressedThisFrame ||
|
||||
(Keyboard.current != null && Keyboard.current.escapeKey.wasPressedThisFrame)) Cancel();
|
||||
else Move(Mouse.current.position.ReadValue());
|
||||
else { if (draggingEntry.allowPlayerRotation && Keyboard.current != null && Keyboard.current.rKey.wasPressedThisFrame) placementAngle += 90; Move(Mouse.current.position.ReadValue()); }
|
||||
}
|
||||
bool lowered = IsDragging || IsWaitingForReturn;
|
||||
if (!lowered) bookGroup.blocksRaycasts = true;
|
||||
var position = lowered ? new Vector2(bookHome.x, -book.rect.height + 100f) : bookHome;
|
||||
float scaledHeight = book.rect.height * Mathf.Abs(book.localScale.y);
|
||||
var lowerTarget = automaticLoweredBookPosition
|
||||
? new Vector2(bookHome.x, -scaledHeight * (1f - book.pivot.y) + visibleBookHeightWhileBuilding)
|
||||
: loweredBookPosition;
|
||||
var position = lowered ? lowerTarget : bookHome;
|
||||
book.anchoredPosition = Vector2.Lerp(book.anchoredPosition, position,
|
||||
1f - Mathf.Exp(-18f * Time.unscaledDeltaTime));
|
||||
if (IsDragging)
|
||||
{
|
||||
bool outside = Check(draggingEntry, target) == "Außerhalb des Schienenbereichs";
|
||||
bool outside = Backend.CheckBuild(new BuildRequest(draggingEntry, target, placementAngle)).failure == BuildFailure.OutsideRegion;
|
||||
float alpha = outside ? 0.35f + 0.2f * Mathf.Sin(Time.unscaledTime * 5f) : 0.4f;
|
||||
Tint(innerOutline, new Color(1f, 0.8f, 0.3f, alpha));
|
||||
Tint(outerOutline, new Color(1f, 0.8f, 0.3f, alpha));
|
||||
@@ -238,61 +245,33 @@ namespace DepthsOfGreed.HandbookUI
|
||||
|
||||
private void Message(string reason)
|
||||
{
|
||||
feedback.gameObject.SetActive(true);
|
||||
feedback.transform.SetAsLastSibling();
|
||||
feedback.color = Color.white;
|
||||
feedback.text = reason;
|
||||
messageStarted = Time.unscaledTime;
|
||||
messageUntil = messageStarted + 2.65f;
|
||||
if (feedbackBox)
|
||||
{
|
||||
feedbackBox.gameObject.SetActive(true);
|
||||
feedbackBox.transform.SetAsLastSibling();
|
||||
feedback.transform.SetAsLastSibling();
|
||||
}
|
||||
UpdateFeedback();
|
||||
}
|
||||
|
||||
private void UpdateFeedback()
|
||||
{
|
||||
if (!feedback || messageUntil <= 0) return;
|
||||
float elapsed = Time.unscaledTime - messageStarted;
|
||||
if (Time.unscaledTime >= messageUntil) { ClearFeedback(); return; }
|
||||
float alpha = elapsed > 2.4f ? Mathf.Clamp01((messageUntil - Time.unscaledTime) / 0.25f) : 1f;
|
||||
feedback.color = new Color(1, 1, 1, alpha);
|
||||
if (feedbackBox)
|
||||
{
|
||||
float pulse = elapsed < 0.4f ? Mathf.Pow(Mathf.Sin(elapsed / 0.4f * Mathf.PI * 2f), 2f) : 0;
|
||||
Color color = Color.Lerp(feedbackBackground, new Color(0.48f, 0.34f, 0.15f, 1), pulse);
|
||||
color.a = alpha;
|
||||
feedbackBox.color = color;
|
||||
float canvasHeight = ((RectTransform)transform).rect.height;
|
||||
float y = Mathf.Min(-10f, book.anchoredPosition.y + book.rect.height - canvasHeight + 70f);
|
||||
feedbackBoxRect.anchoredPosition = new Vector2(0, y);
|
||||
feedback.rectTransform.anchoredPosition = new Vector2(0, y);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearFeedback()
|
||||
{
|
||||
messageUntil = 0;
|
||||
if (feedback) { feedback.text = ""; feedback.color = Color.white; }
|
||||
if (feedbackBox) feedbackBox.gameObject.SetActive(false);
|
||||
LastFailure = reason;
|
||||
if (draggingEntry) failedTypeId = draggingEntry.id;
|
||||
general.ShowError(reason, !IsDragging);
|
||||
if (!IsDragging && buildHint) buildHint.text = reason;
|
||||
}
|
||||
private void UpdateFeedback() { }
|
||||
private void ClearFeedback() { if (feedback) feedback.text = ""; if (feedbackBox) feedbackBox.gameObject.SetActive(false); }
|
||||
private void RefreshResources()
|
||||
{
|
||||
resources.text = "Energie: " + Energy + " · Gedärme: 100 (Test)\nTürme: " + placed.Count + "/" + MaximumTowers;
|
||||
resources.text = "Energie: " + Energy + " · Gedärme: " + Backend.Entrails + "\nMauer: " + TowerCount + "/" + Backend.WallLimit;
|
||||
if (buildHint)
|
||||
{
|
||||
bool full = placed.Count >= MaximumTowers;
|
||||
buildHint.text = full ? "Turmlimit erreicht (" + placed.Count + "/" + MaximumTowers + ") · Klicken: Infos" : "Ziehen: Bauen · Klicken: Infos";
|
||||
bool full = TowerCount >= Backend.WallLimit;
|
||||
buildHint.text = full ? "Turmlimit erreicht (" + TowerCount + "/" + Backend.WallLimit + ") · Klicken: Infos" : "Ziehen: Bauen · Klicken: Infos";
|
||||
buildHint.color = full ? new Color(0.7f, 0.15f, 0.1f) : new Color(0.3f, 0.3f, 0.3f);
|
||||
}
|
||||
}
|
||||
public void ShowCardHint(HandbookTowerEntry entry)
|
||||
{
|
||||
var result = Backend.CheckAvailability(entry);
|
||||
if (buildHint) buildHint.text = !result.Allowed ? result.message : entry && entry.id == failedTypeId && LastFailure != null ? LastFailure : "Ziehen: Bauen · Klicken: Infos";
|
||||
}
|
||||
public void ClearCardHint() { RefreshResources(); }
|
||||
private void ShowGuides(bool show)
|
||||
{
|
||||
innerOutline.gameObject.SetActive(show);
|
||||
outerOutline.gameObject.SetActive(show);
|
||||
outerOutline.gameObject.SetActive(show && draggingEntry && draggingEntry.region == BuildRegion.WallRing);
|
||||
}
|
||||
private LineRenderer MakeCircle(string name, Transform parent, int order)
|
||||
{
|
||||
@@ -325,6 +304,6 @@ namespace DepthsOfGreed.HandbookUI
|
||||
}
|
||||
else line.widthCurve = AnimationCurve.Constant(0, 1, 1);
|
||||
}
|
||||
private void OnDestroy() { if (lineMaterial) Destroy(lineMaterial); }
|
||||
private void OnDestroy() { if (Backend != null) Backend.StateChanged -= RefreshResources; if (lineMaterial) Destroy(lineMaterial); }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user