noch mehr sprechen

This commit is contained in:
klappstuhl24 2024-04-06 21:43:51 +02:00
parent 2f5f25d0bd
commit 2ecb40333c
7 changed files with 174 additions and 45 deletions

View File

@ -267,7 +267,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!114 &37507748
MonoBehaviour:
m_ObjectHideFlags: 0
@ -489,8 +489,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: a61873b0f5608a44982d48387f34f682, type: 3}
m_Name:
m_EditorClassIdentifier:
ZombiePrefab: {fileID: 0}
_spawnRate: 1
ZombiePrefab: {fileID: 856601670117699726, guid: a34b2d22562c7214f9daf0d3dea8d85c, type: 3}
_spawnRate: 10
_spawnTimer: 0
--- !u!1001 &514859708
PrefabInstance:
@ -502,7 +502,7 @@ PrefabInstance:
m_Modifications:
- target: {fileID: 958156999735417459, guid: 7c7f0805c6bdc4f41bd65ec128f6b658, type: 3}
propertyPath: m_LocalPosition.x
value: 28.41
value: 28.09
objectReference: {fileID: 0}
- target: {fileID: 958156999735417459, guid: 7c7f0805c6bdc4f41bd65ec128f6b658, type: 3}
propertyPath: m_LocalPosition.y
@ -510,7 +510,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 958156999735417459, guid: 7c7f0805c6bdc4f41bd65ec128f6b658, type: 3}
propertyPath: m_LocalPosition.z
value: -3.352
value: -5.49
objectReference: {fileID: 0}
- target: {fileID: 958156999735417459, guid: 7c7f0805c6bdc4f41bd65ec128f6b658, type: 3}
propertyPath: m_LocalRotation.w
@ -616,6 +616,8 @@ MonoBehaviour:
serializedVersion: 2
m_Bits: 4294967295
grounded: 0
_hand: {fileID: 0}
_carriedItem: {fileID: 0}
--- !u!1 &547927580
GameObject:
m_ObjectHideFlags: 0
@ -1277,6 +1279,7 @@ MonoBehaviour:
_hungerNeed: {fileID: 0}
_wantedFood: 0
_toiletNeed: {fileID: 0}
_maxPrivateContextBufferSize: 5
_talkTimer: 10
--- !u!4 &983523620
Transform:
@ -1310,6 +1313,8 @@ MonoBehaviour:
speakingSpeed: 1.1
playSound: 0
generate: 0
newVoice: 0
Voice:
--- !u!114 &983523622
MonoBehaviour:
m_ObjectHideFlags: 0
@ -2081,6 +2086,8 @@ MonoBehaviour:
speakingSpeed: 1.1
playSound: 0
generate: 0
newVoice: 0
Voice:
--- !u!114 &1814492793
MonoBehaviour:
m_ObjectHideFlags: 0
@ -2135,6 +2142,7 @@ MonoBehaviour:
_hungerNeed: {fileID: 0}
_wantedFood: 0
_toiletNeed: {fileID: 0}
_maxPrivateContextBufferSize: 5
_talkTimer: 10
--- !u!82 &1814492795
AudioSource:

View File

