展示HN:NPCs的情感神经网络矩阵
Show HN: Neural emotion matrix for NPCs

原始链接: https://github.com/mavdol/npc-neural-affect-matrix

## 神经情感矩阵:具有演化人格的动态NPC 神经情感矩阵旨在通过赋予NPC持久的情感和通过互动演化的人格,来创造更具可信度的NPC,超越传统的条件逻辑。它利用罗素的情感环模型——将情感映射到效价(愉悦度)和唤醒(能量)轴上——来追踪和以类似人类的方式响应互动。 该系统作为一个游戏引擎(Unity、Unreal等)的API,允许开发者检查NPC对角色/实体的感受,并使用这些数据进行逼真的互动。主要功能包括对对话的情感理解、塑造未来回应的情感记忆以及复杂的 relationship 构建(爱/恨)。 该API提供函数来初始化NPC、评估互动(处理文本以确定情感反应)、检索当前情感状态、管理记忆(保存/清除),并且至关重要的是,包含强大的内存管理以防止泄漏。NPC通过JSON配置,定义他们的背景、默认人格和记忆衰减率。该项目适用于Windows,并欢迎社区贡献。

## NPC 神经情绪矩阵 开发者 mavdol 使用 Rust 和机器学习创建了一个系统,为游戏中的非玩家角色 (NPC) 增加动态的情绪深度。该系统基于 Russell 的情绪环模型,分析文本或动作以确定 NPC 的情绪状态——表示为效价(愉快/不愉快)和唤醒度(精力充沛/平静)维度上的坐标——并将其存储为情绪“记忆”。 核心是一个预训练的 DistilBERT 模型,目前在约 1k 个游戏对话上进行训练,计划扩展到 100k+。重要的是,它*分析*内容,而不是*生成*对话;它决定游戏应该使用哪个预先编写好的对话或动作。 该项目提供与 C/C++ 兼容的 API,方便与 Unity 和 Unreal 等引擎集成。Mavdol 正在寻求关于代码质量和架构的反馈,并欢迎贡献。评论者的早期反应强调了其在更具沉浸感的 RPG 体验方面的潜力,以及与本地 LLM 集成以实现独特的 NPC 生成。可视化工具可在 [https://valence-arousal-visualizer.vercel.app/](https://valence-arousal-visualizer.vercel.app/) 访问。
相关文章

原文

License: MIT Rust

Give each NPC persistent emotions and dynamic personalities that evolve through interactions.


🎯 What is Neural Affect Matrix?

Traditional NPCs rely on conditional logic and don't understand the source of their actions. This often leads to bugs or incoherent decisions that break immersion and make characters feel artificial. The goal is to make NPCs more human by giving them emotions as an important source of their behavior. Emotions that persist over time, creating unique personalities through experiences.

The system works as a simple api for any game engine or modding tools. You can instantly check how any NPC feels about specific characters or entity, then use that emotional data to create more believable interactions.

Here's what makes NPCs unique:

  • 🧠 Emotional Understanding: NPCs grasp the emotional meaning behind conversations and actions
  • 💭 Emotional Memory: Every interaction shapes how they feel in the future
  • 🎭 Evolving Personalities: Characters change and grow based on their experiences
  • 🔄 Complex Relationships: NPCs can love some characters or entity while disliking others, just like real people

Think about how humans work: we feel first, then rationalize our decisions. NPCs should work the same way.

We use Russell's Circumplex Model, a proven scientific framework that maps human emotions onto a simple 2D coordinate system:

  • Valence (X-axis): How pleasant or unpleasant the emotion feels (-1 to +1)
  • Arousal (Y-axis): How energetic or calm the emotion is (-1 to +1)

This creates an emotional landscape where every feeling can be precisely mapped and tracked over time.

Russel's Circumplex

🔗 Visualize emotions: Interactive Valence-Arousal Explorer


