Forum rules - please read before posting.

Timers - Global or Local?

I found something in the forum that helped me create a time for a gameplay mechanic im working on. It works perfectly if I stay in the scene, but if I leave the scene it resets.

The example i've used is I talk to a character. Then 10 seconds later, they decide they are bored, get up and leave the room.

The below combination works perfectly for this:

This is the action (timer) that launches during the conversation.


And this is the timer that runs in the background. 

Is there a way for this timer to be run globally? It works absolutely perfectly if I stay on the same scene.

For example, if you make somebody a hot coffee, but take too long delivering it, it turns cold and the character will reject it.

Comments

  • Your images aren't displaying for me, I'm afraid.  Please try posting them on imgur.com.
  • The Actions don't show the full logic - most of them are collapsed, so I can't see why you're using e.g. a Scene: Check Action.

    Perhaps if you posted the link to the forum thread where you got the idea.
  • edited September 2018
    Ok sorry, I didn't think they would be relevant so collapsed them. I guess until I know the answer, anything could be relevant.  :)

    I have expanded them and i'll explain them.
    PART 1

    Talk to the NPC

    NPC gives you a task

    Launches an action list from an asset file.

    Passing basic variables:
    int (10) - wait 10 seconds
    str (Izzy) - global variable name
    obj (Izzy) - NPC
    obj (to Hallway) - Marker for walk to.
    Str (DiningRoom) - Current scene.

    Camera returns to normal gameplay and you now wander off to perform your quest.



    PART 2:

    This waits 10 seconds (as per the varable above)
    It then sets a Global variable (Izzy) to 2. This variable indicates that the timer has completed and this character has left the room.

    I then perform a Scene:Check, to see if the current Scene matches the scene specified (DiningRoom). If it does, it then goes on to animate the character leaving the room.  If you are in a different room, there is nothing to do, so no animation or deleting the character. The global variable has already been set to 2.

    If I stay in the DiningRoom scene, maybe just wander around the room a little (confirming gameplay is still running), after 10 seconds the character stands up and leaves the room.

    Perfect.

    However, if I have the conversation (starting the 10 second timer) then leave the scene (ie visit the Kitchen) and wait 10 seconds... upon returning to the DiningRoom scene, the global variable is still set to 1, and the character is still sitting at the table.

    This tells me that the Action List is only running within the Scene and is just being stopped / reset when a new scene loads. 


    If it helps, when the DiningRoom scene starts, one of the checks is to see if Global Var "Izzy" is set to 1. If it is, it places her at the table.

    Any other number, and she'll be deleted from the scene at start. (this works as she doesn't appear there until you wake her up - changing variable from 0 to 1).

    I hope I have explained it a bit better?

    Any more questions please don't hesitate to ask.

    Regards
    Kev



  • You're correct in that ActionLists do not survive scene changes.

    What isn't clear to me is what you're looking to do - when the player is outside of the scene, should the timer continue - or simply resume when the player re-enters it?

    A possible way around this would be to rely on a countdown variable, i.e. an Integer Global variable that is set to the "Wait time" parameter.  A Variable: Check Action checks if it's non-zero, and if so it reduces itself by 1 (Variable: Set), waits 1 second (Engine: Wait) before looping back on itself to check again.  Once it's zero, you run whatever subsequent Actions you need to.

    Having the timer work that way then allows you to resume it without re-setting it's initial value.  You can then e.g. check if it's non-zero when you re-enter the scene (if so, a timer is in progress), and you can then resume the countdown.
  • Ok that's interesting. I can have a look into that. Essentially it's timed events, so they need to be global to the game. So no matter where you are in the game, if you take too long performing a task, a consequential action occurs. For instance, you can make a hot cup of coffee and then walk around various scenes with it in your inventory. Over time it'll get cooler until it's too cold to drink and an NPC would reject it. Ideally these timers need to survive a scene change and run in the game engine background otherwise you could end up having a huge list of things to check when you load every scene. There will be 5 NPCs. You have to wake them up first, then you have a time limit to find and prepare their food otherwise they get bored and wander back to their rooms to play. If you make toast, but leave it too long, it'll get cold and they'll reject it. Little gameplay mechanics to make the puzzles more interesting. I'll look into the global variables as timers, but if there was a way to have an action list persist through scene changes, that would be perfect :) Kev
  • To add to this, I'm interested in how to run persistent actions, I imagine this would be somewhat similar to the Weird Ed coming to the door on Maniac Mansion or Storekeeper on Monkey Island, where you need a global action that retains persistency between scenes. @kevrev Wouldn't you need to have, for instance, your coffee global subtraction var action on every scene so it ran properly? I'm not sure how this would work for several global/persistent actions.
  • edited September 2018
    Yes thats kinda the problem. If I had 10 different timers all running at the same time, i'd have to duplicate the actions on every single scene in the game (or at least ones you can visit whilst the time is running).

    For instance, I have a child who starts off asleep in bed.
    You have to perform an action to wake them up and send them downstairs for breakfast.

    When you enter the DiningRoom they are sitting at the table.

    You talk to them to discover what they want for breakfast, and then you have a 2 minute timer to be able to find all the relevant items, prepare their breakfast and deliver it to them.

    If you don't deliver it within the 2 minutes, they get bored and wander back to their bedroom to start playing their games console.

    You then have to go back to their bedroom, ask them to come downstairs again...

    But by this time, if you've made them a cup of tea and some toast, its gone cold.

    So they confirm what they want again, 2 minute timer restarts, you attempt to give them the breakfast and they say "ewww! its cold". So you have to make it again... all the time their attention span (timer) is waning....

    I'd like the whole game to revolve around mechanics like this.

    So 5 different kids. All wanting different things at different times, and each thing you try to make could also have an expiry.

    This could turn into dozens of timers running concurrently - but if they can only be checked per scene, I'd have to duplicate ALL the timers in all the scenes, all referencing the same timer Global variable and performing 10 times as many actions as really needed.

    If the timers and associated action scripts ran independently from the scenes, i'd only need to setup each timer/action-list once.

    Kev
  • For something so complex, I'd personally prefer to rely on a dedicated script to handle that.

    On a technical level, an ActionList asset can feasibly be made to survive scene changes simply by marking it's associated RuntimeActionList as DontDestroyOnLoad.  To try for your yourself, insert this into RuntimeActionList.cs:

    void Start ()
    {
      DontDestroyOnLoad (gameObject);
    }

    This, however, brings about a wider issue in that it then much easier to "break" AC, since such an ActionList would typically be running at all times - yet an ActionList cannot be saved mid-run (or at least, not midway through an Action).

    The upcoming v1.65 release will allow for a new custom event that is called when an ActionList begins, meaning you'll be able to (among other things) mark a list as "DontDestroyOnLoad" without having to modify the source code as above.
  • That's sounds great! I presume this would also allow you to kill the actionlist as well with a custom event? This is how Scumm worked with global timers, local functions died on room leave and global a just ran until killed, and I think this is kind of timer style @kevrev is looking for.
  • Excellent, I can work with that. Would 1.65 include an action to "destroy" the object too? Or would we still rely on custom code?
  • Any ActionList can be killed through script - see the "Interaction scripting" chapter of the Manual.

    Even if an assed-based ActionList is marked as DontDestroyOnLoad, it'll still be killed when a save game file is loaded - but otherwise it'll be up to you to kill it outside of it ending through its natural course.

    @KevRev: What do you mean by that, exactly?
  • No I think I understand, that's perfect thank you.
  • @ChrisIceBox ; that worked beautifully, thank you.

    @zebbi you may also find this useful. You can restrict this to only the Action Lists you want it to affect.

    I've added a layer of safety to stop it breaking AC. If you add a parameter named "Persistent", it'll remain persistent. Without the parameter, it treats it as a normal action list.


    RuntimeActionList.cs:

            void Start()
            {
                if (useParameters && assetSource.parameters != null)
                {
                    foreach (ActionParameter assetParameter in assetSource.parameters)
                    {
                        if ((assetParameter.label=="Persistent"))
                        {
                            DontDestroyOnLoad(gameObject);
                        }
                    }
                }
            }

  • Ah poop! Just discovered the Run ActionList Asset literally just runs that asset and not an instantiated version of it. So if I kick off multiple timers they reset.

    I'm happy to figure out the code if somebody can point me in the right direction?

    Video demonstrates - I expected to see three "BreakfastTimer" running.....

    image

    I can create an asset file for each, but had tried to make it generic so a timer asset could be used multiple times for different purposes.

    Kev
  • Don't worry.... Easy fix... "Can run multiple instances?". :)
  • @kevrev thanks, I appreciate that, i'll take a look at it!
  • I believe I was a little premature in calling this a "quick fix".  Problems can arise if an Action is running in the middle of a scene change, but I'll be incorporating a check for this as part of the next update.

    I'm also considering adding a proper "Survive scene changes?" option to assets, though with the caveat that it won't be available if the asset itself is skippable.  This should also allow for Scene: Check Actions to link to other Actions once complete.

    It's still not something I'm totally sure about, so it's inclusion will be dependent upon feedback.  Look out for a call for testing soon.
  • Ok great, will do Chris. For now, the above works really well for me :)
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.