started building out level

Signed-off-by: sdqhome\caleb <caleb@sdqhome.co.uk>
This commit is contained in:
2026-08-05 08:18:15 +01:00
parent f53c8256df
commit 7b8d500f75
6372 changed files with 6314829 additions and 20587 deletions

View File

@@ -3,6 +3,7 @@ using UnityEngine.AI;
using UnityEngine.InputSystem;
[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(CombatController))]
public class PlayerController : MonoBehaviour
{
[Header("Movement Settings")]
@@ -11,9 +12,11 @@ public class PlayerController : MonoBehaviour
[SerializeField] private float stoppingDistance = 0.2f;
[SerializeField] private LayerMask groundLayer = ~0; // Default to all layers
[Header("Interaction Settings")]
[Header("Interaction & Combat Settings")]
[SerializeField] private LayerMask interactableLayer = ~0;
[SerializeField] private float defaultInteractionRadius = 2.0f;
[Tooltip("If true, the player automatically turns to attack any enemy that damages them (RuneScape style).")]
[SerializeField] private bool autoRetaliate = true;
[Header("Visual Feedback Prefabs (Optional)")]
[SerializeField] private GameObject moveClickEffectPrefab;
@@ -22,6 +25,7 @@ public class PlayerController : MonoBehaviour
private Camera mainCamera;
private CharacterController characterController;
private NavMeshAgent navAgent;
private CombatController combatController;
private Vector3 targetPosition;
private IInteractable targetInteractable;
@@ -33,7 +37,13 @@ public class PlayerController : MonoBehaviour
mainCamera = Camera.main;
characterController = GetComponent<CharacterController>();
navAgent = GetComponent<NavMeshAgent>();
combatController = GetComponent<CombatController>();
targetPosition = transform.position;
if (combatController != null && combatController.Stats != null)
{
combatController.Stats.onHealthChanged.AddListener(OnHealthChanged);
}
}
private void Update()
@@ -41,6 +51,7 @@ public class PlayerController : MonoBehaviour
HandleInput();
ProcessMovement();
ProcessInteractionCheck();
ProcessCombatCheck();
}
private void HandleInput()
@@ -58,7 +69,7 @@ public class PlayerController : MonoBehaviour
HandleLeftClickOrDrag(screenMousePos, isFirstPress);
}
// Right Click: Interact with object
// Right Click: Interact with object or attack enemy
if (currentMouse.rightButton.wasPressedThisFrame)
{
HandleRightClick(screenMousePos);
@@ -72,6 +83,7 @@ public class PlayerController : MonoBehaviour
{
SetDestination(hit.point);
ClearTargetInteractable();
combatController.ClearTarget();
// Only spawn click effect on the initial click frame (not every frame while dragging)
if (isFirstPress)
@@ -84,11 +96,26 @@ public class PlayerController : MonoBehaviour
private void HandleRightClick(Vector2 screenPosition)
{
Ray ray = mainCamera.ScreenPointToRay(screenPosition);
// Check for Raycast hit on Interactable or Enemy
if (Physics.Raycast(ray, out RaycastHit hit, 100f, interactableLayer))
{
IInteractable interactable = hit.collider.GetComponentInParent<IInteractable>();
// Check if object is an Enemy / CharacterStats for Combat
CharacterStats enemyStats = hit.collider.GetComponent<CharacterStats>() ?? hit.collider.GetComponentInParent<CharacterStats>() ?? hit.collider.GetComponentInChildren<CharacterStats>();
if (enemyStats != null && enemyStats != combatController.Stats && !enemyStats.IsDead)
{
ClearTargetInteractable();
combatController.SetTarget(enemyStats);
SetDestination(enemyStats.transform.position);
SpawnEffect(interactClickEffectPrefab, hit.point);
return;
}
// Check if object is an IInteractable
IInteractable interactable = hit.collider.GetComponent<IInteractable>() ?? hit.collider.GetComponentInParent<IInteractable>() ?? hit.collider.GetComponentInChildren<IInteractable>();
if (interactable != null)
{
combatController.ClearTarget();
targetInteractable = interactable;
isMovingToInteractable = true;
SetDestination(interactable.GetTransform().position);
@@ -97,10 +124,60 @@ public class PlayerController : MonoBehaviour
}
}
// Right-clicked ground with no interactable
// Right-clicked ground with no interactable/enemy
if (Physics.Raycast(ray, out RaycastHit groundHit, 100f, groundLayer))
{
ClearTargetInteractable();
combatController.ClearTarget();
}
}
private void ProcessCombatCheck()
{
if (combatController.CurrentTarget == null) return;
if (combatController.CurrentTarget.IsDead)
{
combatController.ClearTarget();
return;
}
// Update destination to track moving target
targetPosition = combatController.CurrentTarget.transform.position;
if (navAgent != null && navAgent.enabled)
{
navAgent.stoppingDistance = combatController.Stats.AttackRange * 0.9f;
navAgent.SetDestination(targetPosition);
}
// Check if inside attack range
if (combatController.IsInAttackRange(combatController.CurrentTarget))
{
isMoving = false;
if (navAgent != null && navAgent.enabled && navAgent.hasPath)
{
navAgent.ResetPath();
}
combatController.TryExecuteAttack();
}
}
private void OnHealthChanged(float currentHealth, float maxHealth)
{
if (!autoRetaliate || combatController.CurrentTarget != null) return;
// Scan nearby hostile objects / enemies that are attacking the player
Collider[] hits = Physics.OverlapSphere(transform.position, 10.0f, interactableLayer);
foreach (var hit in hits)
{
CharacterStats attackerStats = hit.GetComponent<CharacterStats>() ?? hit.GetComponentInParent<CharacterStats>() ?? hit.GetComponentInChildren<CharacterStats>();
if (attackerStats != null && attackerStats != combatController.Stats && !attackerStats.IsDead)
{
combatController.SetTarget(attackerStats);
SetDestination(attackerStats.transform.position);
Debug.Log($"[PlayerController] Auto-retaliating against '{attackerStats.CharacterName}'!");
break;
}
}
}
@@ -122,6 +199,12 @@ public class PlayerController : MonoBehaviour
// If using NavMeshAgent
if (navAgent != null && navAgent.enabled)
{
float targetStoppingDistance = isMovingToInteractable && targetInteractable != null
? (targetInteractable.GetInteractionRadius() > 0 ? targetInteractable.GetInteractionRadius() : defaultInteractionRadius) * 0.9f
: stoppingDistance;
navAgent.stoppingDistance = targetStoppingDistance;
if (!navAgent.pathPending && navAgent.remainingDistance <= navAgent.stoppingDistance)
{
if (!navAgent.hasPath || navAgent.velocity.sqrMagnitude == 0f)
@@ -138,7 +221,7 @@ public class PlayerController : MonoBehaviour
float distance = direction.magnitude;
float currentStoppingDistance = isMovingToInteractable && targetInteractable != null
? targetInteractable.GetInteractionRadius()
? (targetInteractable.GetInteractionRadius() > 0 ? targetInteractable.GetInteractionRadius() : defaultInteractionRadius) * 0.9f
: stoppingDistance;
if (distance > currentStoppingDistance)
@@ -161,10 +244,13 @@ public class PlayerController : MonoBehaviour
{
if (!isMovingToInteractable || targetInteractable == null) return;
float distance = Vector3.Distance(transform.position, targetInteractable.GetTransform().position);
Vector3 flatPlayerPos = new Vector3(transform.position.x, 0, transform.position.z);
Vector3 flatTargetPos = new Vector3(targetInteractable.GetTransform().position.x, 0, targetInteractable.GetTransform().position.z);
float distance = Vector3.Distance(flatPlayerPos, flatTargetPos);
float radius = targetInteractable.GetInteractionRadius() > 0 ? targetInteractable.GetInteractionRadius() : defaultInteractionRadius;
if (distance <= radius)
if (distance <= radius + 0.1f)
{
// Face target interactable
Vector3 dir = (targetInteractable.GetTransform().position - transform.position);