Search Unity

Active NPCs and events in inactive scenes?

Discussion in 'Game Design' started by Ukounu, Dec 29, 2021.

  1. Ukounu

    Ukounu

    Joined:
    Nov 2, 2019
    Posts:
    208
    I'm planning to make an RPG-like game where player can go from one level (scene) to another. The problem I encountered while designing this system is keeping events and NPC behaviors happening in scenes which are currently not loaded.

    Let's say I have a shopping area map where an NPC opens his store at 10 AM, then goes to drink coffee at 11 AM, goes to storage to bring boxes with goods at 12 AM, etc. So that when player visits that scene at different times he will see that NPC doing different activities. NPCs can also interact with other objects (doors, boxes, etc.), so that player will see them in different states depending on current time of the day.

    In active scene NPCs execute their daily routine according to their behavior scripts, walking on navmesh maps from one waypoint to another. But when scene is not loaded, it means that all NPCs, scripts, baked navmesh maps, waypoints are also not loaded and cannot work. So when player is in some other scene, I must somehow simulate everything that can happen in all other (inactive) maps, and then update the map where the player goes to its "current" state.

    What is the best practice to achieve that functionality? Writing ungodly amounts of code for every hour:minute:second for every objects that can be moved or changed (e.g., if it's 12:01 there should 7 boxes with goods in the storage room, and shop owner should be at x,y with another box in hands; if it's 12:02 there should be 8 boxes with goods in the storage, and shop owner should at x,y turning away from storage, etc. etc.) sounds to me like an incredibly complex and convoluted solution. Is there some more reasonable approach?
     
  2. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,694
    If you really need to keep the simulation going for the whole world, run the simulation separately from its visual representation in the current scene. In other words, the simulation will run in memory in regular C# objects not necessarily tied to scene GameObjects.

    However, maybe it isn't necessary to accurately maintain the entire simulation all the time. It's an RPG, not a scientific simulation. It's more important to be fun than to be 100% accurate. When you leave a scene, you could record the current in-world time and current scene state. When you return to the scene, fast-forward the scene's state to something that would reasonably reflect what would have likely happened during the elapsed time.

    For example, say an NPC runs a bakery. When the player leaves the bakery scene at 5:00 AM, the baker is in the kitchen making bread. Record that the scene was last open at 5:00 AM, and the baker is alive.

    Then say the player returns to the bakery scene at 11:00 AM. Since the baker was recorded as being alive (e.g., the player didn't murder him), it might be reasonable to place the baker behind the counter, and fill up the shelves a random 25-75% with bread, suggesting that he finished baking and customers have stopped by and bought some bread.

    Of course, if the player initiated a meteor storm at the wizard's tower scene between 5:00 AM and 11:00 AM, then when the player returns to the bakery scene you might want to fast-forward it differently. Perhaps the bakery is in shambles and the baker is putting out a fire.
     
    Last edited: Dec 29, 2021
    angrypenguin likes this.
  3. Ukounu

    Ukounu

    Joined:
    Nov 2, 2019
    Posts:
    208
    Even if I do approximations instead of precise calculations, it still will involve a lot of manual coding for every object that can change its state. Writing two sets of scripts (one running in real time in active level, and another for offline calculations), which will execute the same logic for the same events/NPCs, sounds to me like a really messy approach towards game design/logic.

    I was just hoping that that maybe I'm missing something and there exists already some simple & elegant solution for things like that - instead of just brute forcing everything through additional code... Oh well.
     
  4. Steve_Stevens

    Steve_Stevens

    Joined:
    May 3, 2016
    Posts:
    35
    I wouldn’t think so. Just check the last state when the object is ready activated and approximate right then and there. If the player enters the area and doesn’t see the object right away. You can even run thru the approximations via a co routine so you can spread the task over several frames. It would just be an extra class on your object to approximate work done while they were suspended. You could come up with some algorithm that is applied multiplied by hours since last active.
     
  5. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    There is. As @TonyLi said, you can separate the logic from the in-scene representation. When a scene is loaded all of the stuff in it can be listening to the logic and updating its presentation in real-time. For everything else the logic can still be running, but with nothing presenting it to the user.

    If you look up the "Model-View-Controller" design pattern it'll give you a broad overview of the approach.
     
    TonyLi likes this.
  6. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,694
    If you want to avoid having to simulate the entire game world all the time, you don't necessarily need a lot of extra code to do the fast-forward approach. Define your simulation on two levels of abstraction:

    At the higher level, define each NPC's normal daily schedule -- for example, the baker wakes at 4 AM, walks to the bakery at 4:30 AM, bakes from 5 AM to 6 AM, stand behind the counter from 6 AM to noon, etc. Also define how the NPC will handle special circumstances.

    At the lower level, if the baker's scene is loaded, use the high level data to run the simulation in realtime. If the baker's scene isn't loaded, then when you load the baker's scene use the same high level data to put the scene in a state that matches the high level data's schedule.
     
    angrypenguin likes this.
  7. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,635
    Another idea is (if every NPC has a regular schedule) you could move the schedule to the location instead of the agent. So instead of the baker storing the information that he goes to the bakery between 5 and 6, the bakery could store the info instead. When the player enters the bakery, the bakery can check the schedule to see if it needs to spawn the baker and where. Likewise, if player sneaks into the baker's house at 3:00 am, the baker's house knows that it needs to spawn the baker sleeping in bed. That way, you're only processing things that the player can see.
     
    neoshaman likes this.
  8. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    This, you don't need to simulate anything, because you have a time table that define a schedule, you can probably bake activity start and end directly in the table and interpolate the exact moment down to the precise animation. If action have state change on the global level (like the baker produce one unit of bread every hour) just save the last state, and on query calculate the delta and infer the number of unit produced (ie time passed / unit of time for one production). Even better if you can derive all npcs' schedules based on the npc's property (obviously the baker would bake, and all baker would follow the baker template).
     
  9. Ukounu

    Ukounu

    Joined:
    Nov 2, 2019
    Posts:
    208
    Thanks for all the responses. I can't say I found a "simple" solution I hoped for, but at least I got some ideas to work on.