Working on quests, moved to CineMachine for camera and started to build out areas, started combat system
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.AI;
|
||||
using EasyTalk.Controller;
|
||||
using EasyTalk.Nodes;
|
||||
|
||||
public abstract class Character : MonoBehaviour
|
||||
{
|
||||
@@ -34,6 +36,22 @@ public abstract class Character : MonoBehaviour
|
||||
[SerializeField]
|
||||
protected int MaxHp = 10;
|
||||
|
||||
[Header("Dialogue")]
|
||||
public bool hasDialogue = false;
|
||||
[Tooltip("The Dialogue asset for this character. Will be loaded into the central DialogueController.")]
|
||||
public Dialogue dialogue;
|
||||
[Tooltip("Optional: Entry point name for starting dialogue. Leave empty to use default entry point.")]
|
||||
public string dialogueEntryPoint = "";
|
||||
[Tooltip("Name of the GameObject with the central DialogueController. Leave empty to auto-find.")]
|
||||
public string dialogueManagerName = "Manager";
|
||||
|
||||
[Header("Debug")]
|
||||
[SerializeField]
|
||||
protected bool enableDebugLogs = false;
|
||||
|
||||
// Cache the central DialogueController
|
||||
protected static DialogueController centralDialogueController;
|
||||
|
||||
[Header("Components")]
|
||||
// Optional movement controller reference, assign in inspector if used
|
||||
public NavMeshMovementController MovementController;
|
||||
@@ -219,6 +237,174 @@ public abstract class Character : MonoBehaviour
|
||||
SetFloatIfExists(paramHeadVertical, vertical);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make character look at a target with head rotation, body rotation when clamped
|
||||
/// </summary>
|
||||
public void LookAtTarget(Transform target)
|
||||
{
|
||||
if (target == null) return;
|
||||
|
||||
Vector3 directionToTarget = target.position - transform.position;
|
||||
directionToTarget.y = 0; // Keep on horizontal plane
|
||||
|
||||
if (directionToTarget.sqrMagnitude < 0.01f) return;
|
||||
|
||||
// Calculate angle to target
|
||||
float angleToTarget = Vector3.SignedAngle(transform.forward, directionToTarget, Vector3.up);
|
||||
|
||||
// Head rotation limits (before body needs to rotate)
|
||||
const float headHorizontalLimit = 60f;
|
||||
|
||||
if (Mathf.Abs(angleToTarget) > headHorizontalLimit)
|
||||
{
|
||||
// Rotate body to face target
|
||||
Quaternion targetRotation = Quaternion.LookRotation(directionToTarget);
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f);
|
||||
|
||||
// Reset head to neutral when body rotates
|
||||
SetHeadLook(0f, 0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just rotate head
|
||||
float normalizedAngle = angleToTarget / headHorizontalLimit; // -1 to 1
|
||||
SetHeadLook(normalizedAngle, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when player interacts with this character. Override to add custom behavior.
|
||||
/// </summary>
|
||||
public virtual void OnInteract(GameObject player)
|
||||
{
|
||||
Log($"Interacting with {gameObject.name}");
|
||||
|
||||
// Look at player
|
||||
if (player != null)
|
||||
{
|
||||
LookAtTarget(player.transform);
|
||||
|
||||
// Make player look at this character
|
||||
Character playerChar = player.GetComponent<Character>();
|
||||
if (playerChar != null)
|
||||
{
|
||||
playerChar.LookAtTarget(transform);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDialogue)
|
||||
{
|
||||
ShowDialogue();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display dialogue for this character using EasyTalk with centralized DialogueController
|
||||
/// </summary>
|
||||
/// <param name="entryPoint">Optional entry point override. If null/empty, uses dialogueEntryPoint field.</param>
|
||||
protected virtual void ShowDialogue(string entryPoint = null)
|
||||
{
|
||||
// Find the central DialogueController if not cached
|
||||
if (centralDialogueController == null)
|
||||
{
|
||||
centralDialogueController = FindCentralDialogueController();
|
||||
}
|
||||
|
||||
// Check if we have both a controller and dialogue asset
|
||||
if (centralDialogueController != null && dialogue != null)
|
||||
{
|
||||
// Load this character's dialogue into the central controller
|
||||
centralDialogueController.ChangeDialogue(dialogue);
|
||||
|
||||
// Use provided entry point, fallback to field, then default
|
||||
string targetEntryPoint = !string.IsNullOrEmpty(entryPoint) ? entryPoint : dialogueEntryPoint;
|
||||
|
||||
// Play dialogue with optional entry point
|
||||
if (!string.IsNullOrEmpty(targetEntryPoint))
|
||||
{
|
||||
centralDialogueController.PlayDialogue(targetEntryPoint);
|
||||
Log($"{gameObject.name}: Starting EasyTalk dialogue at entry point '{targetEntryPoint}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
centralDialogueController.PlayDialogue();
|
||||
Log($"{gameObject.name}: Starting EasyTalk dialogue");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Warnings for missing components
|
||||
if (centralDialogueController == null)
|
||||
{
|
||||
Debug.LogWarning($"No central DialogueController found. Make sure there's a DialogueController on a GameObject named '{dialogueManagerName}'.", gameObject);
|
||||
}
|
||||
if (dialogue == null)
|
||||
{
|
||||
Debug.LogWarning($"No Dialogue asset assigned to {gameObject.name}. Assign a Dialogue asset in the inspector.", gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Public wrapper for UnityEvents or other triggers
|
||||
/// </summary>
|
||||
/// <param name="entryPoint">Optional entry point name. If empty, uses default dialogueEntryPoint.</param>
|
||||
public virtual void StartDialogue(string entryPoint = "")
|
||||
{
|
||||
// Look at player if available
|
||||
if (Player.current != null)
|
||||
{
|
||||
LookAtTarget(Player.current.transform);
|
||||
|
||||
// Make player look at this character
|
||||
Player.current.LookAtTarget(transform);
|
||||
}
|
||||
|
||||
ShowDialogue(entryPoint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the central DialogueController in the scene
|
||||
/// </summary>
|
||||
protected DialogueController FindCentralDialogueController()
|
||||
{
|
||||
// First, try to find by the specified manager name
|
||||
if (!string.IsNullOrEmpty(dialogueManagerName))
|
||||
{
|
||||
GameObject manager = GameObject.Find(dialogueManagerName);
|
||||
if (manager != null)
|
||||
{
|
||||
DialogueController controller = manager.GetComponent<DialogueController>();
|
||||
if (controller != null)
|
||||
{
|
||||
Log($"Found central DialogueController on '{dialogueManagerName}'");
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: search for any DialogueController in the scene
|
||||
DialogueController foundController = FindAnyObjectByType<DialogueController>();
|
||||
if (foundController != null)
|
||||
{
|
||||
Log($"Found DialogueController via FindAnyObjectByType on '{foundController.gameObject.name}'");
|
||||
return foundController;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debug logging utility
|
||||
/// </summary>
|
||||
protected void Log(string message)
|
||||
{
|
||||
if (enableDebugLogs)
|
||||
{
|
||||
Debug.Log($"[{GetType().Name}] {message}", gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyStaticAnimatorParams()
|
||||
{
|
||||
if (animator == null) return;
|
||||
@@ -322,6 +508,9 @@ public abstract class Character : MonoBehaviour
|
||||
yield return new WaitForSeconds(attackHoldSeconds);
|
||||
}
|
||||
SetBoolIfExists(paramShoot, false);
|
||||
|
||||
// Wait one frame for animator to process the Shoot_b = false transition
|
||||
yield return null;
|
||||
|
||||
if (restoreWeaponAfterAttack)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user