Forum rules - please read before posting.

Player Switching throughout scenes

I am currently implementing player switching and am hitting some roadblocks. 
Whenever a switch occurs, the previous character should stay it it's last position and be interactive with the new player.

I used player switch and teleport actions to switch player and move the NPC placeholder far away. This works nicely but:
If I switch to a character, that is in another scene, the teleport action doesn't run since the ActionList was part of the last scene(even though it's an asset). So far I didn't find any usable solution. I could create a separate action list in the new scene, that would trigger OnLoad and check for any NPC placeholders that need to be moved, but since we have over 100 scenes, this is not a very viable option.

My solution: I would use just one prefab for the player and NPC: it would have all components for player and NPC, where the NPC scripts would be disabled. Whenever the player gets switched, my custom switch action would first change the gameobject tag from Player to something else and enable those NPC scripts(and maybe disable Player scripts).
And because that object no longer has Player tag it wont get removed when KickStarter.ResetPlayer() runs.
It works fine but my only issue is, that the object is not persistant. It doesn't save with the scene so whenever we come back to this scene the NPC is gone. I added remember NPC and remember transform scripts with no success. 

Is this approach alright? If yes, how could I make AC save the NPC gameobject?

Comments

  • edited July 2018
    If it's any help, I'm doing something similar in my current game (although using a rather different solution to the one you're attempting)

    I have 8 or 9 different characters who can potentially become the Player character, and I switch between them via a conversation dialogue option ("Take over from me"). It should appear to the actual game player as if the game is simply swopping control between the two characters

    Each actor has one prefab for their Player character, and another separate one which is the equivalent NPC character. Apart from either a "Player" or "NPC" Component as appropriate, they both also have a "Constant Id" Component with "Retain in Prefab" set true, and a "Moveable" Component

    When the time comes to switch over I use the "Player Switch" ActionList

    The first part of that works fine, I enter the new Player from the drop-down list, specify "Replace NPC", and give it the Prefab of the NPC who is going to become the new Player Character. AC actually keeps the old NPC gameobject in the scene but moves it off screen (to somewhere like (100, -100, 100))

    However, although that bits works fine, I was never able to get "Old Player: Replace with NPC" to work unless the NPC that was going to replace the old player was already physically present in the scene. And that wasn't any use because I wanted to use a prefab, because the switch could potentially happen in any scene

    So, what I do instead is to record the current Player's Transform position before doing the switch, and then use "Old Player: Remove from Scene". After that I use the "Object: Add" ActionList to spawn the NPC prefab replacement into the scene at the pre-recorded position

    So far that's worked for me without too many problems (and those were mainly down to wanting the replaced player character to start following any in-scene path that happens to be available)

    It's a 2d game, but I'm sure that the technique would work just as well in a 3d game
  • Indeed - the NPC you replace the old Player with must already be present in the same scene.  It can still be a prefab, just with an instance of it placed in the file and hidden far away.

    I shall see if its viable to include an option to auto-spawn an NPC prefab, however.
  • Looking further into this, I have to concur with @HarryOminous' suggestion of using the Object: Add or remove Action to spawn the NPC beforehand.

    This Action will check the prefab's presence in the scene beforehand - meaning you can call it without worry of duplicates being spawned.

    In order to save an object's presence in the scene, attach the Remember Transform component, check both Save scene presence? and Retain in prefab?, and make sure the prefab is placed in a Resources folder.  For more on this, see the Manual's "Saving asset references" chapter.
  • Wow somehow my comment got deleted after 5 minutes. Here we go again.

    HarryOminous thank you for your opinion and suggestion. I see that we both have similar problems and different solutions. I was first attempting to use two prefabs for each character, a player and a NPC one. This solution however might be over complicated since in case we need to change lets say sprites of some body parts we need to do it in both prefabs. That is not ideal.
    Thats why I was trying my approach of one prefab that gets "decoupled" once it gets switched with another player. The object stays behind and NPC related stuff gets enabled. 
    I managed to get it to work now by adding those prefabs to the Resources folder and setting up Remember Transform components. It works pretty neat, even switching from and to another scene works fine. I also added a hotspot and interactions with asset related action lists and it worked neatly, even character follow and talk works. 
    My only issue now is that if lets say an NPC that was a player gets moved by Keep out of players way? or Player follow and gets then switched back as the player it will jump to it's original position. 
    Is there any solution implemented to save player positions by code or while moving?

    Thanks again for your help!

    PS:(my original comment got deleted after I edited it, could be a forum related bug)
  • So to be clear:
    1. A Player becomes an NPC
    2. The NPC moves
    3. The NPC becomes the Player again, but the Player spawns in their position from #1
    Correct?

    The Player: Switch Action has a New Player position field that, when set to Replace NPC, will cause the "saved" player position to be overridden with the NPC he replaces.

    However, if you're using a custom script to de-couple the Player and doing Player/NPC conversions then it might be that won't work - though I can only speculate.

    When a player is spawned in, they'll return to their previous "saved" position.  On a technical level, the "New Player position" field simply update their position afterwards.  If you're doing this all with a custom system, you'll need to store the NPCs position before switching player, and then re-apply it to the player afterwards.
  • Hello and thanks for restoring my comment. I hope you found the issue.

    After wasting a whole week with player switching I figured that this might not be the best solution. Switching players in the same scene is working fine but as soon as the new player is in a different scene everything falls apart. 
    Sometimes there is no player in DontDestroyOnLoad, sometimes the default camera gets changed and sometimes there are duplicate objects with the Player tag. So I dropped my whole idea and used a different set of prefabs for NPCs instead.

    Those work fine althought there are some issues of which I managed to sort some out.
    1. Switching player that is in a different scene won't remove his placeholder NPC. So I wrote an Awake() function that checks if that NPC is the player and removes it.(using Kickstarter.scenechanger.ScheduleForDeletion(). I hope this is fine?)

    2. I had to create many Actions for every player switching scenario. For example, I have 5 players, so I need about 4 Action times 5. (figuring out which NPC to replace it and some other stuff). So I copied your PlayerSwitch Action and added this stuff in code. It now also checks if switching is made in same scene so the script itself removed the placeholder NPC instead of the Awake() function.

    3. Switching between characters to other scenes sometimes switches to default (0) character and puts the one that was supposed to be switched to to pos 0,0. Not sure why as of yet.

    4. Last week before I've written a single line of code I asked how to make objects stay in scene after switching forth and back. You told me to add a RememberTransform component which I did and it worked fine. Right now I do not have any Remember components attached but they still stay when coming back. I do however have a ConstantID attached. Is this enough to serialize the object and load it back? If yes, super!

    In conclusion: I made separate NPC prefabs to be replaced to as you suggested. I used a modified version of PlayerSwitch Action that has references of all PlayerNPC prefabs and uses the corresponding one. I attached a script to every PlayerNPC prefab that Destroys the object if it has the same name as the player.

    Sorry for the long comment!



  • 1. This is fine, though you could possibly do this with a Player: Check / Object: Add or remove Action instead of resorting to a custom script.  I shall see if its possible to automate this as part of the Player: Switch Action, however.

    2. I don't know the exact contents of each of those ActionLists, but it may be that use of ActionList parameters can be of use here.  Like function parameters, ActionList parameters are designed to let you "recycle" Actions by altering their fields dynamically when run.

    3. Sounds like a bug, but I'll need more details and steps to recreate.  If you can learn more about the conditions that cause this, please let me know.

    4. Which objects, NPCs?  That shouldn't be the case - though it may be that Unity now remembers such changes when testing in the Editor.  Use of the Remember Transform component is necessary for reliable dynamic object saving.
  • I hope it's ok for me to jump into this thread, but these are some of the same kind of issues I've also been struggling with recently

    The problem with the suggestion for 2) above is that ActionLists don't handle Prefabs passed as GameObject parameters in the same way as they handle them within the ActionList itself

    So, for example, if you write an ActionList which contains a number of actions: NPC Character MoveAlongPath/Stop, NPC Character FaceObject (Player), Player Walks to NPC Marker,  Player FaceObject (NPC), then, if you hardcode the NPC Prefab into the ActionList itself, everything works fine, AC finds the NPC in the scene and processes the actions accordingly

    However, if you try and parameterise it, and pass the NPC to the ActionList via a GameObject parameter, and use THAT instead, then... well, the way it will fail will depend on the particular Action you're using, but it definitely won't work, and will most likely fail with a NullReferenceException or similar

    Which means that you're pretty much forced to duplicate that ActionList for each individual NPC. Not too bad if you've only got a couple of NPCs, but I've got over 20, with more planned, so it's starting to become a bit of an issue for me
  • @ChrisIceBox ;
    3. I managed to find the issue. Some scene's default cameras didn't yet have a ConstantID so sometimes camera would go to MainCamera(that is created with scene setup) and switches to default(0) player. Not sure if this is the exact cause but after I attached ID scripts to all cameras the bug was gone. Very weird.

    4. Yes NPCs that are instantiated in place of the player. Previously they would disappear when I switched scene forth and back, now they are still there, even after saving and loading game. I do have a RememberTransform on them but it's disabled. All I have is ConstantID. If this is sketchy then I shall re-add those RememberTransforms oh PlayerNPC prefabs just to be safe.

    All in all, player switching now seems to work like it's suppost to. 
  • @HarryOminous
    I skipped using a spaghetti of ActionLists by making my custom Switch. I feel this way I have more control over everything and I can replace an Action with a simple line of code. 
    I did use objects ad ActionList parameters once but only for in-scene. Do they not hold a constantID? That would explain why you get a NullRefException.
  • All my NPCs have ConstantIDs set as "Retain in Prefab". I think the basic problem is that ActionLists aren't designed to handle NPC Prefab GameObjects passed in as parameters (at least in the way I was trying to use them)

    I've been using scripting for many aspects of my game, such as array processing, which isn't handled natively by AC - but there are some instances such as handling Player/NPC interactions where it's always seemed as if it should be quicker to write as ActionLists

    But, like you say, it can often lead to a jumble of spaghetti which is almost unreadable, especially if you come back to it some time later, so I may have to reconsider that approach

  • edited July 2018
    @11tomi12:
    1. Actually I was mistaken - this functionality should already be in there.  You haven't stated your Unity/AC version numbers, but assigning an NPC in the Player: Switch Action's NPC to be replaced field should cause an automatic removal of that NPC.  I have uncovered some related bugs however (see below).

    3. That's as intended - whereas Remember components save changes made to a component, the ConstantID component saves references - i.e. which camera in a scene is active.  This is covered in the Manual's "Saving scene objects" chapter, but AC can attempt to add necessary save components via the top of the Settings Manager.  If such a component is missing upon saving, the Console should warn you about it.

    4. Interesting, what's your Unity version?  I'd expect this wouldn't be the case in builds.

    @HarryOminous:
    Passing a prefab as a parameter should work - are you working with ActionList assets or scene-based ones?  This sounds like it isn't solely to do with player-switching, so please post full details in a new thread so that I can recreate.

    OK, now on to my own testing..

    So I've been through the general workflow for creating a multi (3 or more) player-switching game mechanic, and there are admittedly a few problems.  I'll be addressing them as part of the upcoming v1.64 update.  In summary:

    1) If you switch to a new player for the first time, the "NPC to replace" is removed, but not used as the new player's starting position.  This occurs regardless of whether or not a scene change is required.  This'll be fixed.

    2) NullReferenceException errors if the NPC to replace the old Player / NPC to be replaced by the new Player is not present in the scene.  Such an NPC should still be present beforehand, but the game shouldn't break if not.  Again, this'll be fixed.

    3) Due to the "NPC to replace the old Player" needing to be explicitly set per-player, I found that it's necessary to create a large chain of Player: Check / Player: Switch Actions when it's possible to switch between 3+ player characters.  Similarly, the "New player's placeholder NPC" also needs to be explitly set.  In testing three players, I found that creating a succesful player-switching mechanic required 3 ActionLists of ~6 Actions each because of this.

    My solution is to add an Associated NPC Prefab field to the Player Inspector, which can be referred to automatically.  Instances of this NPC will be used to automatically add/remove the placeholder NPC of both the old and the new Player - and the spawning should be automatic too.  This workflow should reduce each Player-switch ActionList to just a single Player: Switch Action.
  • My Unity version is 2018.1.6f1 and previous 2018.1.5f1. 

    @ChrisIceBox
    Your solutions sounds great! But since I already got it working 100% I wouldn't dare scrambling around again. I'll wait for your upcoming fixes and then consider changing the way it works. 
    Something else: Is there any randomizing Action in AC? If not, it would be great to have one. It would be great for let's say randomizing some NPC responses or animations. 
    I found a way to do this with parameters and setting them to random. But this action would still only have two outputs, true and false. What about having a dynamic range of more than two outgoing actions? This would be great!
  • @11tom12 apologies for hijacking your thread. I've started a new thread as a bug report for my particular problem

    P.S. As to randomising NPC repsonses and so on, ActionList Variable/Check Random Number allows you to create any number of different random actions
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.