Angepasste Garage, verbessertes Icon Asset system, range der türme vorschau beim ziehen

This commit is contained in:
PBM2H25BEB committed 2026-11-05 07:52:47 +01:00
1 parent 5486444dde
commit 5af8655c97
59 files changed
+12079 -457

No files matched your search

@@ -34,6 +34,9 @@ namespace DepthsOfGreed.HandbookUI
private CanvasGroup bookGroup;
private GameObject prefab, preview, controls;
private Transform container, area;
[Header("Mauer-Baubereich")]
[Tooltip("Baugrenzen und Mittelpunkt. Konfiguration auf PlacementTest/BuildArea.")]
[SerializeField] private WallBuildArea buildArea;
private SpriteRenderer ghost, footprint;
private Sprite ghostPlaceholder;
private TMP_Text controlsText, feedback, resources, buildHint;
@@ -46,7 +49,11 @@ namespace DepthsOfGreed.HandbookUI
private LineRenderer previewOutline, innerOutline, outerOutline;
private Material lineMaterial;
private float placementAngle;
private float manualAimOffset;
public bool alignPreviewToCenter = true;
[SerializeField] private LayeredTowerPreview layeredPreview;
private GeneralFeedbackController general;
[SerializeField] private AttackRangePreview attackRangePreview;
public void Initialize(HandbookController owner, BuildMenuController menu, RectTransform openBook, GameObject testPrefab, MonoBehaviour gameplayBackend = null)
{
@@ -62,7 +69,8 @@ namespace DepthsOfGreed.HandbookUI
enabled = false;
return;
}
area = test.transform.Find("BuildArea");
area = buildArea ? buildArea.transform : test.transform.Find("BuildArea");
if (!buildArea && area) buildArea = area.GetComponent<WallBuildArea>();
container = test.transform.Find("PlacedTowers") ?? test.transform.Find("PlaceTowers");
preview = test.transform.Find("PlacementPreview").gameObject;
ghost = preview.transform.Find("GhostVisual").GetComponent<SpriteRenderer>();
@@ -87,8 +95,14 @@ namespace DepthsOfGreed.HandbookUI
}
resources = menu.transform.Find("RightPage/ResourcesText").GetComponent<TMP_Text>();
buildHint = menu.transform.Find("BuildHintText").GetComponent<TMP_Text>();
innerRadius = RadiusOf("BackgroundTower", 3f);
outerRadius = RadiusOf("BackgroundOuterwall", 4f);
if (!buildArea)
{
Debug.LogError("Testplatzierung: WallBuildArea zuweisen.", this); enabled = false; return;
}
if (!buildArea.TryGetRadii(out innerRadius, out outerRadius, out string boundaryError))
{
Debug.LogError("Testplatzierung: " + boundaryError, buildArea); enabled = false; return;
}
if (gameplayBackend && gameplayBackend is IHandbookGameplay real) Backend = real;
else
{
@@ -101,6 +115,7 @@ namespace DepthsOfGreed.HandbookUI
previewOutline = MakeCircle("PlacementOutline", preview.transform, 11);
innerOutline = MakeCircle("BuildArea_Inner", area, 8);
outerOutline = MakeCircle("BuildArea_Outer", area, 8);
innerOutline.useWorldSpace = outerOutline.useWorldSpace = true;
DrawCircle(innerOutline, innerRadius);
DrawCircle(outerOutline, outerRadius);
ShowGuides(false);
@@ -109,28 +124,21 @@ namespace DepthsOfGreed.HandbookUI
RefreshResources();
}
private static float RadiusOf(string name, float fallback)
{
var obj = GameObject.Find(name);
var renderer = obj ? obj.GetComponent<SpriteRenderer>() : null;
return renderer ? Mathf.Min(renderer.bounds.extents.x, renderer.bounds.extents.y) : fallback;
}
public bool Begin(HandbookTowerEntry entry, Vector2 screenPosition)
{
if (!enabled || IsDragging || IsWaitingForReturn || entry == null) return false;
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);
draggingEntry = entry; placementAngle = 0; manualAimOffset = 0; LastFailure = null;
if(attackRangePreview)attackRangePreview.Show(entry);
if(layeredPreview)layeredPreview.Show(entry,ghostPlaceholder);
ghost.gameObject.SetActive(!layeredPreview);
IsDragging = true;
preview.SetActive(true);
footprint.transform.localScale = new Vector3(entry.placementRadius * 2f, entry.placementRadius * 2f, 1f);
DrawCircle(previewOutline, entry.placementRadius);
controls.SetActive(false);
general.ShowControls("Loslassen: Bauen\nRechtsklick / Esc: Abbrechen" + (entry.allowPlayerRotation ? "\nR: Drehen" : ""));
general.ShowControls("Loslassen: Bauen\nRechtsklick / Esc: Abbrechen" + (entry.allowPlayerRotation ? "\nR: Drehen" : "") + (entry.combat != null && entry.combat.unlimitedRange ? "\nReichweite: unbegrenzt" : ""));
bookGroup.blocksRaycasts = false;
ShowGuides(true);
foreach (var record in Backend.BuiltObjects)
@@ -153,12 +161,18 @@ namespace DepthsOfGreed.HandbookUI
if (!plane.Raycast(ray, out float distance)) return;
target = ray.GetPoint(distance);
target.z = 0;
if(alignPreviewToCenter)
{
Vector2 inward = area.position-target;
if(inward.sqrMagnitude>.0001f)placementAngle=Mathf.LerpAngle(placementAngle,Mathf.Atan2(inward.y,inward.x)*Mathf.Rad2Deg-(draggingEntry.combat?.forwardAngleOffset??90)+manualAimOffset,1-Mathf.Exp(-16*Time.unscaledDeltaTime));
}
preview.transform.position = target; preview.transform.rotation = Quaternion.Euler(0, 0, placementAngle);
string reason = Check(draggingEntry, target);
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);
if(layeredPreview)layeredPreview.SetOpacity(outside?.3f:.8f);
Tint(previewOutline, color);
DrawCircle(previewOutline, draggingEntry.placementRadius, outside);
controlsText.text = "Loslassen: Platzieren · Rechtsklick / Esc: Abbrechen";
@@ -222,7 +236,7 @@ namespace DepthsOfGreed.HandbookUI
{
if (Mouse.current.rightButton.wasPressedThisFrame ||
(Keyboard.current != null && Keyboard.current.escapeKey.wasPressedThisFrame)) Cancel();
else { if (draggingEntry.allowPlayerRotation && Keyboard.current != null && Keyboard.current.rKey.wasPressedThisFrame) placementAngle += 90; Move(Mouse.current.position.ReadValue()); }
else { if (draggingEntry.allowPlayerRotation && Keyboard.current != null && Keyboard.current.rKey.wasPressedThisFrame) { if(alignPreviewToCenter)manualAimOffset+=90;else placementAngle+=90; } Move(Mouse.current.position.ReadValue()); }
}
bool lowered = IsDragging || IsWaitingForReturn;
if (!lowered) bookGroup.blocksRaycasts = true;
@@ -293,7 +307,8 @@ namespace DepthsOfGreed.HandbookUI
for (int i = 0; i < segments; i++)
{
float angle = i * Mathf.PI * 2f / segments;
line.SetPosition(i, new Vector3(Mathf.Cos(angle) * radius, Mathf.Sin(angle) * radius, 0));
var point = new Vector3(Mathf.Cos(angle) * radius, Mathf.Sin(angle) * radius, 0);
line.SetPosition(i, line.useWorldSpace ? line.transform.position + point : point);
}
// Alternating width provides a procedural broken outline without an extra sprite.
if (dashed)
@@ -307,3 +322,5 @@ namespace DepthsOfGreed.HandbookUI
private void OnDestroy() { if (Backend != null) Backend.StateChanged -= RefreshResources; if (lineMaterial) Destroy(lineMaterial); }
}
}