Forum rules - please read before posting.

Adventure Creator and Puppet Master

edited February 2021 in Technical Q&A
Good evening,

I recently bought Puppet Master but unfortunately I am not able to make it work with AC. Invector and AC do work very well together, fortunately.

I will describe what happens:

Invector and AC are on the root object and Puppet Master is a child (Invector and Puppet Master work perfectly because of a plugin and a very well tutorial video).

The thing of Puppet Master in my case is that I would like to let the character fall in a realistic way. This works, but.... after the character fell down and stands up again, it teleports ten meters away (every time I press the right or left arrow) after trying to walk again. So, something is going very wrong, and it seems that either Puppet Master or AC messes up the gravity in the character, or it loses it's target (I'm not sure what is hapenning..) I hope someone can help.
«1

Comments

  • edited March 2021

    AC will assume control over a character at all times if their Motion control field is set to Automatic.

    When set to Manual, however, it will delegate motion control to a custom script.

    If you need to set this dynamically, i.e. at the time the character falls, you can do so through script:

    GetComponent <AC.Char>().motionControl = AC.MotionControl.Manual;
    
  • I think it's because of the way you have it set up, that being character controller and AC player component on the root object. Both the character controller and Puppet Master should be a child of the root object.

    I have PM on my character and all falling and getting up behaviours work perfectly well, though I have never used Invector so I can't really speak for that or whether it has an effect or not.

  • Thanks a lot for your help @ChrisIceBox and @Deckard_89. What you said I already tried or is already set up in that way. I will make a small video and post the link here to make the problem more clear.
  • edited March 2021

    Ok, I found the problem, it is actually very simple: The Playerscript from AC isn't the problem, it is the capsule collider. And I don't mean the capsule collider from the charactercontroller (which is a child under the root object), but the one that is needed on the root object. Since the one on the root object seems to determ the triggers and hotspotdetection, which at the moment don't work since the root object isn't moving the collider. So, this is the problem. AC wants me to have a collider on the root object, but the root object doesn't really move, meaning I can't use triggers or anything. I think it should be easily solved with a GetComponent in a script somewhere. But where?

    PS: The flying away thing after falling isn't an issue anymore: it is either working with Puppetmaster and a non functioning AC playerscript (no triggers and such) or a working AC script that blows up Puppetmaster. So I guess solving the capsule collider thing would solve everything and can't be that hard. I hope you can still follow me.

  • See here my video in a bit more detail about it:

    ")

    • If you're using a third-party motion controller to move your Player, you should keep your Player's Motion control set to Manual the whole time.
    • AC doesn't strictly require you to have a Rigidbody and Collider on the root - particularly if you use Manual motion control.
    • While the Player component should ideally be on the root, it's more important for it to be on the object that represents the character in-game (your video seems to show that it's the vShooterMeleeController child object that actually moves). Try moving the Player component to this child instead. You won't be able to reference the prefab any more, but you can leave the character in the scene file instead.
    • Triggers can optionally be set to detect the Player's position, rather than their collider.
    • Components are detected when the scene begins - not every frame. A Hotspot Detector can work with its own Rigidbody - but only if you add it to the object in Edit mode, not during runtime.
  • Thanks a lot for this comprehensive explanation @ChrisIceBox :) The character works now but there are still some problems, one major problem would be the re-spawning of the character and finding the right playerstarts. How would you respawn a gameobject without being a prefab on the right Playerstart marker with the character already in the scene?
  • This is due to the Invector Player being killed?

    You can teleport the Player to a specific PlayerStart through simple script:

    AC.KickStarter.player.Teleport (myPlayerStart);
    

    Or the scene's default with:

    AC.KickStarter.player.Teleport (AC.KickStarter.sceneSettings.defaultPlayerStart);
    

    When you call this, however, will likely be down to how Invector works - I'm not sure if Invector uses an event system. Check Invector's documentation for assistance with that aspect.

  • Hi Chris, thank you very much for answering. My answer back is a bit late because I first had to find out how to combine Invector/Adventure Creator and Puppetmaster. The latter is achieved thankfully! :) The way it works now is that there is no use of a prefab but a just a Player Gameobject that is always present in the scene. The only problem seems to be that the Adventure Creator Player script is not on the Root object. This is problematic since PuppetMaster seems to always remember the Default Playerstart on start-up, meaning that Puppetmaster always starts in the first default position of the scene instead of the actual Playerstart (my scene has different player starts/markers depending on which scene the player came from). So it starts always at the main Playerstart, which is problematic since PuppetMaster always wants to be precisely on the Player Object in the beginning of the scene, otherwise it gets into trouble. I tried to achieve this a bit with your code (put your code on the root object) but I don't get it completely. I should convert it to a Vector 3 but I don't want that, I just want the position from the Marker/PlayerStart where the Player is positioned. How could I achieve this? Or is there a better way to go around this?
  • PuppetMaster has its own Teleport function that takes a position and rotation. Both can be gotten from the AC Marker/PlayerStart class:

    myPlayerStart.Position
    myPlayerStart.Rotation
    
    AC.KickStarter.sceneSettings.defaultPlayerStart.Position
    AC.KickStarter.sceneSettings.defaultPlayerStart.Rotation
    

    It sounds like there'll be issues if using AC's own teleporting Actions etc, since - if the PuppetMaster component is on an object above - it'll become offset again.

    What may be best is to have both AC/PM start in the same place, and then use a custom Action to teleport PuppetMaster instead. Try this:

    using UnityEngine;
    using System.Collections.Generic;
    using RootMotion.Dynamics;
    #if UNITY_EDITOR
    using UnityEditor;
    #endif
    
    namespace AC
    {
    
        [System.Serializable]
        public class ActionTeleportPM : Action
        {
    
            public bool isPlayer;
            public int obToMoveParameterID = -1;
            public int obToMoveID = 0;
            public PuppetMaster puppetMaster;
            protected PuppetMaster runtimePuppetMaster;
    
            public bool snapCamera;
    
            public int markerParameterID = -1;
            public int markerID = 0;
            public Marker teleporter;
            protected Marker runtimeTeleporter;
    
            public override ActionCategory Category { get { return ActionCategory.Object; }}
            public override string Title { get { return "Teleport PM"; }}
    
    
            public override void AssignValues (List<ActionParameter> parameters)
            {
                if (isPlayer)
                {
                    runtimePuppetMaster = KickStarter.player.GetComponentInParent <PuppetMaster>();
                }
                else
                {
                    runtimePuppetMaster = AssignFile <PuppetMaster> (parameters, obToMoveParameterID, obToMoveID, puppetMaster);
                }
                runtimeTeleporter = AssignFile <Marker> (parameters, markerParameterID, markerID, teleporter);
            }
    
    
            public override float Run ()
            {
                if (runtimePuppetMaster && runtimeTeleporter)
                {
                    runtimePuppetMaster.Teleport (runtimeTeleporter.Transform.position, runtimeTeleporter.Transform.rotation, true);    
    
                    if (isPlayer && snapCamera)
                    {
                        if (KickStarter.mainCamera != null && KickStarter.mainCamera.attachedCamera != null && KickStarter.mainCamera.attachedCamera.targetIsPlayer)
                        {
                            KickStarter.mainCamera.attachedCamera.MoveCameraInstant ();
                        }
                    }
                }
    
                return 0f;
            }
    
    
            #if UNITY_EDITOR
    
            public override void ShowGUI (List<ActionParameter> parameters)
            {
                isPlayer = EditorGUILayout.Toggle ("Is Player?", isPlayer);
                if (!isPlayer)
                {
                    obToMoveParameterID = Action.ChooseParameterGUI ("Object to move:", parameters, obToMoveParameterID, ParameterType.GameObject);
                    if (obToMoveParameterID >= 0)
                    {
                        obToMoveID = 0;
                        puppetMaster = null;
                    }
                    else
                    {
                        puppetMaster = (PuppetMaster) EditorGUILayout.ObjectField ("Puppet to move:", puppetMaster, typeof(PuppetMaster), true);
    
                        obToMoveID = FieldToID (puppetMaster, obToMoveID);
                        puppetMaster = IDToField (puppetMaster, obToMoveID, false);
                    }
                }
    
                markerParameterID = Action.ChooseParameterGUI ("Teleport to:", parameters, markerParameterID, ParameterType.GameObject);
                if (markerParameterID >= 0)
                {
                    markerID = 0;
                    teleporter = null;
                }
                else
                {
                    teleporter = (Marker) EditorGUILayout.ObjectField ("Teleport to:", teleporter, typeof (Marker), true);
    
                    markerID = FieldToID <Marker> (teleporter, markerID);
                    teleporter = IDToField <Marker> (teleporter, markerID, false);
                }
    
                if (isPlayer)
                {
                    snapCamera = EditorGUILayout.Toggle ("Teleport active camera too?", snapCamera);
                }
            }
    
    
            public override void AssignConstantIDs (bool saveScriptsToo, bool fromAssetFile)
            {
                if (!isPlayer)
                {
                    AssignConstantID (puppetMaster, obToMoveID, obToMoveParameterID);
                }
                AssignConstantID <Marker> (teleporter, markerID, markerParameterID);
            }
    
            #endif
    
        }
    
    }
    

    Install it in a script named "ActionTeleportPM", and it should appear as Object: Teleport PM.

  • @PurpleShine I am having similar issues as regards to Player Starts, "normal" AC teleporting doesn't work because of PuppetMaster.

    @ChrisIceBox The teleportPM action isn't working for me right now, not when called in an OnStart Cutscene anyway. The character remains at the default starting position, and the Puppet breaks, lying on the floor.

  • Hi Chris, that is fantastic! Thanks a lot! :smile: However, I think my context is a bit different - I mean, would it be possible to Teleport PuppetMaster to the Playerstart depending on where the Player is instead of manually saying where the Player is? Because this would be kind of cumbersome. My scenario is this: I have a big island scene, on this island are houses, every house is a Unity Scene on his own. Meaning: when I go into a house, the scene switches, and when I go back, the scene switches back to the big island scene. With the custom action you wrote that means I would for example have to make a boolean for every scene to make clear where the Player came from. Isn't it easier if PuppetMaster would just follow where the Player came from? Or is that too difficult? Your action would work if I could manually adjust the action from the marker itself (Previous scene activation). However, I guess AC is not designed in that way.. So, is there another way or should I just go with booleans? (Maybe you have an other idea about it that I don't grasp, just to make sure)

  • (As far as I know it's not possible to teleport a Player from one scene to another with a custom action. And yet, that is what this is about. Correct me if I am wrong of course)

  • I made a video to make the problem more clear:

  • edited April 2021

    Ahh, Citadel Island... :)

    If the Action isn't exactly what you're looking for, consider it more as a test for now. As with @Deckard_89, the first step is to have the ability to move both the AC Player and Puppet Master to some intended place - we can deal with having it work with PlayerStarts etc later.

    Your new video doesn't show much in the way of AC - where is your Player component, and what else is involved? If Invector is part of the character too, that may well be contributing to the Player.

    Is your AC Player a child of PuppetMaster, and is the character model always supposed to be at the same position as the PuppetMaster origin? If so, it may be that the Player has to be given a local position of zero when teleporting.

    If you keep your Player character in the scene, and don't rely on spawning any Player prefab via the Settings Manager, then the only difference between starting a scene directly from Play Mode vs entering it from another scene should be in which PlayerStart the Player begins from. If PuppetMaster is disconnecting from the Player, then you'll need to speak with PuppetMaster's author about it.

    Try this alternative script. Attach it to the same object as the AC Player component, and fill in its Inspector:

    using UnityEngine;
    using RootMotion.Dynamics;
    using AC;
    
    public class PMTeleportTest : MonoBehaviour
    {
    
        private Char character;
        public PuppetMaster puppetMaster;
    
        private void OnTeleport ()
        {
            if (character == null) character = GetComponent <Char>();
            puppetMaster.Teleport (character.Transform.position, character.Transform.rotation, true);
            Debug.Log ("Teleported PuppetMaster to " + character.Transform.position);
            character.Transform.localPosition = Vector3.zero;
        }
    }
    

    What is the behaviour when teleporting (try an Object: Teleport Action), and what appears in the Console?

    If there's no change, I'm going to need to know exactly how PuppetMaster is intended to work - at the moment, I'm only hazarding guesses based on what I've seen so far.

  • Thanks again for your amazing thorough answer Chris! I will look into it tomorrow! :smile:
  • edited April 2021

    Hi Chris,

    I just did some tests:

    • The character controller object and the PuppetMaster object are both children of the Root Object (there is nothing on the root object since this is not allowed by PuppetMaster).

    • Teleporting with your custom Action script works perfect.

    • Teleporting with an Object : Teleport also works perfect, although sometimes it looks like (it goes sometimes faster than other times, it's hard to see) it literally translates the PuppetMaster object through Deltatime/Update-time frames per second, which I think is not what we want. I don't get messages except for the one that you wrote in the custom script ( I mean in the script on the character).

    • The new script you wrote (script on the character) works perfect when it works, meaning: if I go from one scene to another it works, PuppetMaster stays at the same location as that of the character. But when I go back it often loses PuppetMaster again.

    I made another video about it (I am sorry if it is a bit long):

  • @ChrisIceBox After more testing, I got the TeleportPM action you wrote to work when using it e.g in a trigger or interaction, but I cannot get it to work via an OnStart cutscene (instead of using PlayerStarts).

    I also got the new script you posted (to be used as a component on the player) to work via object: teleport on the player, and it printed in the console as with @PurpleShine - all was well, but again, I cannot get it to work via scene start cutscene, even if it's the very first action being called.

  • The end of the video shows an error occurs when re-entering the Citadel scene - what is the full message?

    Both the OnStart cutscene and PlayerStart teleporting occur in AC's Start method - it may be that PuppetMaster hasn't finished initialising at this moment.

    @Deckard_89 What is the result of inserting a brief Engine: Wait Action before the OnStart teleport Action? If that has an effect, try a wait of -1 - that'll cause it to wait exactly one frame.

    If that has an effect, it may be that altering Script Execution Order values can sort things.

    Both scripts above were written on the assumption that the Player component was lower down in the Hierarchy than PuppetMaster. If they're instead side-by-side, don't check "Is Player?" in the Action. You'll also need to remove the final line (that updates the local position) in the PMTeleportTest script.

  • Good shout on the Script Execution Order, Chris. I gave PM a negative value (but after camera), unchecked IsPlayer & added a short Engine: Wait delay, now it works - without needing to modify the script.

    Now I'll have to go through my game and swap all player starts with manual teleport actions, but at least it works, thank you very much.

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.