Adding tons of new functionality
Decals, ghost textures, placement functionality, builder stub ins, a new camera system, and more.
This commit is contained in:
parent
56dc775c68
commit
a63cce53e2
54 changed files with 4817 additions and 238 deletions
121
Assets/_Project/Scripts/Gameplay/BuildRangeIndicator.cs
Normal file
121
Assets/_Project/Scripts/Gameplay/BuildRangeIndicator.cs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// Assets/_Project/Scripts/Gameplay/BuildRangeIndicator.cs
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace TD.Gameplay
|
||||
{
|
||||
/// <summary>
|
||||
/// Visualizes a builder's build range as a decal projector circle on the ground.
|
||||
/// Visible only to the owning client, and only while placement mode is active.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Sits as a child of the <see cref="Builder"/> GameObject. The
|
||||
/// <see cref="DecalProjector"/> renders a circular texture onto whatever ground
|
||||
/// geometry is below — flat plane or sloped terrain alike, no special handling needed.</para>
|
||||
///
|
||||
/// <para><b>Owner-only.</b> Non-owning clients should not see other players' build
|
||||
/// range indicators (would be visual clutter). The decal projector is force-disabled
|
||||
/// for non-owners on spawn.</para>
|
||||
///
|
||||
/// <para><b>Toggling.</b> The indicator is only visible when the local player is in
|
||||
/// placement mode. It checks <c>TowerPlacementController.IsPlacing</c> each frame
|
||||
/// and toggles the projector accordingly. When sized correctly the projector size
|
||||
/// matches <c>buildRange * 2</c> (diameter).</para>
|
||||
/// </remarks>
|
||||
public class BuildRangeIndicator : MonoBehaviour
|
||||
{
|
||||
[Tooltip("DecalProjector child component to drive. Auto-found in Awake if empty.")]
|
||||
[SerializeField] private DecalProjector projector;
|
||||
|
||||
[Tooltip("Vertical thickness of the decal projector's projection volume. Should " +
|
||||
"exceed your map's vertical range so the decal projects onto terrain at any height.")]
|
||||
[SerializeField] private float projectionDepth = 50f;
|
||||
|
||||
// Cached references resolved lazily.
|
||||
private Builder cachedBuilder;
|
||||
private TowerPlacementController cachedPlacementController;
|
||||
|
||||
// ----- Lifecycle --------------------------------------------------
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (projector == null) projector = GetComponentInChildren<DecalProjector>();
|
||||
if (projector == null)
|
||||
{
|
||||
Debug.LogError("[BuildRangeIndicator] No DecalProjector found. Add one as a " +
|
||||
"child of this GameObject.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Start hidden; visibility is updated each frame.
|
||||
projector.enabled = false;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
cachedBuilder = GetComponentInParent<Builder>();
|
||||
if (cachedBuilder == null)
|
||||
{
|
||||
Debug.LogError("[BuildRangeIndicator] No Builder found in parents. " +
|
||||
"Disabling indicator.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide for non-owners — other players don't see your range indicator.
|
||||
if (!cachedBuilder.IsOwner)
|
||||
{
|
||||
enabled = false;
|
||||
if (projector != null) projector.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Size the projector to match the builder's range (diameter = 2 * range).
|
||||
// Modern URP DecalProjector exposes width/height/pivot as separate properties
|
||||
// rather than a single Vector3 size. Width and Height are the ground-plane extents
|
||||
// of the projection; pivot.z is the volume's depth offset (0 = volume centered
|
||||
// on the projector position, projecting equally above and below).
|
||||
float diameter = cachedBuilder.BuildRange * 2f;
|
||||
|
||||
// The DecalProjector exposes a `size` Vector3 on its API even though the
|
||||
// inspector splits it into Width/Height/ProjectionDepth — assignment is still
|
||||
// valid in current URP. We use it here to set all three at once.
|
||||
projector.size = new Vector3(diameter, diameter, projectionDepth);
|
||||
projector.pivot = new Vector3(0f, 0f, 0f);
|
||||
|
||||
// Center the projection volume on the builder. The decal projector projects
|
||||
// along its local +Z axis by default; rotate to project downward (look down).
|
||||
//
|
||||
// CRITICAL: rotate the PROJECTOR's transform, not this component's transform.
|
||||
// BuildRangeIndicator lives on the Builder root (so it can find Builder via
|
||||
// GetComponentInParent), but `transform` here is the Builder's transform —
|
||||
// rotating it tips the cylinder onto its side. The projector lives on a child
|
||||
// GameObject; that's the one that needs the 90° X rotation.
|
||||
projector.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
|
||||
projector.transform.localPosition = Vector3.zero;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (cachedBuilder == null) return;
|
||||
|
||||
bool shouldShow = IsLocalPlayerPlacing();
|
||||
if (projector.enabled != shouldShow)
|
||||
projector.enabled = shouldShow;
|
||||
}
|
||||
|
||||
// ----- Helpers ----------------------------------------------------
|
||||
|
||||
private bool IsLocalPlayerPlacing()
|
||||
{
|
||||
if (cachedPlacementController == null)
|
||||
{
|
||||
cachedPlacementController =
|
||||
UnityEngine.Object.FindAnyObjectByType<TowerPlacementController>();
|
||||
if (cachedPlacementController == null) return false;
|
||||
}
|
||||
return cachedPlacementController.IsPlacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue