Cleaner way to ensure only one NPC uses an object at one time?

A lot of my AI is based on spreading around interactable objects, and putting the animations, status effects, and all other use-related information on the object itself, so all the AI ever has to do is locate an object, pathfind to it, and call its UseMe function.

The one big thing I need to avoid is having multiple NPCs all clustering around the same chair/table/computer trying to use it at once. What I’m doing right now is giving the base Interactable class a bool called InUse, and when an NPC tries to find something to do, he iterates through the master list of objects in his room, adds each Interactable where InUse = false to some list AvailableItems, and if AvailableItems.Count >0 the NPC will chose a random index of AvailableItems as its desired interactable, move to it, and call its UseMe.

This is okay, although iterating through the list of every interactable in the room seems potentially wasteful. Where I’m concerned is how I can curate the value of InUse correctly: right now every NPC has a variable MyItem of type Interactable that gets set to the item they want to use, the first line of UseMe sets InUse=true, and when one of the many, many things that could change an NPC’s AI state occurs, they set MyItem.InUse=false and move on.

What I’m wondering is if there’s an obvious, better way to approach this problem? My implementation works, but it seems clumsy at several stages, especially when it comes to checking which items are potentially useable, and the need to manually set and unset InUse in every single state change seems very unwieldy, especially since it requires adding a custom variable to the main NPC class for an incredibly specific use case.

What about using a manager script?

In OnEnable, the interactable registers itself with the manager. In OnDisable it unregisters itself. The manager keeps two lists: reserved interactables and available interactables.

When an NPC needs something to do, it asks the manager for a random interactable from its available list. The manager can move this interactable to the reserved list. When the NPC is done, or if it decides to do something else, it tells the manager to move the interactable back to the available list.

The manager can just grab the first interactable from the available list. When you return an interactable to the available list, insert it at a random index.

You could move the current user information to the interactable or the manager instead of the NPC, but ultimately it needs to be somewhere, so you’re not going to get rid of it entirely.

Oh that’s a great idea Tony, thank you! Using a manager is a great idea, but I’m curious, how would you recommend keeping track of which NPC is reserving which object, if I move the user information out of the NPC class? I’ve been trying to keep NPC data extremely trim as it’s one of the only classes that I do lots of search/sort on, but the more I think about it the more it seems worth taking the hit to store the reference on the NPC: if it’s on the NPC proper I could hand the manager a reference to it along with the request to re-register it in the active objects, but if all the NPC sends is a reference to itself, I’d be adding an extra search to match NPC with object no matter where that data was actually stored.

You could use a Dictionary<NPC, Interactable> for the manager’s in-use items instead of just a List. Then looking up what item an npc is using will be quick and not require searching through a list.

http://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx

Keep in mind, Dictionaries can only have unique keys so if an NPC is able to reserve/use multiple objects, you might want to do Dictionary<NPC, List>

Unique keys is actually really useful, as I want to restrict NPCs to one object at a time. I had completely forgotten about dictionaries, but that was a hugely useful idea- after tinkering I managed to get a manager working that only ever needs a reference to the NPC, thank you for the suggestion!!

Does the interactable/manager really need to know which NPC has an object reserved, or just that it is reserved? Something to consider. You may be able to cut down on dependencies this way.

That’s an interesting point. The interactable/manager don’t need the information, but it’s still useful to keep around: I chunk the map very aggressively for optimization, and maintaining a record of the relationship makes loading chunks much easier, as it can spawn anybody who’s using an interactable by that interactable.