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/BuilderInputController.cs
Normal file
121
Assets/_Project/Scripts/Gameplay/BuilderInputController.cs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// Assets/_Project/Scripts/Gameplay/BuilderInputController.cs
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using TD.Core;
|
||||
|
||||
namespace TD.Gameplay
|
||||
{
|
||||
/// <summary>
|
||||
/// Owner-only client-side controller for builder input. Handles right-click-to-move,
|
||||
/// deferring to placement mode (right-click cancels placement instead).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para><b>Owner-only.</b> This component lives on the same GameObject as
|
||||
/// <see cref="Builder"/> but only its owning client processes input. Non-owner clients
|
||||
/// have this component but its Update is a no-op. The owner sends move requests via
|
||||
/// <see cref="Builder.RequestMoveRpc"/>.</para>
|
||||
///
|
||||
/// <para><b>Right-click priority.</b> If <c>TowerPlacementController.IsPlacing</c> is
|
||||
/// true, right-click cancels placement (handled by <c>TowerPlacementController</c>
|
||||
/// itself). When NOT placing, right-click moves the builder.</para>
|
||||
///
|
||||
/// <para><b>Raycast target.</b> The cursor is raycast against the BuildablePlane layer
|
||||
/// (same as placement). The hit point's XZ is sent as the target; Y is recomputed by
|
||||
/// the server via terrain raycast.</para>
|
||||
/// </remarks>
|
||||
public class BuilderInputController : NetworkBehaviour
|
||||
{
|
||||
// ----- Inspector --------------------------------------------------
|
||||
|
||||
[Tooltip("Physics layer mask for the BuildablePlane collider. Cursor is raycast " +
|
||||
"against this layer to determine the move target.")]
|
||||
[SerializeField] private LayerMask buildablePlaneLayerMask;
|
||||
|
||||
[Tooltip("Maximum raycast distance for cursor → world conversion.")]
|
||||
[SerializeField] private float raycastMaxDistance = 500f;
|
||||
|
||||
// Cached reference to the sibling Builder component.
|
||||
private Builder builder;
|
||||
|
||||
// Cached reference to the local TowerPlacementController, looked up lazily because
|
||||
// it may not exist at OnNetworkSpawn time.
|
||||
private TowerPlacementController cachedPlacementController;
|
||||
|
||||
// ----- Lifecycle --------------------------------------------------
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
builder = GetComponent<Builder>();
|
||||
if (builder == null)
|
||||
{
|
||||
Debug.LogError("[BuilderInputController] Missing Builder component on the " +
|
||||
"same GameObject. Disabling input.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Non-owners do nothing.
|
||||
if (!IsOwner)
|
||||
{
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ----- Input handling ---------------------------------------------
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Defensive: enabled is set false for non-owners in OnNetworkSpawn, but keep
|
||||
// the IsOwner check here in case order-of-operations changes.
|
||||
if (!IsOwner) return;
|
||||
|
||||
var mouse = Mouse.current;
|
||||
if (mouse == null) return;
|
||||
|
||||
if (!mouse.rightButton.wasPressedThisFrame) return;
|
||||
|
||||
// Defer to placement mode: if the player is placing a tower, right-click cancels
|
||||
// placement rather than moving the builder. TowerPlacementController handles
|
||||
// the cancel itself; we just don't process the click here.
|
||||
if (IsLocalPlayerPlacing()) return;
|
||||
|
||||
// Cursor → world.
|
||||
if (!TryGetBuildablePlaneHit(mouse.position.ReadValue(), out Vector3 worldPoint))
|
||||
return;
|
||||
|
||||
// Submit to server.
|
||||
builder.RequestMoveRpc(worldPoint);
|
||||
}
|
||||
|
||||
// ----- Helpers ----------------------------------------------------
|
||||
|
||||
private bool IsLocalPlayerPlacing()
|
||||
{
|
||||
if (cachedPlacementController == null)
|
||||
{
|
||||
// Find lazily — controller may have been added after this component spawned.
|
||||
cachedPlacementController =
|
||||
UnityEngine.Object.FindAnyObjectByType<TowerPlacementController>();
|
||||
if (cachedPlacementController == null) return false;
|
||||
}
|
||||
return cachedPlacementController.IsPlacing;
|
||||
}
|
||||
|
||||
private bool TryGetBuildablePlaneHit(Vector2 screenPos, out Vector3 hitPoint)
|
||||
{
|
||||
hitPoint = Vector3.zero;
|
||||
|
||||
var cam = Camera.main;
|
||||
if (cam == null) return false;
|
||||
|
||||
Ray ray = cam.ScreenPointToRay(new Vector3(screenPos.x, screenPos.y, 0f));
|
||||
if (Physics.Raycast(ray, out RaycastHit hit, raycastMaxDistance, buildablePlaneLayerMask))
|
||||
{
|
||||
hitPoint = hit.point;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue