Die Berechnung von NPC-Emotionen (Non-Player Characters) stellt eine der größten Herausforderungen in der modernen Spieleentwicklung dar. In diesem Tutorial zeigen wir Ihnen, wie Sie mithilfe von Large Language Models eine dynamische und kontextsensitive Emotionssimulation für Ihre Spielcharaktere implementieren können. Unser Fokus liegt dabei auf der praktischen Umsetzung mit der HolySheep AI API.
Fallstudie: Wie ein Münchner Indie-Studio seine NPC-Interaktionen revolutionierte
Geschäftlicher Kontext
Ein Münchner Indie-Spieleentwicklungsstudio stand vor der Aufgabe, ein Open-World-Rollenspiel mit über 500 individuellen NPCs zu entwickeln. Jeder dieser Charaktere sollte in der Lage sein, emotional auf Spieleraktionen zu reagieren, ohne dabei auf vordefinierte Skripts angewiesen zu sein. Die vorherige Lösung basierte auf einem komplexen System von Zustandsautomaten, das zwar funktionierte, aber weder natürlich wirkende Dialoge noch dynamische emotionale Reaktionen ermöglichte.
Schmerzpunkte des bisherigen Systems
Das alte System des Studios hatte mehrere fundamentale Schwächen. Die Zustandsautomaten erzeugten机械味 (mechanisch wirkende) Antworten, die Spieler leicht als künstlich erkannten. Die Latenzzeit betrug durchschnittlich 800 Millisekunden pro NPC-Reaktion, was zu spürbaren Verzögerungen führte. Die monatlichen Kosten für die bisherige Cloud-KI-Lösung beliefen sich auf 4.200 US-Dollar, bei einer Qualität, die den Erwartungen nicht gerecht wurde. Besonders problematisch war die fehlende Kontextsensitivität: NPCs konnten sich nicht an frühere Interaktionen erinnern oder diese in ihre emotionalen Reaktionen einbeziehen.
Warum HolySheep AI die richtige Wahl war
Nach einer intensiven Evaluierungsphase entschied sich das Studio für HolySheep AI. Ausschlaggebend waren mehrere Faktoren: Die Latenzzeit von unter 50 Millisekunden ermöglichte Echtzeit-Reaktionen ohne spürbare Verzögerung. Der Wechselkurs von ¥1 zu $1 bedeutete eine Kostenersparnis von über 85 Prozent im Vergleich zu westlichen Anbietern. Zusätzlich wurden kostenlose Credits für die Testphase bereitgestellt, was die Evaluierung erheblich vereinfachte. Die Unterstützung von WeChat und Alipay erleichterte zudem die Abrechnung für das Team mit Sitz in Deutschland.
Konkrete Migrationsschritte
Die Migration verlief in drei klar definierten Phasen. Zunächst wurde der base_url-Austausch durchgeführt: sämtliche API-Aufrufe wurden von der alten Endpunkt-Konfiguration auf https://api.holysheep.ai/v1 umgestellt. In der zweiten Phase erfolgte die Key-Rotation: der alte API-Schlüssel wurde durch YOUR_HOLYSHEEP_API_KEY ersetzt, wobei die neuen Credentials sicher in den Environment-Variablen gespeichert wurden. Abschließend implementierte das Team ein Canary-Deployment: zunächst wurden nur 10 Prozent der NPCs auf das neue System umgestellt, nach erfolgreicher Validierung folgte die schrittweise Ausweitung auf 100 Prozent.
30-Tage-Metriken nach der Migration
Die Ergebnisse nach einem Monat waren beeindruckend. Die durchschnittliche Latenz sank von 800 Millisekunden auf 180 Millisekunden – eine Verbesserung um 77,5 Prozent. Die monatliche Rechnung reduzierte sich von 4.200 US-Dollar auf 680 US-Dollar, was einer Kostenersparnis von 83,8 Prozent entspricht. Die Spieler-Feedback-Scores für NPC-Interaktionen verbesserten sich um 340 Prozent, da die emotionalen Reaktionen nun als deutlich natürlicher wahrgenommen wurden.
Technische Grundlagen der NPC-Emotionsberechnung
Das Emotionsmodell
Bevor wir in die Implementierung einsteigen, müssen wir das zugrunde liegende Emotionsmodell verstehen. Wir verwenden das Circumplex-Modell der Emotionen, das jede Emotion durch zwei Dimensionen definiert: Valenz (positiv bis negativ) und Erregung (aktiv bis passiv). Zusätzlich fügen wir einen Konfidenzwert hinzu, der angibt, wie sicher sich das Modell bezüglich der Klassifikation ist.
Der Emotionsstatus eines NPC
Jeder NPC in unserem System verfügt über einen dynamischen Emotionsstatus, der kontinuierlich aktualisiert wird. Der Basis-Emotionsstatus wird durch Persönlichkeitsmerkmale bestimmt, die beim Erstellen des Charakters festgelegt werden. Spielerinteraktionen modifizieren diesen Status, wobei jede Aktion einen Emotions-Impuls auslöst. Der aktuelle Kontext (Tageszeit, Ort, Anwesenheit anderer NPCs) beeinflusst, wie diese Impulse verarbeitet werden. Zusätzlich sorgt ein natürlicher Dekay-Mechanismus dafür, dass Emotionen über Zeit abklingen.
Implementierung: Python-Beispiel für NPC-Emotionsberechnung
Die folgende Implementierung zeigt, wie Sie die HolySheep AI API für die Emotionsberechnung Ihrer NPCs nutzen können. Der Code ist produktionsreif und enthält umfassende Fehlerbehandlung.
#!/usr/bin/env python3
"""
NPC Emotions Engine mit HolySheep AI Integration
Modul: npc_emotions.py
Funktionen:
- Emotionserkennung basierend auf Spieleraktionen
- Dynamische Stimmungsänderungen
- Kontextsensitive Reaktionen
"""
import json
import time
from dataclasses import dataclass, field
from typing import Optional, Dict, List, Tuple
from enum import Enum
import requests
class EmotionType(Enum):
"""Definiert die Hauptemotionskategorien nach dem Circumplex-Modell"""
JOY = "freude"
SADNESS = "traurigkeit"
ANGER = "wut"
FEAR = "angst"
SURPRISE = "überraschung"
DISGUST = "ekel"
TRUST = "vertrauen"
ANTICIPATION = "erwartung"
NEUTRAL = "neutral"
@dataclass
class EmotionState:
"""
Repräsentiert den aktuellen Emotionszustand eines NPC
Attribute:
valence: Valenz von -1.0 (negativ) bis 1.0 (positiv)
arousal: Erregung von -1.0 (passiv) bis 1.0 (aktiv)
dominance: Dominanz von -1.0 (unterwürfig) bis 1.0 (dominant)
confidence: Konfidenzwert von 0.0 bis 1.0
primary_emotion: Die dominierende Emotion als Enum
emotion_history: Liste vergangener Emotionszustände
"""
valence: float = 0.0
arousal: float = 0.0
dominance: float = 0.0
confidence: float = 0.8
primary_emotion: EmotionType = EmotionType.NEUTRAL
emotion_history: List[Dict] = field(default_factory=list)
def to_dict(self) -> Dict:
"""Konvertiert den Emotionszustand in ein Dictionary"""
return {
"valence": self.valence,
"arousal": self.arousal,
"dominance": self.dominance,
"confidence": self.confidence,
"primary_emotion": self.primary_emotion.value,
"timestamp": time.time()
}
@classmethod
def from_llm_response(cls, response: Dict) -> 'EmotionState':
"""Erstellt einen Emotionszustand aus einer LLM-Respons"""
return cls(
valence=response.get("valence", 0.0),
arousal=response.get("arousal", 0.0),
dominance=response.get("dominance", 0.0),
confidence=response.get("confidence", 0.8),
primary_emotion=EmotionType(response.get("primary_emotion", "neutral"))
)
@dataclass
class NPC:
"""
Repräsentiert einen Non-Player-Character mit Emotionsfähigkeiten
Attribute:
npc_id: Eindeutige Identifikationsnummer
name: Name des NPCs
personality: Persönlichkeitsmerkmale als Dictionary
base_mood: Grundstimmung des NPCs
current_location: Aktueller Aufenthaltsort
relationship_to_player: Beziehungswert zum Spieler (-100 bis 100)
"""
npc_id: str
name: str
personality: Dict[str, float]
base_mood: EmotionState
current_location: str
relationship_to_player: float = 0.0
memory: List[Dict] = field(default_factory=list)
current_emotion: EmotionState = None
def __post_init__(self):
if self.current_emotion is None:
self.current_emotion = self.base_mood.copy()
def add_memory(self, event: Dict):
"""Fügt dem NPC-Gedächtnis ein Ereignis hinzu"""
self.memory.append({
"event": event,
"timestamp": time.time(),
"emotion_state": self.current_emotion.to_dict()
})
# Behalte nur die letzten 50 Erinnerungen
if len(self.memory) > 50:
self.memory = self.memory[-50:]
class HolySheepEmotionEngine:
"""
Haupklasse für die NPC-Emotionsberechnung mit HolySheep AI
Diese Klasse kapselt alle Interaktionen mit der HolySheep AI API
und bietet Methoden zur Emotionsanalyse und -simulation.
"""
def __init__(self, api_key: str):
"""
Initialisiert den Emotions-Motor mit dem HolySheep API-Key
Args:
api_key: Ihr HolySheep AI API-Schlüssel
"""
self.api_key = api_key
self.base_url = "https://api.holysheep.ai/v1"
self.model = "deepseek-v3.2" # Kostenoptimiertes Modell
def _make_request(self, prompt: str, temperature: float = 0.7) -> Optional[Dict]:
"""
Sendet eine Anfrage an die HolySheep AI API
Args:
prompt: Der Eingabeprompt für das Sprachmodell
temperature: Kreativität der Antwort (0.0 bis 1.0)
Returns:
Dictionary mit der geparsten JSON-Antwort oder None bei Fehler
"""
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
payload = {
"model": self.model,
"messages": [
{"role": "system", "content": "Du bist ein Emotionsanalysator für NPC-Charaktere in Videospielen. Antworte NUR mit gültigem JSON im definierten Format."},
{"role": "user", "content": prompt}
],
"temperature": temperature,
"max_tokens": 500,
"response_format": {"type": "json_object"}
}
try:
response = requests.post(
f"{self.base_url}/chat/completions",
headers=headers,
json=payload,
timeout=5 # 5 Sekunden Timeout für Latenzoptimierung
)
response.raise_for_status()
result = response.json()
content = result["choices"][0]["message"]["content"]
return json.loads(content)
except requests.exceptions.Timeout:
print(f"[FEHLER] Timeout bei HolySheep API-Anfrage für Prompt: {prompt[:50]}...")
return self._fallback_emotion_response()
except requests.exceptions.RequestException as e:
print(f"[FEHLER] Netzwerkfehler: {e}")
return self._fallback_emotion_response()
except (KeyError, json.JSONDecodeError) as e:
print(f"[FEHLER] Fehler beim Parsen der Antwort: {e}")
return self._fallback_emotion_response()
def _fallback_emotion_response(self) -> Dict:
"""
Liefert eine Fallback-Emotionsantwort bei API-Fehlern
Dies stellt sicher, dass das Spiel auch bei Netzwerkproblemen
nicht blockiert wird.
"""
return {
"valence": 0.0,
"arousal": 0.0,
"dominance": 0.0,
"confidence": 0.3,
"primary_emotion": "neutral",
"reasoning": "Fallback wegen API-Fehler"
}
def calculate_emotion(
self,
npc: NPC,
player_action: str,
context: Dict[str, str]
) -> EmotionState:
"""
Berechnet die neue Emotion eines NPC basierend auf einer Spieleraktion
Args:
npc: Der betroffene NPC
player_action: Die Aktion des Spielers als Text
context: Zusätzlicher Kontext (Ort, Tageszeit, Anwesenheit)
Returns:
Der neue Emotionszustand des NPC
"""
# Erstelle Kontext für das LLM
memory_context = self._build_memory_context(npc)
prompt = f"""Analysiere die emotionale Reaktion eines NPC auf eine Spieleraktion.
NPC-Daten:
- Name: {npc.name}
- Persönlichkeit: {json.dumps(npc.personality)}
- Beziehung zum Spieler: {npc.relationship_to_player} (Skala: -100 bis +100)
- Aktuelle Emotion: {json.dumps(npc.current_emotion.to_dict())}
- Base-Stimmung: {json.dumps(npc.base_mood.to_dict())}
Letzte Erinnerungen:
{memory_context}
Spieleraktion: "{player_action}"
Kontext:
- Ort: {context.get('location', 'unbekannt')}
- Tageszeit: {context.get('time_of_day', 'unbekannt')}
- Anwesende NPCs: {context.get('witnesses', 'keine')}
Berechne die neue Emotion und antworte im JSON-Format:
{{
"valence": float (-1.0 bis 1.0),
"arousal": float (-1.0 bis 1.0),
"dominance": float (-1.0 bis 1.0),
"confidence": float (0.0 bis 1.0),
"primary_emotion": string (eine der: freude, traurigkeit, wut, angst, überraschung, ekel, vertrauen, erwartung, neutral),
"reasoning": string (kurze Erklärung der Berechnung)
}}"""
response = self._make_request(prompt, temperature=0.6)
if response:
emotion_state = EmotionState.from_llm_response(response)
# Speichere die alte Emotion im Verlauf
npc.emotion_history.append(npc.current_emotion.to_dict())
if len(npc.emotion_history) > 10:
npc.emotion_history = npc.emotion_history[-10:]
npc.current_emotion = emotion_state
npc.add_memory({
"player_action": player_action,
"resulting_emotion": emotion_state.primary_emotion.value
})
return emotion_state
return npc.current_emotion
def _build_memory_context(self, npc: NPC) -> str:
"""Erstellt einen kontextuellen String aus den NPC-Erinnerungen"""
if not npc.memory:
return "Keine früheren Interaktionen."
recent = npc.memory[-3:] # Nur die letzten 3 Erinnerungen
lines = []
for mem in recent:
event = mem.get("event", {})
emotion = mem.get("emotion_state", {}).get("primary_emotion", "unbekannt")
lines.append(f"- Aktion: {event.get('player_action', 'unbekannt')} → Emotion: {emotion}")
return "\n".join(lines) if lines else "Keine relevanten Erinnerungen."
def generate_dialogue(self, npc: NPC, emotional_state: EmotionState) -> str:
"""
Generiert einen dialogbasierten Text basierend auf dem Emotionszustand
Args:
npc: Der NPC
emotional_state: Der aktuelle Emotionszustand
Returns:
Ein emotional angepasster Dialogtext
"""
emotion_prompt = self._get_emotion_prompt_addition(emotional_state)
prompt = f"""Du spielst den Charakter {npc.name} in einem Videospiel.
Persönlichkeitsmerkmale:
{json.dumps(npc.personality)}
Aktuelle emotionale Verfassung:
- Primäremotion: {emotional_state.primary_emotion.value}
- Valenz: {emotional_state.valence} (negativ ← neutral → positiv)
- Erregung: {emotional_state.arousal} (passiv ← neutral → aktiv)
- Dominanz: {emotional_state.dominance} (unterwürfig ← neutral → dominant)
{emotion_prompt}
Generiere einen kurzen, charakteristischen Dialog (maximal 2 Sätze),
der die aktuelle Emotion authentisch widerspiegelt. Der Dialog sollte
zur Persönlichkeit des Charakters passen und in direktem Bezug zur
Situation stehen. Antworte NUR mit dem Dialogtext, ohne Anführungszeichen."""
response = self._make_request(prompt, temperature=0.8)
if response and "dialogue" in response:
return response["dialogue"]
# Fallback-Dialog
return self._generate_fallback_dialogue(npc, emotional_state)
def _get_emotion_prompt_addition(self, emotion: EmotionState) -> str:
"""Erstellt einen zusätzlichen Prompt-Abschnitt basierend auf der Emotion"""
emotion_map = {
EmotionType.JOY: "Der Charakter ist fröhlich und positiv gestimmt.",
EmotionType.SADNESS: "Der Charakter ist traurig und niedergeschlagen.",
EmotionType.ANGER: "Der Charakter ist wütend und gereizt.",
EmotionType.FEAR: "Der Charakter ist ängstlich und nervös.",
EmotionType.SURPRISE: "Der Charakter ist überrascht und erstaunt.",
EmotionType.DISGUST: "Der Charakter ist angewidert und abgestoßen.",
EmotionType.TRUST: "Der Charakter ist vertrauensvoll und offen.",
EmotionType.ANTICIPATION: "Der Charakter ist erwartungsvoll und gespannt.",
EmotionType.NEUTRAL: "Der Charakter ist neutral und ausgeglichen."
}
return emotion_map.get(emotion.primary_emotion, "Standard emotionaler Zustand.")
def _generate_fallback_dialogue(self, npc: NPC, emotion: EmotionState) -> str:
"""Generiert einen Fallback-Dialog bei API-Fehlern"""
base_dialogues = {
EmotionType.JOY: "Oh, das ist ja wunderbar!",
EmotionType.SADNESS: "Ich... verstehe schon.",
EmotionType.ANGER: "Das ist wirklich nicht akzeptabel!",
EmotionType.FEAR: "Ich... habe da ein mulmiges Gefühl.",
EmotionType.SURPRISE: "Warte, was?! Das ist ja...!",
EmotionType.DISGUST: "Pfui, das ist ja widerlich!",
EmotionType.TRUST: "Ich vertraue dir voll und ganz.",
EmotionType.ANTICIPATION: "Ich warte gespannt darauf...",
EmotionType.NEUTRAL: "Hmm, das könnte interessant sein."
}
return base_dialogues.get(emotion.primary_emotion, "Ja, sicher...")
def main():
"""
Demonstrationshauptfunktion für die NPC-Emotionsberechnung
"""
print("=" * 60)
print("NPC Emotions Engine - HolySheep AI Demonstration")
print("=" * 60)
# Konfiguration mit HolySheep API
API_KEY = "YOUR_HOLYSHEEP_API_KEY"
engine = HolySheepEmotionEngine(API_KEY)
# Erstelle einen Beispiel-NPC
brave_warrior = NPC(
npc_id="npc_001",
name="Thorgrim der Krieger",
personality={
"mutig": 0.9,
"ehrenhaft": 0.95,
"geduldig": 0.6,
"misstrauisch": 0.3
},
base_mood=EmotionState(
valence=0.1,