started building out level
Signed-off-by: sdqhome\caleb <caleb@sdqhome.co.uk>
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user