I’ve got four initial types of NPCs on my mind: merchants, police, pirates, and miners. Merchants are probably the second most complex because of their perceived behavior patterns.
As far as the player is concerned, merchants arrive in a system and are either hauling goods or are on their way to pick up goods. Their logical destination in the system is a station where they’ll be buying or selling. Once they complete their transactions, they’ll need to head to a jumpgate to continue their trade route.
I had originally had a global merchant pool with actual pilot names, but realized that doing it that way would be expensive and confusing. Expensive because I’d need to come up with an astronomical number of names, instantiate all the NPCs the game needs on start-up (and load and save them), and put them into a pool. Confusing because there’d need to be some manager that ensured that “Captain Dirk Squarejaw” doesn’t pop into a system, trade, leave the system…and then pop in through another jumpgate.
The solution was to create generic merchants — “Merchant Freighter” — in a scene-specific object pool. These would be generated when the player enters the scene, thereby reducing the frequency of objects that need to be created, reducing the need for unique names, and removing the confusion since everyone is named the same. Originally I had opted to just use this pool to draw from up front, destroying the object when it entered the jumpgate and creating a new instance to replace it in the pool, but after getting to this point in the article I decided to go back and re-tool it to use JUST the pool in true object pooling methods.
I had two strange issues after that. The first was that every so often an NPC would just decide to NOPE! his job, skip past the jumpgate out of the sector, and keep going into deep space. I figured out that this was a consequence of object re-use. When a merchant is created for the first time, he gets his route mapped out in the NPCMovement component. As the NPC reaches a stage node, the next node is activated and the NPC turns to face it. When it jumps, it’s SetActive(false) and moved out of the general area. However, it wasn’t being reset when it was re-drawn from the pool, so it thought the first leg of it’s journey was the last leg of the journey, and would head off in the incorrect direction.
The second issue was that after a point, merchants were staying docked at a station. It looked like they would “bounce off” the hull of the station and careen towards their exit jumpgate. This was because the variable I had for tracking the period of random undocking was being set inside a condition that wasn’t firing as often, making the last undocking variable check always evaluate to “yep, let em undock!”. I just had to move the setting of that variable outside the conditional statement and the merchants were free to sit around the station for as long as they liked (until their timer arbitrarily kicked them out).
* * *
I’m thinking the next step is to create the police. These guys are going to simply fly around, never docking, never leaving the sector. They’ll use all jumpgates and stations (and later, other items floating in space) as waypoints, randomized in order, and fly between them.
Miners will be pretty simple: They hang around asteroids and occasionally head to a station, and then back to the asteroids.
Pirates, then, are going to be a real PITA. They won’t have a set path because they’re designed to be annoying. They need to attack miners. They need to attack players. They need to avoid the police (but the police will chase them) and other lawful centers like jumpgates and stations. I suspect they’ll be “popup NPCs” that are randomly added and sent in to keep things interesting. I haven’t quite gotten that far yet, though.