[ Input Text ] → [ Neural Affect ML Model ] → [ Memory Retrieval ] →
[ Contextual Re-evaluation ] → [ Emotional Response (Valence, Arousal) ]
  1. Emotion from text: The model evaluates valence/arousal of the text.
  2. Memory Integration: Retrieves relevant past interactions
  3. Reevaluate Emotion: Use memory to reevaluate valence/arousal
  4. Local Storage: Updates memory with new emotional data

Language Support: Currently optimized for English text


Build for production

Since the majority of video game engines run on Windows, we've streamlined the build process to make integration as simple as possible.

chmod +x build.sh
./build.sh

Find your binaries

📁 dist/
├── npc_neural_affect_matrix.dll     # Main file
├── onnxruntime.dll                  # AI runtime
└── onnxruntime_providers_shared.dll # AI providers

Note: Docker is required to execute build.sh


src/
├── api/              # C API endpoints
│   ├── services/     # Files that contain functions that communicate with modules
│   ├── endpoints.rs  # All the functions that we can call
│   └── type.rs       # The default types used
├── modules/
│   ├── emotion/      # Neural emotion prediction
│   └── memory/       # Memory management
├── models/           # Input/output data structures
├── config/           # Configuration handling

🧩 API References (FFI)

The Neural Affect Matrix provides a C API for seamless integration with game engines like Unity, Unreal Engine, and other C/C++ applications.

Initializes the shared neural model that powers emotion prediction. This function must be called before using any other API functions to ensure the AI model is properly loaded and ready for use.

ApiResult* initialize_neural_matrix();

Response Fields:

  • Response (string): Confirmation message indicating successful model initialization

Important Notes:

  • This function should be called once at application startup
  • Must be called before creating any NPC sessions
  • If initialization fails, all subsequent API calls will fail

Initializes a new NPC session with unique emotional state and memory storage. Each session represents an independent NPC instance that can maintain its own relationships, memories, and emotional evolution.

ApiResult* create_npc_session(
    const char* config_json,
    const char* npc_memory_json
);

Parameters:

  • config_json (const char*): JSON string containing NPC configuration (required)
    • Must be valid JSON matching the configuration structure
    • Cannot be NULL or empty
  • npc_memory_json (const char*): JSON string containing existing memory data (optional)
    • Pass NULL for new NPCs with no prior history
    • Use exported memory from get_npc_memory() to restore saved NPCs

Response Fields:

  • npc_id (string): Unique identifier for the NPC session, required for all subsequent API calls

Cleanly removes an NPC session and frees all associated memory. This permanently deletes the NPC's emotional state and memory history.

ApiResult* remove_npc_session(const char* npc_id);

Parameters:

  • npc_id (const char*): Unique NPC session identifier (required)
    • Must be a valid UUID string returned from create_npc_session
    • Cannot be NULL or empty

Response Fields:

  • Response (string): Confirmation message indicating successful removal

The core function that processes text input through the neural emotion prediction model, integrates it with the NPC's memory, and returns an emotional response. This function updates the NPC's memory with the new interaction.

ApiResult* evaluate_interaction(
    const char* npc_id,
    const char* text,
    const char* source_id
);

Parameters:

  • npc_id (const char*): NPC session identifier (required)
    • Must be a valid UUID from an active session
  • text (const char*): Input text to process (required)
    • Can be dialogue, actions, or events
    • Supports up to 512 characters
    • Works best with English text
  • source_id (const char*): Identifier for who/what is causing this interaction (optional)
    • Pass NULL for anonymous interactions
    • Use consistent IDs (e.g., "player", "merchant", "enemy_orc") for relationship tracking

Response Fields:

  • valence (float, -1.0 to 1.0): Emotional pleasantness/unpleasantness of the response
  • arousal (float, -1.0 to 1.0): Emotional energy/calmness of the response

Retrieves the NPC's current overall emotional state by calculating the weighted average of all memories, with recent interactions having more influence.

ApiResult* get_current_emotion(const char* npc_id);