@ -1,7 +1,9 @@
using Microsoft.VisualStudio.Utilities;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using UnityEngine;
using UnityEngine.Serialization;
using Utility;
@ -97,31 +99,51 @@ public class Developer : MonoBehaviour
[SerializeField]
private GameObject _caffeineNeed;
[SerializeField] private WantedConsumable _wantedDrink;
[SerializeField]
private WantedConsumable _wantedDrink;
[SerializeField]
private GameObject _hungerNeed;
[SerializeField] private WantedConsumable _wantedFood;
[SerializeField]
private WantedConsumable _wantedFood;
[SerializeField]
private GameObject _toiletNeed;
private AudioSource _audioSource;
private float _talkPauseTime = 15.0f;
private List<GameObject> _needList = new List<GameObject>();
private bool _isDead = false;
/// <summary>
/// indicates wether the Dev is dead or not
/// </summary>
public bool IsDead => _isDead;
[SerializeField]
private int _maxPrivateContextBufferSize = 2;
[SerializeField]
private CircularBuffer<string> _privateContextBuffer;
/// <summary>
/// Returns the private Context Buffer
/// </summary>
public CircularBuffer<string> PrivateContextBuffer => _privateContextBuffer;
// stuff for talking
[SerializeField, ShowOnly]
private float _talkTimer;
private AudioSource _audioSource;
private float _talkPauseTime = 15.0f;
private bool _hasTalkedWhileHyperactive = false;
private bool _hasTalkedWhileOvercaffeinated = false;
private List<GameObject> _needList = new List<GameObject>();
void Start()
{
_developerNeeds = gameObject.GetComponent<DeveloperNeeds>();
_audioSource = GetComponent<AudioSource>();
_talkTimer = UnityEngine.Random.Range(5.0f, 15.0f);
_talkTimer = 2.0f; //Random.Range(5.0f, 15.0f);
_fingersLeft = _baseStats.Fingers;
_privateContextBuffer = new CircularBuffer<string>(_maxPrivateContextBufferSize);
}
private void Update()
@ -138,6 +160,12 @@ public class Developer : MonoBehaviour
}
}
[ContextMenu("Hurt him")]
private void TestHurt()
{
Hurt();
}
[ContextMenu("Give Coffee")]
private void TestCoffee()
{
@ -183,12 +211,14 @@ public class Developer : MonoBehaviour
// TODO: Wie wäre es damit, das nicht fest zu coden?
if (drinkType == _wantedDrink)
{
Talk($"The Devolper thanks Gottfried for the {drinkType.GetAsString()}");
Talk($"The Developer thanks Gottfried for the {drinkType.GetAsString()}", 1);
_privateContextBuffer.Add($"The Developer is greatful for the {drinkType.GetAsString()} Gottfried recently brought him");
_happiness += 0.2;
}
else
{
Talk($"The Devolper blames Gottfried for bringing {drinkType.GetAsString()} but he actaully wanted a {_wantedDrink.GetAsString()}");
Talk($"The Developer is happy about the caffeine but he blames Gottfried for bringing {drinkType.GetAsString()} because he actaully wanted a {_wantedDrink.GetAsString()} instead", 0, true);
_privateContextBuffer.Add($"The Developer is still annoyed about when Gottfried recently brought him {drinkType.GetAsString()} instead of {_wantedDrink.GetAsString()}");
_happiness -= 0.2;
}
}
@ -214,7 +244,8 @@ public class Developer : MonoBehaviour
_needList.Remove(_hungerNeed);
NeedFullfilled(_hungerNeed);
_hungerNeed = null;
Talk("The Developer thanks Gottfried for the Pizza");
Talk("The Developer thanks Gottfried for the Pizza", 1);
_privateContextBuffer.Add($"The Developer is greatful for the Pizza Gottfried recently brought him");
}
if (_wantedFood != WantedConsumable.None)
@ -247,7 +278,8 @@ public class Developer : MonoBehaviour
_needList.Remove(_toiletNeed);
NeedFullfilled(_toiletNeed);
_toiletNeed = null;
Talk("The Developer finally can go to the toilet");
Talk("The Developer finally can go to the toilet", 1);
_privateContextBuffer.Add($"The developer is grateful that he went to the toilet a few minutes ago");
}
if (onToilet)
@ -309,6 +341,8 @@ public class Developer : MonoBehaviour
if (_hungerLevel <= 0.0)
{
if (!_isDead)
Talk($"The developer is starving, The developer is dying, The developer blames Gottfried for letting him starve with his last words", 0, true);
Die();
}
}
@ -414,11 +448,27 @@ public class Developer : MonoBehaviour
// Ob er stirbt oder nicht, für uns hat er auf jeden Fall seinen Nutzen verloren.
if (_fingersLeft == 0)
{
if (!_isDead)
Talk($"The developer lost all his fingers duo to an attack by a monster, The developer is dying, The developer gives a short speech with his last words, The developer blames Gottfried for his death", 0, true);
Die();
}
else
{
if (_fingersLeft == 9)
Talk($"The developer lost a finger duo to an attack by a monster, The developer has {_fingersLeft} left, The developer is in pain, The developer is irrevocably less productive now, The developer blames Gottfried for this", 0, true);
else
Talk($"The developer lost another finger duo to an attack by a monster, The developer has only {_fingersLeft} left, The developer is in pain, The developer is irrevocably less productive now, The developer blames Gottfried for this", 0, true);
if (Random.Range(0, 2) == 0)
_privateContextBuffer.Add($"The developer cries for his {10 - _fingersLeft} lost fingers");
else
_privateContextBuffer.Add($"The developer is greatful he still has {_fingersLeft} fingers");
}
}
private void Die()
{
_isDead = true;
Debug.Log($"{Name} ist verreckt.");
}
@ -428,29 +478,50 @@ public class Developer : MonoBehaviour
return distanceToPlayer <= _talkRange;
}
/// <summary>
/// Returns the context stored in the contextBuffer seperated with ',' as a string
/// </summary>
/// <returns></returns>
public string GetPrivateContextAsString()
{
if (_privateContextBuffer.Count != 0)
{
string output = "";
foreach (string context in _privateContextBuffer)
{
output += context + ", ";
}
return output;
}
return string.Empty;
}
/// <summary>
/// Starts talking when player is near to the Dev.
/// </summary>
public void TalkIfInRange()
{
if (IsGottfriedInRange())
if (IsGottfriedInRange() && !_isDead)
{
Talk();
string context = GetPrivateContextAsString();
context += GameManager.Instance.GetContextAsString();
Talk(context);
}
}
/// <summary>
/// Dev starts talking.
/// </summary>
public void Talk(string context = null)
public void Talk(string context, int shortnessLevel = 0, bool priority = false)
{
if (context == null)
if (priority)
{
context = GameManager.Instance.GetContextAsString();
_audioSource.Stop();
_audioSource.clip = null;
}
if (!_audioSource.isPlaying)
{
GetComponent<Text2Speech>().Generate(context);
GetComponent<Text2Speech>().Generate(context, shortnessLevel);
}
}
}

