update
This commit is contained in:
133
Assets/Scripts/AI NPC/ConversationManager.cs
Normal file
133
Assets/Scripts/AI NPC/ConversationManager.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
namespace Hallucinate.AI
|
||||
{
|
||||
public class ConversationManager : MonoBehaviour
|
||||
{
|
||||
public static ConversationManager Instance { get; private set; }
|
||||
|
||||
[Header("Settings")]
|
||||
public int maxSimultaneousConversations = 3;
|
||||
public float maxConversationDuration = 120f; // 2 minutes
|
||||
|
||||
private List<ConversationSession> activeSessions = new List<ConversationSession>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance == null) Instance = this;
|
||||
else Destroy(gameObject);
|
||||
}
|
||||
|
||||
public bool CanStartConversation()
|
||||
{
|
||||
return activeSessions.Count < maxSimultaneousConversations;
|
||||
}
|
||||
|
||||
public void StartConversation(EnemyAI initiator, EnemyAI responder)
|
||||
{
|
||||
if (!CanStartConversation()) return;
|
||||
|
||||
ConversationSession session = new ConversationSession(initiator, responder, maxConversationDuration);
|
||||
activeSessions.Add(session);
|
||||
StartCoroutine(RunConversation(session));
|
||||
}
|
||||
|
||||
private IEnumerator RunConversation(ConversationSession session)
|
||||
{
|
||||
Debug.Log($"<color=cyan>[ConvManager]</color> Starting: {session.initiator.npcName} & {session.responder.npcName}");
|
||||
|
||||
// Phase 1: Initiator speaks
|
||||
bool phase1Complete = false;
|
||||
session.RequestDialogue(session.initiator, (success) => phase1Complete = true);
|
||||
|
||||
float startTime = Time.time;
|
||||
while (!phase1Complete && Time.time < startTime + 10f) yield return null;
|
||||
|
||||
if (phase1Complete && !session.isInterrupted)
|
||||
{
|
||||
yield return new WaitForSeconds(4f); // Reading time
|
||||
|
||||
// Phase 2: Responder speaks
|
||||
bool phase2Complete = false;
|
||||
session.RequestDialogue(session.responder, (success) => phase2Complete = true);
|
||||
|
||||
float phase2StartTime = Time.time;
|
||||
while (!phase2Complete && Time.time < phase2StartTime + 10f) yield return null;
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(4f);
|
||||
EndConversation(session);
|
||||
}
|
||||
|
||||
public void EndConversation(ConversationSession session)
|
||||
{
|
||||
if (activeSessions.Contains(session))
|
||||
{
|
||||
session.Cleanup();
|
||||
activeSessions.Remove(session);
|
||||
Debug.Log($"<color=cyan>[ConvManager]</color> Ended session. Active: {activeSessions.Count}");
|
||||
}
|
||||
}
|
||||
|
||||
public void InterruptConversation(EnemyAI npc)
|
||||
{
|
||||
ConversationSession session = activeSessions.Find(s => s.initiator == npc || s.responder == npc);
|
||||
if (session != null)
|
||||
{
|
||||
session.isInterrupted = true;
|
||||
EndConversation(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ConversationSession
|
||||
{
|
||||
public EnemyAI initiator;
|
||||
public EnemyAI responder;
|
||||
public float durationLimit;
|
||||
public bool isInterrupted;
|
||||
|
||||
public ConversationSession(EnemyAI initiator, EnemyAI responder, float limit)
|
||||
{
|
||||
this.initiator = initiator;
|
||||
this.responder = responder;
|
||||
this.durationLimit = limit;
|
||||
|
||||
initiator.isTalking = true;
|
||||
responder.isTalking = true;
|
||||
|
||||
// Set references for Gizmos and Facing
|
||||
initiator.SetTalkingPartner(responder);
|
||||
responder.SetTalkingPartner(initiator);
|
||||
}
|
||||
|
||||
public void RequestDialogue(EnemyAI speaker, Action<bool> callback)
|
||||
{
|
||||
if (isInterrupted) { callback?.Invoke(false); return; }
|
||||
|
||||
EnemyAI listener = (speaker == initiator) ? responder : initiator;
|
||||
|
||||
// Face each other
|
||||
speaker.FaceTarget(listener.transform.position);
|
||||
listener.FaceTarget(speaker.transform.position);
|
||||
|
||||
string prompt = $"You are {speaker.npcName} talking to {listener.npcName}. Previous context: None. " +
|
||||
"Keep it natural and short.";
|
||||
|
||||
GeminiService.Instance.GetResponse(speaker.persona, prompt, (json) => {
|
||||
if (isInterrupted) { callback?.Invoke(false); return; }
|
||||
speaker.ProcessDialogueResult(json);
|
||||
callback?.Invoke(true);
|
||||
});
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
if (initiator != null) initiator.isTalking = false;
|
||||
if (responder != null) responder.isTalking = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user