Parameters:

  • npc_id (const char*): NPC session identifier (required)

Response Fields:

  • valence (float, -1.0 to 1.0): Emotional pleasantness/unpleasantness of the response
  • arousal (float, -1.0 to 1.0): Emotional energy/calmness of the response

get_current_emotion_by_source_id

Retrieves the NPC's emotional state toward a specific character or entity, based only on interactions with that source.

ApiResult* get_current_emotion_by_source_id(
    const char* npc_id,
    const char* source_id
);

Parameters:

  • npc_id (const char*): NPC session identifier (required)
  • source_id (const char*): Identifier for the specific source (required)

Response Fields:

  • valence (float, -1.0 to 1.0): Emotional pleasantness/unpleasantness of the response
  • arousal (float, -1.0 to 1.0): Emotional energy/calmness of the response

Exports all memory data for an NPC in JSON format. This is essential for save/load systems and debugging emotional state.

ApiResult* get_npc_memory(const char* npc_id);

Parameters:

  • npc_id (const char*): NPC session identifier (required)

Response Format:

[
  {
    "id": "mem_001",
    "source_id": "player_character",
    "text": "Thank you for saving my family",
    "valence": 0.85,
    "arousal": 0.45,
    "past_time": 1440
  }
]

Permanently deletes all memory entries for an NPC, effectively resetting their emotional state to the base personality.

ApiResult* clear_npc_memory(const char* npc_id);

Parameters:

  • npc_id (const char*): NPC session identifier (required)

Critical function that must be called after every API function to prevent memory leaks. Failure to call this will cause memory accumulation.

void free_api_result(ApiResult* result);

Parameters:

  • result (ApiResult*): Pointer returned from any API function (required)

All functions return an ApiResult structure that provides error handling and data management:

typedef struct {
    bool success;       // Operation success status
    char* data;         // JSON response data (on success)
    char* error;        // Error message (on failure)
} ApiResult;

Field Descriptions:

  • success (bool): true if operation completed successfully, false if an error occurred
  • data (char*): JSON-formatted response data when success is true, NULL when operation fails
  • error (char*): Human-readable error message when success is false, NULL on successful operations

Configuration Fields:

  • identity.name (string): Display name for the NPC, used in logging and debugging
  • identity.background (string): Character backstory that influences emotional responses and provides context for interactions
  • personality.valence (float, -1.0 to 1.0): Default emotional disposition on the pleasant/unpleasant axis. Positive values create optimistic characters, negative values create pessimistic ones
  • personality.arousal (float, -1.0 to 1.0): Default energy level on the calm/excited axis. Positive values create energetic characters, negative values create calm ones
  • memory.decay_rate (float, 0.0 to 1.0): Rate at which old memories fade over time. Higher values make NPCs forget faster, lower values create longer-lasting impressions

NPC Configuration Structure

NPCs are configured using JSON with the following structure:

{
  "identity": {
    "name": "Village Guard",
    "background": "A loyal guard who protects the village from threats. Has served for 15 years and takes pride in maintaining order."
  },
  "personality": {
    "valence": 0.2,
    "arousal": -0.1
  },
  "memory": {
    "decay_rate": 0.1
  }
}

Each NPC maintains a local memory of interactions:

{
  "source_id": "player_character",
  "text": "Thank you for saving my life",
  "valence": 0.85,
  "arousal": 0.45,
  "past_time": 1440
}

Fields Explained:

  • source_id: Who/what caused this emotional memory
  • valence/arousal: Emotional coordinates for this specific interaction
  • past_time: Game time elapsed (in minutes) when this occurred
  • Memory naturally decays over time based on decay_rate

We welcome contributions! Here's how to get started:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes and add tests
  4. Test your changes: cargo test
  5. Open a Pull Request

📚 Resources & Research

  • Russell's Circumplex Model of Affect
  • Memory decay and emotional persistence research

This project is licensed under the MIT License - see the LICENSE file for details.


联系我们 contact @ memedata.com