View File

@ -41,11 +41,11 @@ public class DeveloperNeeds : MonoBehaviour
{
case "coffee":
spawnedNeed = Instantiate(Needs[0], new Vector3(0.0f, 2f + (numNeeds * 0.5f), 0.0f), Needs[0].transform.rotation);
context = "The Developer wants coffee";
context = "The Developer wants Gottfried to bring him a coffee";
break;
case "mate":
spawnedNeed = Instantiate(Needs[1], new Vector3(0.0f, 2f + (numNeeds * 0.5f), 0.0f), Needs[0].transform.rotation);
context = "The Developer wants a Blub Mate (Yes, its a drink called Blub Mate)";
context = "The Developer wants Gottfried to bring him a Blub Mate (Yes, its a drink called Blub Mate)";
break;
case "toilet":
spawnedNeed = Instantiate(Needs[2], new Vector3(0.0f, 2f + (numNeeds * 0.5f), 0.0f), Needs[0].transform.rotation);
@ -53,7 +53,11 @@ public class DeveloperNeeds : MonoBehaviour
break;
case "hunger":
spawnedNeed = Instantiate(Needs[3], new Vector3(0.0f, 2f + (numNeeds * 0.5f), 0.0f), Needs[0].transform.rotation);
context = "The Developer wants a pizza";
context = "The Developer wants Gottfried to bring him a pizza";
break;
case "money":
spawnedNeed = Instantiate(Needs[3], new Vector3(0.0f, 2f + (numNeeds * 0.5f), 0.0f), Needs[0].transform.rotation);
context = "The Developer wants a raise, The Developer needs more money";
break;
default:
Debug.LogError($"Unbekannter need \"{needName}\"");
@ -66,7 +70,7 @@ public class DeveloperNeeds : MonoBehaviour
spawnedNeed.transform.localScale = new Vector3(0.4f, 0.01f, 0.4f);
if (!_audioSource.isPlaying)
{
_text2speech.Generate(context);
_text2speech.Generate(context, 1);
}
return spawnedNeed;
}

View File

@ -41,7 +41,7 @@ public partial class GameManager : MonoBehaviourSingleton<GameManager>
private DifficultySettings _difficultySettings;
[SerializeField]
private int _maxContextBufferSize = 5;
private int _maxContextBufferSize = 3;
[SerializeField]
private CircularBuffer<string> _contextBuffer;
@ -89,6 +89,8 @@ public partial class GameManager : MonoBehaviourSingleton<GameManager>
TimeManager.Instance.Init();
_contextBuffer = new CircularBuffer<string>(_maxContextBufferSize);
_contextBuffer.Add("The Developer is greatful to work at this office with Gottfried");
_contextBuffer.Add("The Developer excited to develope the new game");
_difficultySettings = _difficulty.GetSettings();
@ -203,7 +205,7 @@ public partial class GameManager : MonoBehaviourSingleton<GameManager>
}
return output;
}
return null;
return string.Empty;
}
/// <summary>

View File

