The Cinemachine Camera is not snapping to the player after scene load (Cinemachine 3.1.4, Unity 6)
This is part of the Unity 2.5D Turn-Based RPG: Build Your Own Turn-Based Battles & Environments course.
Heading into battle > Changes scene to battle scene > defeat/win > load back to the overworld scene with the correct player position works all fine.
When running the game directly from the overworld scene, the problem doesn’t exist, and everything works.
The issue is apparent when I start the game from another scene (the main menu scene > prologue scene > overworld scene) as I enter a battle and load back, the camera races forward from its original start position (at the start of the overworld scene) all the way to the player (where the player had the battle), creating a noticeable delay, and furthermore, the player doesnt load in the correct postion either which is weird.
I’m not sure exactly what the problem is, since it works when loading straight from the overworld scene.
Perhaps it’s an initialisation order or something to do with cinemachine.
I tried many things, such as turning the xyz position damping to 0, which cut the camera straight to the player (which is good), but it created a small glitch where it momentarily shows the last frame of the battle.
I would really appreciate any help as I’ve been trying to troubleshoot this for a while
I added a visual fade out from the battle scene which hides the glitch!
Now, the spawning issue.
At the moment, it seems like wherever I enter a battle in the overworld scene, and then enter the battle scene and load back into the overworld, I’m always loading in the same place, and it’s always where I initiated my first battle.
And another issue, when I recruit another character, she doesn’t load back with me in the overworld scene and ends up back in her original position in the overworld before I recruit her. Also, a dublicate ends up following me after returning out of nowhere a few seconds later.
That was going to be my suggestion. Not much else you can do to stop that first frame buffer. I’ve always stuck to using a transition. You’ll find this in lots of games between scenes.
At the end of the battle, you should be spawning in the location where you were when you entered the battle, so this is normal… unless you’re meaning that in successive battles, you’re going back to that first location, that’s not normal.
The position is stored in PartyManager when you change scenes, and should be getting set every time you start an encounter in PlayerController.FixedUpdate()
This one I"m not sure at all about, since the JoinableCharacterScript should be checking with the PartyManager to see if the character is in the party. If it is, then it should be SetActive(false). That’s called on Start (and PartyManager is a Singleton, so it should already be there if a character had already been recruited).
I doubly can’t explain the actual follow character being spawned a few seconds later, this should be happening right away. That almost sounds like a coroutine is managing it (which it should’t be).
Paste in your CharacterManager.SpawnOverworldMembers() method.
Thank you very much for the response both on the video and here.
Yeah, it also makes the battle seem smoother between transitions. I need to add a fade-in for the transition to the battle scene next!
Sorry if I didn’t word it well. I meant that the character is indeed returning to the first location, which, as you said, is not normal. It’s either not updating the saved player position correctly before entering battle or not restoring that position properly after loading back into the overworld, since it’s always where the first battle commenced.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class CharacterManager : MonoBehaviour
{
[SerializeField] private GameObject joinPopup;
[SerializeField] private TextMeshProUGUI joinPopupText;
private bool infrontOfPartyMember;
private GameObject joinableMember;
private PlayerControls playerControls;
private List<GameObject> overworldCharacters = new List<GameObject>();
private const string PARTY_JOINED_MESSAGE = " Joined The Party!";
private const string NPC_JOINABLE_TAG = "NPCJoinable";
private void Awake()
{
playerControls = new PlayerControls();
}
// Start is called before the first frame update
void Start()
{
playerControls.Player.Interact.performed += _ => Interact();
}
// Public method to be called once PartyManager is initialized
public void InitCharacterVisuals()
{
Debug.Log("CharacterManager: InitCharacterVisuals()");
// clear any old visuals
foreach (var go in overworldCharacters) Destroy(go);
overworldCharacters.Clear();
// now spawn fresh
SpawnOverworldMembers();
}
private void OnEnable()
{
playerControls.Enable();
}
private void OnDisable()
{
playerControls.Disable();
}
// Update is called once per frame
void Update()
{
}
private void Interact()
{
if (infrontOfPartyMember == true && joinableMember != null)
{
MemberJoined(joinableMember.GetComponent<JoinableCharacterScript>().MemberToJoin);//add member
infrontOfPartyMember = false;
joinableMember = null;
}
}
private void MemberJoined(PartyMemberInfo partyMember)
{
GameObject.FindFirstObjectByType<PartyManager>().AddMemberToPartyByName(partyMember.MemberName);// add party member
joinableMember.GetComponent<JoinableCharacterScript>().CheckIfJoined();// disable joinable member
// join pop up
joinPopup.SetActive(true);
joinPopupText.text = partyMember.MemberName + PARTY_JOINED_MESSAGE;
SpawnOverworldMembers(); // adding an overworld member
}
private void SpawnOverworldMembers()
{
List<PartyMember> currentParty = GameObject.FindFirstObjectByType<PartyManager>().GetCurrentParty();
Debug.Log(" Current party count: " + currentParty.Count);
Debug.Log("SpawnOverworldMembers called.");
for (int i = 0; i < overworldCharacters.Count; i++)
{
Destroy(overworldCharacters[i]);
}
overworldCharacters.Clear();
for (int i = 0; i < currentParty.Count; i++)
{
if (i==0) // first member will be the player
{
GameObject player = gameObject; // get the player
GameObject playerVisual = Instantiate(currentParty[i].MemberOverworldVisualPrefab,
transform.position, Quaternion.identity); // spawn the member visual
playerVisual.transform.SetParent(player.transform); // settting the parent to the player
player.GetComponent<PlayerController>().SetOverworldVisuals(playerVisual.GetComponent<Animator>(),
playerVisual.GetComponent<SpriteRenderer>()); // assign the player controller values
playerVisual.GetComponent<MemberFollowAI>().enabled = false;
overworldCharacters.Add(playerVisual); // add the overworld character visual to the list
}
else // any other will be a follower
{
Vector3 positionToSpawn = transform.position;// get the followers spawn position
positionToSpawn.x -= i;
GameObject tempFollower = Instantiate(currentParty[i].MemberOverworldVisualPrefab,
positionToSpawn, Quaternion.identity);// spawn the follower
tempFollower.GetComponent<MemberFollowAI>().SetFollowDistance(i); // set follow ai settings
overworldCharacters.Add(tempFollower); // add the follower visual to our list
}
}
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == NPC_JOINABLE_TAG)
{
//enable our prompt
infrontOfPartyMember = true;
joinableMember = other.gameObject;
joinableMember.GetComponent<JoinableCharacterScript>().ShowInteractPrompt(true);
}
}
private void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == NPC_JOINABLE_TAG)
{
//disable our prompt
infrontOfPartyMember = false;
joinableMember.GetComponent<JoinableCharacterScript>().ShowInteractPrompt(false);
joinableMember = null;
}
}
}
I’m not seeing what could be causing this here. I’ll need to take a closer look at the project.
Zip up your project and upload it to https://gdev.tv/projectupload.
Be sure to remove the Library folder from the zip to conserve space
Be sure to tag me (Brian T) as the requesting instructor
Be sure to include a link back to this message so I can easily get back to you.
I re-saved the player’s position inside a new FadeManager script just before loading the battle scene, which seems to have fixed the player position problem. Now, to fix the duplication of the character!
Apologies, I misunderstood and thought your isssues had been resolved.
In terms of the download you sent, I never received said email (or it was filtered out so that I never saw it).
Be sure to zip the project and remove the Library folder to conserve space.
Be sure to tag me (Brian T) as the requesting instructor and include a link back to this topic.
I’m still having trouble with my character reappearing after scene load. I think the game is having trouble saving preferences and is instead restarting the scene after loading back from the battle scene, which reinstates the recruited character.
That upload website just does not work for me at all. The upload portion always gives me an error, so I’ve copied the necessary information and pasted it in an email alongside a link to my zip file.
EDIT:
I forgot to include that to get the problem to happen, you have to start the game from the Main menu and then click on ‘New Game’ and then recruit the character!
This is odd, the joinable character is acting correctly for me. Once she’s recruited, she doesn’t reappear in the overworld scene at her spawn location, but is immediately following me.
This suggests that there may be a Library issue (when you move a project to a different computer, it rebuilds the Library).
Try this:
Close Unity
Navigate to the project’s location and delete the Library folder
No, deleting the library will simply force Unity to rebuild it’s internal database, which is based on the contents in the assets folder. Whenever an asset is added to the assets folder, it’s converted to a format that is more easily used by Unity in the Library folder. That’s why when we have you send a project, we have you exclude that folder. When a project is moved to a new computer, the library has to be rebuilt anyways. Sometimes, something will get messed up in the library, and without a rebuild will cause issues in Unity.
I did the above steps, started the game from the main menu and after returning from battle, the recruitable character was still there (as well as the one that was following me). I’m not sure what the problem is. At first, I thought it was something to do with persistent data not loading properly since i’m loading a battle scene and then loading back to the overworld scene. When I load from the overworld scene and repeat the steps, the character is gone and it works. But when I start the game from the main menu, the character doesnt dissapear after battle.
Ah, I had started from the Overworld Scene. Running it through the menu is leaving the joinable character in the scene when returning from battle (but I have no delay in her being by my side).
I’ll dig a little deeper.
Ok, so the solution I came up with was to remove the PartyManager from the OverWorldScene and paste it into the Main Menu scene. Not entirely sure why this made a difference, but it worked normally this time.
That is so strange. I wonder why that worked. I have yet to try it, but will get round to attempting it this weekend.
Since the PartyManager uses DontDestroyOnLoad, it still works even from the MainMenu I’m guessing. Would removing it from the Overworld cause any issues, like null references or things not working, especially when testing scenes directly in Unity?