Forum rules - please read before posting.

"Wait Until Finish" in custom action script issue

Hello,
I am trying to create a custom Action that allows my player to reach a marker.

The "MoveTo" action per se, works just fine, but i want the player to reach its destination before moving to the next action or ending the interaction:

            if (!isRunning)
            {
                isRunning = true;
                if (AC.KickStarter.player.transform.position != MoveDestination)
                {
                    AC.KickStarter.player.MoveToPoint(MoveDestination, false);
                }
                return defaultPauseTime;
            }
            else
            {
                isRunning = false;
                return 0f;
            }
        }

I am quite sure i misunderstood how the return defaultPauseTime works.

Any ideas?

Thanks!

Comments

  • Digged deeper,
    appartenly i have misunderstood the entire "move to point" action.

    What i want is the character to pathfind to the final destionation and the action to wait till this operation is finished before moving on.

    Chris, what would you recommend my approach to be?

  • The Wait until finish? field in the default Character: Move to point Action should do this already, unless I'm misundertanding you.

    Regarding your code, once you set your "isRunning" variable to true, the Action will be re-run - either the next frame if you returned defaultPauseTime, or a specific time after otherwise.

    To have a custom Action continue running until you're ready for it to end, you need to keep doing this until your intended condition is met, i.e.:

    if (!isRunning)
    {
        isRunning = true;
        KickStarter.player.MoveToPoint(MoveDestination, false);
        return defaultPauseTime;
    }
    else
    {
        if ((KickStarter.player.transform.position - MoveDestination).sqrDistance > 0.01f)
        {
            return defaultPauseTime;
        }
        isRunning = false;
        return 0f;
    }
    
  • I am trying to build a custom Character>MoveToPoint because i need to pass to the action the parameters of the destination GameObject, not those of the GameObject where the interaction starts from.

    Also, from my understanding, MoveToPoint only make the character reaching destination in a straight line, rather than actually pathfinding its way to it?

    To give you context:

    • Character interacts with door;
    • Character teleports to another door somewhere else in the world;
    • Character walk through the door and reaches a marker (stored in parameters);

    My doors are prefabs and they all contain standardized markers and parameters, so all i need to do tweak the "Teleport to" gameobject parameter with the Target door and the ActionList should execute all the required actions for me.

    Hope that makes sense?

    I have also tried your code, but the Player gets stuck at the point where is teleported and cannot continue to its final destination.

    Code attached below.

    public override float Run ()
            {
                // Assign variables runtime
                MoveDestination = ThisObject.GetComponent<Interaction>().parameters[0].gameObject.GetComponent<Interaction>().parameters[3].gameObject.transform.position;
                TeleportDestination = ThisObject.GetComponent<Interaction>().parameters[0].gameObject.GetComponent<Interaction>().parameters[2].gameObject.transform.position;
    
                //Perform actions
                AC.KickStarter.player.Teleport(TeleportDestination, false);
    
                //GetComponentInParent<Interaction>().parameters[2].gameObject.GetComponent<Marker>())
    
                /* 
                 * This function is called when the action is performed.
                 * 
                 * The float to return is the time that the game
                 * should wait before moving on to the next action.
                 * Return 0f to make the action instantenous.
                 * 
                 * For actions that take longer than one frame,
                 * you can return "defaultPauseTime" to make the game
                 * re-run this function a short time later. You can
                 * use the isRunning boolean to check if the action is
                 * being run for the first time, eg: 
                 */
                if (!isRunning)
                {
                    isRunning = true;
                    KickStarter.player.MoveToPoint(MoveDestination, false);
                    return defaultPauseTime;
                }
                else
                {
                    if ((KickStarter.player.transform.position - MoveDestination).sqrMagnitude > 0.01f)
                    {
                        return defaultPauseTime;
                    }
                    isRunning = false;
                    return 0f;
                }
            }
    
  • Update:

    If i run the action above and observe the character from Unity's viewport, rather than from the Game View, the character actually reaches the destination point, even though in the Game view it still appears to be stuck.

    Can this be related to physics and Update methods?

  • I am trying to build a custom Character>MoveToPoint because i need to pass to the action the parameters of the destination GameObject, not those of the GameObject where the interaction starts from.

    The existing Action allows you to use a GameObject parameter in place of the "Marker to reach" field - is this not what you're looking to do?

    Also, from my understanding, MoveToPoint only make the character reaching destination in a straight line, rather than actually pathfinding its way to it?

    Pathfinding is optional with this Action, but enabled by default. If you're trying it with "Pathfind?" unchecked, and the character isn't pathfinding, it may be an issue with your NavMesh.

    If i run the action above and observe the character from Unity's viewport, rather than from the Game View, the character actually reaches the destination point, even though in the Game view it still appears to be stuck.

    It may be a Unity issue. What is the behaviour in builds? Though, from the above I'm still not sure a custom Action is necessary here.

  • The existing Action allows you to use a GameObject parameter in place of the "Marker to reach" field - is this not what you're looking to do?

    Yes, the current Character>MoveToPoint action allows you to manually specify a marker and have the character teleport to it, but since i am planning to have loads of doors the character can teleport to, i want to make this less tedious to tweak.

    All i want to end up doing is to just change the "Teleport to" parameter within any given door interaction script (see pic below). The action should then look at the target teleport door interaction's parameter, and, once the character has completed the teleport, move it to a specific locator which is also set in the door's local parameters.

    Breakdown:

    • Player interacts with a door;
    • Door is unlocked, good;
    • Requirements says player has all necessary items to enter that door (narrative);
    • Player is teleported to target door locator (e.g. Parameter 2);
    • Player then moves to target door locator (e.g. Parameter 3);

    Accessing a target door's local parameters is already sorted, the issue i am having is with the "wait until finish".

    After implementing your suggestion, the action actually pauses gameplay and the player reaches the destination target, but then it does not resume gameplay.

                if (!isRunning)
                {
                    isRunning = true;
                    KickStarter.player.MoveToPoint(MoveDestination, false,true);
                    distance = Vector3.Distance(KickStarter.player.transform.position, MoveDestination);
    
                    Debug.Log(distance);
    
                    return defaultPauseTime;
                }
                else
                {
    
                    if (distance >= AC.KickStarter.settingsManager.GetDestinationThreshold())
                    {
                        return defaultPauseTime;
                    }
    
                    isRunning = false;
                    return 0f;
                }
    
            }
    
  • the current Character>MoveToPoint action allows you to manually specify a marker and have the character teleport to it

    The only mention this Action makes of teleporting is the optional ability to have the character teleport to their desination if they take too long to reach it through movement. Can you share a screenshot of exactly which part of the Action you're looking to override through parameters?

    On the topic of using an Interaction that has parameters: it's worth noting that you can have a Hotspot reference an ActionList asset file when assigning Interactions. If that asset makes use of parameters, attaching the "Set Interaction Parameters" component to the Hotspot will let you specify each parameter value at the time the asset is run for that particular Hotspot interaction.

    After implementing your suggestion, the action actually pauses gameplay and the player reaches the destination target, but then it does not resume gameplay.

    Rather than comparing distance to query the Player's state, you could try checking if they are currently pathfinding with:

    KickStarter.player.IsPathfinding ()
    
  • Rather than comparing distance to query the Player's state, you could try checking if they are currently pathfinding with:

    This worked!

    On the topic of using an Interaction that has parameters: it's worth noting that you can have a Hotspot reference an ActionList asset file when assigning Interactions. If that asset makes use of parameters, attaching the "Set Interaction Parameters" component to the Hotspot will let you specify each parameter value at the time the asset is run for that particular Hotspot interaction.

    I am not sure i follow you in this case. What happens if i have multiple doors in the scene (all with multiple markers, e.g: Marker_In, Marker_Out, etc)? How do i modify the "target" parameters on the go? Wouldn't it be easier and quicker to just create a "template" door prefab, containing an instance of the same interaction with the parameters already set (which i would only need to do once per door type)?

    When i then duplicate the door prefab across the scene, all i need to do is just change one parameter (which is the teleport target).

    Then, the action will look at that first "teleport to" parameter, and from there look at all other "local" parameters, which are following the same format (Param0 is always Teleport 2, Param1 is always Way in, Param3 is always Way out, etc).

    That's the reason why i thought i needed a custom action that would look at the parameters of the GameObject i am targeting, rather than at it's own parameters.

    Otherwise the character would teleport at the specific marker of the door he is already teleporting from and would barely move.

    Unless i am missing something?

  • edited April 2021

    If a scene-based ActionList has it's Actions Source property set to Asset File, it'll rely on an ActionList asset for its Actions - parameters included.

    Actions cannot exist as prefabs - but this way, you can make a Door prefab that has all the Hotspots / Markers / logic involved either in a prefab, or an ActionList asset shared by all instances of that prefab.

    If the Set Interaction Parameters component is then also included in the prefab, you can set the parameter values as part of the prefab - and not have to set them for each instance of the door.

    It's a complex topic, and the exact steps will vary based on need, but this video covers the main principles. Have a look through it and see if that is compatible with what you're trying to do.

  • edited April 2021

    Thanks Chris,
    I think my use case is slightly different from the one covered in the tutorial.

    In my prototype, doors function like portals and not like simple doors.

    Entering door A, will teleport the player to door B, which is somewhere else in the level.

    What i need to do is for an Action contained in an ActionList to perform tasks (teleport to, move to, mainly) partially related to the interaction the player interacted with (let's say the door the player wanted to enter), and partially related to the destination door.

    Something along this line:

    USER INPUT:

    • Player interact with Hotspot_DoorA;

    ACTION:

    • Player is moved to DoorA Marker_Exit (other side of the door);
    • Player is then teleported to DoorB Marker_Exit;
    • Player is moved to DoorB Marker_Enter;

    USER INPUT:

    • Player moves freely;

    I have currently created a custom action that does what i described above, but it seems
    this is not possible to use it when the source of an ActionScript is set to Asset rather than Scene, as the parameters can't be accessed easily.

    I have also tried accessing the SetInteractionParameters scripts but i haven't figured a way to access the parameters there.

    Does this make sense?

    Thanks for your help!

  • edited April 2021

    I think I'm following, but I don't see a need to use a custom Action.

    not possible to use it when the source of an ActionScript is set to Asset rather than Scene, as the parameters can't be accessed easily.

    Can you share screenshots of the configuration that isn't working? Bear in mind that you don't need an Interaction ActionList that references an asset - you can have the Hotspot reference ActionList assets directly. The SetInteractionParameters component will still work with that.

    At least so far as I'm understanding things, here's how I would go about it:

    • Create a Door (A) with a Hotspot and Enter/Exit Markers as children.
    • Duplicate it (Door b), parent both Doors to a shared parent
    • Create an ActionList asset and give it three GameObject parameters: Marker1, Marker2, Marker3
    • Add standard Character: Move to point / Object: Teleport Actions to move the Player in the intended way - only using the parameters to reference where to move/teleport to
    • For both Door Hotspots, set the Actions source to Asset file, create a new Use Interaction, map it to this asset, and also attach a Set Interaction Parameters component
    • For Door A's SIP component, set Marker1 to DoorA_ExitMarker, Marker2 to DoorB_ExitMarker, and Marker3 to DoorB_EnterMarker
    • For Door B's SIP component, set Marker1 to DoorB_ExitMarker, Marker2 to DoorA_ExitMarker, and Marker3 to DoorA_EnterMarker
    • It should not be possible to prefab this hierarchy (starting from the shared parent), and copy/pasted multiple times without copies interfering
  • edited April 2021

    Hello Chris,
    the problem i have with manually linking markers to an AL is that it becomes overly complicated when you have several doors in the level, or when you want to rewire doors to one another.

    The more doors i have, the more markers i have, the more complex refactoring a level's design becomes.

    If each door has 2/3 markers, and i expect to have up to 14 doors per level, that means at some point I will have up to 42 markers to look after. Not counting all the conditionals to eventually lock/unlock doors.

    I am not saying it's the wrong approach of course, just that it can become a headache to rewire doors everytime a new door needs to be added or when the level design changes even slightly.

    My hope was to have an AL "knowing" what to do when the player interacts with a specific door.

    In that case my AL would look something like this:

    PARAMETERS:
    - Conditionals;
    - TeleportTo (GameObject);
    - Enter (GameObject);
    - Exit (GameObject);

    ACTIONS:
    - Check that door conditionals;
    - Teleport player to "TeleportTo" Exit;
    - Move player to "TeleportTo" Enter;

    Here's the custom TeleportTo action i am currently using:

    TeleportDestination = GetParameterWithID(_parameters, 0).gameObject.GetComponent<Interaction>().parameters[2].gameObject.transform.position;

    In this case, the Door prefab already reference its own Enter and Exit markers. So when i instance a new Door prefab in the scene, the local markers are already referenced and all i need to do is to add the destination Door.GameObject to the "TeleportTo" parameter of the newly instantiated door.

    When the player interacts with DoorA, the AL should know what to do in order to teleport him to DoorB, and what to look for.

    My only roadblock in doing so is that parameters of an Asset AL are only applied when the interaction on the target door is executed, or via an InteractionStarter, which is not exactly what i need, as that means the player would be trying to enter all doors simultaneously when the level starts.

    I only need a way to have those parameters applied independently from an interaction when the level starts. With a single custom Action, i can then access only the parameters i need.

    I have already achieved a working version of this using InScene AL, but that's not convenient as, when i will need to modify the logic behind door's interaction at some point, i will also need to rewire every single door in the level.

    Hope you can help, i know we are very close to a breakout :smiley:

  • edited April 2021

    My comments above were making the assumption that each door only has one other door it can lead to. If each door is linked to only one other - and the other only linked to the first - you can prefab both doors together so that you can assign all parameter values inside the prefab once and be done.

    Is this not the case for your situation? How does it differ, if not?

    My only roadblock in doing so is that parameters of an Asset AL are only applied when the interaction on the target door is executed, or via an InteractionStarte

    An ActionList asset can be given default parameter values, and its parameters can be set at runtime either through script or through use of the ActionList: Run Action's Set Parameters Only option. If the asset is shared by others, though, they shouldn't be set before it's run.

    Again, if you can share screenshots of exactly what configuration isn't working, I can attempt a recreation.

  • Hi Chris,
    The problem is not with "how many doors one door can lead to", but "how quickly can I link doors together without having to reassign all the positioning markers in it?".

    It really is "only assign the single "TeleportTo" gameObject" on each door VS "assign 3 positioning markers on each door".

    The first option totals 2 "human interactions" with a couple of door, the second 6.

    As mentioned, it can be ideal for a quick 2 doors prototype, but it becomes a head ache as soon as you have much more doors spread around the level, as in my case.

    If the asset is shared by others, though, they shouldn't be set before it's run.

    All doors should share the same ActionList, but use different values for the same type of parameters.

    Again, if you can share screenshots of exactly what configuration isn't working, I can attempt a recreation.

    The solution you suggested already works, it's just not ideal in my scenario.

    All I am trying to do is to make it easier later down the line to reassign doors and quickly test the design of a level, without going crazy in recoupling doors in prefabs.

  • how quickly can I link doors together without having to reassign all the positioning markers in it?

    Please elaborate on what the issue is. The workflow I'm suggesting doesn't involve re-assigning markers once the initial prefab has been set up.

    When it comes to an issue like this, the devil is in the details - please consider sharing screens as I'm really struggling to picture your situation here.

  • Quick update, following your suggestion worked. It's not as bad as i thought it would have been, it's just a matter of staying very focused when tweaking teleportation Actions.

    Thanks a lot for your help!

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.