@ -12,6 +12,7 @@ using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using Google.Cloud.TextToSpeech.V1;
using Palmmedia.ReportGenerator.Core;
[Serializable]
public class TextToSpeechResponse
@ -35,7 +36,7 @@ public class Text2Speech : MonoBehaviour
[SerializeField]
public bool generate = false;
[SerializeField]
public bool newVoiceAndGenerate = false;
public bool newVoice = false;
[SerializeField]
public string Voice;
@ -49,8 +50,10 @@ public class Text2Speech : MonoBehaviour
private OpenAIAPI _openAiApi;
private Conversation? _conversation;
private readonly string _openAiApiKey = "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";
private readonly string _prompt = "Write a short text for a Developer as an NPC in a game. The Developer works at a small gamedevelopement office and its manager is called Gottfried who is responsable for all the Developers needs. The text should be based on the following bullet-point context, which describes the events of the last moments. Remember to only respond with the short text that only this ONE Developer should speak and nothing else! The context is: ";
private readonly string _defaultPrompt = "Write a short text for a Developer as an NPC in a game. The Developer works at a small gamedevelopement office and its manager is called Gottfried who is responsable for all the Developers needs and protection. The text should be based on the following bullet-point context, which describes the events of the last moments. Remember to only respond with the short text that only this ONE Developer should speak and nothing else! The context is: ";
private readonly string _shortPrompt = "Write a relatively short text for a Developer as an NPC in a game. The Developer works at a small gamedevelopement office and its manager is called Gottfried who is responsable for all the Developers needs and protection. The text should be based on the following bullet-point context, which describes the events of the last moments. Remember to only respond with the relatively short text that only this ONE Developer should speak and nothing else! The context is: ";
private readonly string _veryShortPrompt = "Write a very short text for a Developer as an NPC in a game. The Developer works at a small gamedevelopement office and its manager is called Gottfried who is responsable for all the Developers needs and protection. The text should be based on the following bullet-point context, which describes the events of the last moments. Remember to only respond with the very short text that only this ONE Developer should speak and nothing else! The context is: ";
private int _shortnessLevel = 0;
void Start()
{
_tmpPath = "tmp_audio_" + GetInstanceID().ToString() + ".wav";
@ -69,7 +72,7 @@ public class Text2Speech : MonoBehaviour
generate = false;
if (voice == null)
{
GetRandomGermanVoice(gender, (v) => {
GetRandomEnglishVoice(gender, (v) => {
voice = v;
Voice = voice.ToString();
//Debug.Log($"GoogleCloud: Choosen voice is\n{voice}");
@ -81,27 +84,27 @@ public class Text2Speech : MonoBehaviour
StartCoroutine(GenerateAndSynthesizeText(context));
}
}
if (newVoiceAndGenerate)
if (newVoice)
{
newVoiceAndGenerate = false;
newVoice = false;
voice = null;
Voice = null;
generate = true;
}
}
public void Generate(string c)
public void Generate(string c, int shortnessLevel = 0)
{
context = c;
_shortnessLevel = shortnessLevel;
generate = true;
}
public void GetRandomGermanVoice(string gender, Action<JToken> callback)
public void GetRandomEnglishVoice(string gender, Action<JToken> callback)
{
StartCoroutine(GetRandomGermanVoiceCoroutine(gender, callback));
StartCoroutine(GetRandomEnglishVoiceCoroutine(gender, callback));
}
private IEnumerator GetRandomGermanVoiceCoroutine(string gender, Action<JToken> callback)
private IEnumerator GetRandomEnglishVoiceCoroutine(string gender, Action<JToken> callback)
{
string url = $"https://texttospeech.googleapis.com/v1beta1/voices?key={_googelCloudApiKey}";
@ -191,7 +194,19 @@ public class Text2Speech : MonoBehaviour
};
_conversation = _openAiApi.Chat.CreateConversation(chatRequest);
_conversation.AppendUserInput(_prompt + context);
string prompt = _defaultPrompt;
switch (_shortnessLevel)
{
case 1:
prompt = _shortPrompt; break;
case 2:
prompt = _veryShortPrompt; break;
default:
break;
}
_conversation.AppendUserInput(prompt + context);
string response = await _conversation.GetResponseFromChatbotAsync();
//Debug.Log($"ChatGPT: {response}");
return response;

View File

@ -8,3 +8,32 @@
"pitch": -2
}
{
"languageCodes": [
"en-US"
],
"name": "en-US-Studio-Q",
"ssmlGender": "MALE",
"naturalSampleRateHertz": 24000,
"pitch": 1
}
{
"languageCodes": [
"en-AU"
],
"name": "en-AU-Wavenet-D",
"ssmlGender": "MALE",
"naturalSampleRateHertz": 24000,
"pitch": 6
}
{
"languageCodes": [
"en-AU"
],
"name": "en-AU-Neural2-D",
"ssmlGender": "MALE",
"naturalSampleRateHertz": 24000,
"pitch": 2
}

View File

@ -25,7 +25,7 @@ public class ZombieSpawner : MonoBehaviour
if (_spawnTimer <= 0)
{
Instantiate(ZombiePrefab, transform.position, Quaternion.identity);
Instantiate(ZombiePrefab, transform.position, Quaternion.identity, transform);
_spawnTimer = 60 / _spawnRate;
}
}