From 2ecb40333cf706089c98183024f3ccf29b7b6dd7 Mon Sep 17 00:00:00 2001 From: klappstuhl24 Date: Sat, 6 Apr 2024 21:43:51 +0200 Subject: [PATCH] noch mehr sprechen --- 3d Prototyp/Assets/Scenes/GameLoopTest.unity | 18 ++- 3d Prototyp/Assets/Scripts/Developer.cs | 111 ++++++++++++++---- 3d Prototyp/Assets/Scripts/DeveloperNeeds.cs | 12 +- 3d Prototyp/Assets/Scripts/GameManager.cs | 6 +- 3d Prototyp/Assets/Scripts/Text2Speech.cs | 41 +++++-- .../Assets/Scripts/Utility/GoodVoices.txt | 29 +++++ 3d Prototyp/Assets/Scripts/ZombieSpawner.cs | 2 +- 7 files changed, 174 insertions(+), 45 deletions(-) diff --git a/3d Prototyp/Assets/Scenes/GameLoopTest.unity b/3d Prototyp/Assets/Scenes/GameLoopTest.unity index be6e17b5..95e2a15a 100644 --- a/3d Prototyp/Assets/Scenes/GameLoopTest.unity +++ b/3d Prototyp/Assets/Scenes/GameLoopTest.unity @@ -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: diff --git a/3d Prototyp/Assets/Scripts/Developer.cs b/3d Prototyp/Assets/Scripts/Developer.cs index 543fe054..79af2be2 100644 --- a/3d Prototyp/Assets/Scripts/Developer.cs +++ b/3d Prototyp/Assets/Scripts/Developer.cs @@ -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 _needList = new List(); + private bool _isDead = false; + + /// + /// indicates wether the Dev is dead or not + /// + public bool IsDead => _isDead; + + [SerializeField] + private int _maxPrivateContextBufferSize = 2; + [SerializeField] + private CircularBuffer _privateContextBuffer; + + /// + /// Returns the private Context Buffer + /// + public CircularBuffer 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 _needList = new List(); - void Start() { _developerNeeds = gameObject.GetComponent(); _audioSource = GetComponent(); - _talkTimer = UnityEngine.Random.Range(5.0f, 15.0f); + _talkTimer = 2.0f; //Random.Range(5.0f, 15.0f); _fingersLeft = _baseStats.Fingers; + _privateContextBuffer = new CircularBuffer(_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,9 +244,10 @@ 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) { if (foodType == _wantedFood) @@ -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."); } @@ -426,31 +476,52 @@ public class Developer : MonoBehaviour { float distanceToPlayer = Vector3.Distance(transform.position, GameManager.Instance.PlayerTransform.position); return distanceToPlayer <= _talkRange; - } + } + + /// + /// Returns the context stored in the contextBuffer seperated with ',' as a string + /// + /// + public string GetPrivateContextAsString() + { + if (_privateContextBuffer.Count != 0) + { + string output = ""; + foreach (string context in _privateContextBuffer) + { + output += context + ", "; + } + return output; + } + return string.Empty; + } /// /// Starts talking when player is near to the Dev. /// public void TalkIfInRange() { - if (IsGottfriedInRange()) + if (IsGottfriedInRange() && !_isDead) { - Talk(); + string context = GetPrivateContextAsString(); + context += GameManager.Instance.GetContextAsString(); + Talk(context); } } /// /// Dev starts talking. /// - 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().Generate(context); + { + GetComponent().Generate(context, shortnessLevel); } } } diff --git a/3d Prototyp/Assets/Scripts/DeveloperNeeds.cs b/3d Prototyp/Assets/Scripts/DeveloperNeeds.cs index c0d89483..c2165cdc 100644 --- a/3d Prototyp/Assets/Scripts/DeveloperNeeds.cs +++ b/3d Prototyp/Assets/Scripts/DeveloperNeeds.cs @@ -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; } diff --git a/3d Prototyp/Assets/Scripts/GameManager.cs b/3d Prototyp/Assets/Scripts/GameManager.cs index 0b7be640..0a14805e 100644 --- a/3d Prototyp/Assets/Scripts/GameManager.cs +++ b/3d Prototyp/Assets/Scripts/GameManager.cs @@ -41,7 +41,7 @@ public partial class GameManager : MonoBehaviourSingleton private DifficultySettings _difficultySettings; [SerializeField] - private int _maxContextBufferSize = 5; + private int _maxContextBufferSize = 3; [SerializeField] private CircularBuffer _contextBuffer; @@ -89,6 +89,8 @@ public partial class GameManager : MonoBehaviourSingleton TimeManager.Instance.Init(); _contextBuffer = new CircularBuffer(_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 } return output; } - return null; + return string.Empty; } /// diff --git a/3d Prototyp/Assets/Scripts/Text2Speech.cs b/3d Prototyp/Assets/Scripts/Text2Speech.cs index d0c60f19..7fa9e6f8 100644 --- a/3d Prototyp/Assets/Scripts/Text2Speech.cs +++ b/3d Prototyp/Assets/Scripts/Text2Speech.cs @@ -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,9 +72,9 @@ public class Text2Speech : MonoBehaviour generate = false; if (voice == null) { - GetRandomGermanVoice(gender, (v) => { + GetRandomEnglishVoice(gender, (v) => { voice = v; - Voice = voice.ToString(); + Voice = voice.ToString(); //Debug.Log($"GoogleCloud: Choosen voice is\n{voice}"); StartCoroutine(GenerateAndSynthesizeText(context)); }); @@ -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 callback) + public void GetRandomEnglishVoice(string gender, Action callback) { - StartCoroutine(GetRandomGermanVoiceCoroutine(gender, callback)); + StartCoroutine(GetRandomEnglishVoiceCoroutine(gender, callback)); } - private IEnumerator GetRandomGermanVoiceCoroutine(string gender, Action callback) + private IEnumerator GetRandomEnglishVoiceCoroutine(string gender, Action 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; diff --git a/3d Prototyp/Assets/Scripts/Utility/GoodVoices.txt b/3d Prototyp/Assets/Scripts/Utility/GoodVoices.txt index b172982d..685791ad 100644 --- a/3d Prototyp/Assets/Scripts/Utility/GoodVoices.txt +++ b/3d Prototyp/Assets/Scripts/Utility/GoodVoices.txt @@ -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 +} \ No newline at end of file diff --git a/3d Prototyp/Assets/Scripts/ZombieSpawner.cs b/3d Prototyp/Assets/Scripts/ZombieSpawner.cs index eb7dcd35..28b62b46 100644 --- a/3d Prototyp/Assets/Scripts/ZombieSpawner.cs +++ b/3d Prototyp/Assets/Scripts/ZombieSpawner.cs @@ -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; } }