Table of Contents

Remembrance

Remembrance is a memory and emotions module for your AI agents so they can remember what happend in the world and react to it. Your NPCs can hold grudges against players and other NPCs, return a favor or even try to seduce you or bribe you. They can remember what happend by whoom to whoom and where and when. You can also attach any custom data to your memories.

How it works

NPCs or any other objects in your game record their memories in a container and then the container can be searched for values with different criteria. They can also set float emotion values per object or in general.

Memory

There are two components that you can use or you can use the underlying data containers. Each of the listed components have a AddMemory() method which records a new memory to be remembered. They all also have multiple overloads of a querying method which gives you the closest memory to a specific time with additional arguments which limits the acceptable memories. For example you can return only memories with a specific target or of a specific type or both. There are methods caching the last recorded memory with a specific action id or target for specific common use-cases as well. They usually are of the form GetLastXXX()

Memory component

This is the component you want most of the times.

This component is more advanced and can remove memories from the middle of the list and uses a List<T> as its underlying data container. when the maximum capacity is reached, the first item in the list is removed after each addition. This component has the forgetting functionality where you can specify in each memory, after how many seconds it should be forgotten and the component forgets that memory after the specified seconds.

SimpleMemory component

This component is simpler and uses a Queue<T> as its underlying data container and when reaching capacity, dequeues the first item in the queue. This component cannot forget memories and cannot remove any memory other than the first one in the queue but if it is enough for your use-cases then have better performance in scenarios which item removal from the list becomes a bottleneck in your game.

Since queues don't have indexing, all searches use the foreach construct in C# and are slower than for loops. A foreach structure calls MoveNext() and Current() methods of the queue to get to the next object and then read it.

MemoryData

The MemoryData class is the type that the methods in the component accept and return.

Properties of a memory

A memory is stored using the MemoryData class and it contains a set of properties which can be used for querying

  • MemoryType This is an integer value which can be used to find out what type the memory is based on your custom types in your game. for example if your additionalData can be of multiple types, this can be used to see what type it should be casted to.
  • StartTime The time that this memory started. The constructor sets this automatically.
  • EndTime The time that this memory ended. Calling End(float time) on the MemoryData object sets this automatically.
  • ForgetAfterSeconds If greater than 0 then the memory will be forgotten after this many seconds.
  • Position The position that this memory happend in. If you need additional data like room name/level name/bounds, you can put them in additional data or other optional fields.
  • ActionType This field is of type System.Type in .NET and allows you to set the type of the class which caused this memory as an action so you know for example if the shooting was using the Spell class or the FireBall class. This could be derrived from other fields in theory but having it is handy specially in the Utility AI integration.
  • Initiator The object which initiated the memory. You can put any unity object including GameObjects and components in this as a reference. It can also be null.
  • Target The target of this memory, for example the killed object in a murder memory. This can be null if the memory has no targets.
  • ActionId This can be used for a unique id of an action instance. For example if you want to store exactly which magic spell of an NPC hit you, you can store its id here and put the NPC itself in the initiator field and the spell type in the ActionType field.
  • AdditionalData is any custom data that you want to attach to this memory. usually you should find out what this can be casted to based on ActionType, actionId or memoryType

Emotions

There is a component called EmotionComponent and an Emotion Collection asset which define what emotions exist and allow you to set and get their values. Emotions can be general or per object. for example your NPC might be generally sad but happy toward a tree they really like or they can have an emotion only for objects, like affection but it might not be meaningful in your game mechanics to have a general affection emotion for the agents.

All emotions are floats between 0 and 1 and define how they are combined with a similar emotion. For example if two objects share an emotion like hate toward each other, then you can ask them to align their hates so if I hate my friend by 0.9 and he hates me by 0.6, first of all we are probably not firneds and secondly, there are methods to let our hates affect each other so both are set at the higher value or are averaged based on the settings in the emotions collection.

Debuggers

Both modules have their own specific debugger windows to help you see what values exist in an agent's memory or what emotions it holds.