How do I get an NPC to follow the player?
A fine, yet naive, implementation is to get a path (up to the position of the player) from the path system every few seconds based on a timer.
In using this approach you should make some basic checks to determine whether or not you actually need a new path, since theres no reason to burn processing requesting paths when the player isn't actually moving for example.
Whether or not you need something more complex depends on how big a part of your game this type of feature is going to play. If this is a very common feature of your game, then you will eventually want to optimize to not make requests when the NPC is "close" enough and if you allow multiple followers then you probably want some kind of formation system etc.
Why does my frame rate drastically drop when I am in an area with many NPCs?
The problem might be that your non player character class does not have its replication mapping set up. In the server, you will need to set up the Replication Destination(client) and Replication Destination(server) class mappings.
How do I define NPCs and spawn them?
Generic NPC Considerations
There are a number of issues to consider when talking about NPCs:
- Specification - Definition of what makes "George" look/act like a "George"
- Spawning - How is the NPC generated? Always present as part of the area? Dynamically?
- AI - How does an NPC know how to do what it does?
- Do I really need a NPC for a "Visual Effect"?
Clean engine has only the most basic definition of an npc, one where you use the "character specification" which basically tells the engine which model to use to visualize the NPC. The functionality is exposed via /henpc and via script calls to $NPC. This basic functionality however is not capable of handling what behavior(s) are appropriate for the npc, nor is it capable of complex logic during generation for example to set up game specific data structures without implementing a significant amount of the override methods.
It would also be perfectly reasonable for a game with simpler npcs to handle npc specifications totally within script branching from the override methods of $NPC to add addition commands for creating for example a cat that wanders aimlessly through an area.
For Hero's Journey, we use the Spec System to handle a parametrically driven definition for our NPCs allowing our designers to define NPCs without needing to script their behaviors. Essentially, specs function as a template which is formed by a "base" class and one or more "decorator" classes. Specs also function as "Factories" that know how to instantiate (in this case) a npc.
- Base Class
- Decorator Classes
- NpcWearRandomOutfitSpecDec - handles assembling a random outfit for an npc when it is generated
- NpcAiAgentSpecDec - handles the specification of which ai agent to use for the npc
- threatDetectSightSoundSpecDec - controls threat analysis for the npc
- NpcAbilityListsToUseSpecDec - specifies the lists of abilities the creature utilizes for combat
- BaseMerchantSpecDec - declares the npc is a merchant and stores references to the shop inventory specs it uses
Designers then use a GUI to design our NPCs by GLOMming capabilities onto a spec:
and then editing them using a editor:
When creating a new NPC, a design selects a base class (only one for HJ's npcs currently) and then using GLOMming (dynamic composition) decorates the spec to support extended functionality and define its behaviors in parametrically driven manner. Our /henpc has been extended to support creating an npc from a specID "/HENPC CreateFromSpec <specID> [level]" located in HJnpcClassMethods (the override script for our $NPC system node).
When an npc is instantiated from a spec, each decorator receives a callback to a shared function allowing it the opportunity to (most often) GLOM a (related) decorator class on the instantiation and set any initial field values (if any fields are present in the deccorator). For example, threatDetectSightSoundSpecDec (a decorator for npc specs) GLOMs onto the instantiation the (related) decorator class threatDetectSightSound. Every specDerivedObject (the instantiated npc node) knows how to find the spec from which it was instantiated, allowing it to access any of the state/immutable data allowing the instantiation to be as lightweight as possible.
The spec system is detailed here: Spec System
Once you have some kind of specification for your creatures, you need to consider how you want them to actually be instantiated in your world. The way /henpc functions is to create npcs as permanent features of the area, for a game that does not have combat this may be entirely appropriate. For games more like HJ, we need the capability to spawn npcs/creatures dynamically for characters to fight. In HJ our spawners are call "MonGens" (monster generators), they can be set up in a variety of ways so that creatures spawned have specific territories, follow specific paths, are respawned when killed and a ton of other options.
Whether or not you choose to use some kind of Spawner, you do need to tell your creature AI to start at some point. This could be done in a variety of ways including any or all of these:
- Persisted NPCs in the area
- During Area Spinup, loop through all npcs and wake up their AI
- A timer on the persisted npc that wakes the npc up if it is not already awake
- Non-Persisted npcs (dynamically spawned)
- As part of the instantiation from a spec, a wake up call could be made
- An external event, such as someone logging into the area
Because creature spawning is a relatively customized behavior for any game, no spawner is included in clean engine code so whatever you write would be custom code for your game.
As you indicate you have discovered, Clean Engine includes a framework supporting a stack-based AI system and some very basic behaviors. We do recommend that you implement an abstract class as a child of _AiAgent and parent to all of your game specific ai agents. This allows you to override all of the functionality of _AiAgent and affect all of your game specific ai agents at the same time (assuming they had not already overridden the method).
For HJ, the aiagent for a NPC is specified by the specification and the agent is woken by the spawner. For your game, you may want to consider the simpler option detailed in the spawner comments above to just wake up your persisted npcs during area spin-up.