#pass data from scenes
1 messages · Page 1 of 1 (latest)
could you explain that a bit further? I am having trouble to follow along with your idea a bit, sorry
e.g.
public class Player : MonoBehaviour
{
public static Player Player;
public PlayerHealth health;
//other components
public void Awake()
{
if (Player == null) Player = this;
else Destroy(gameObject);
}
}
known as the "Singleton" pattern
thanks for your time, I guess I will have to read what that is.
I appreciate your help :)
np. The other way is some single manager script that handles passing the player reference into a scene once it loads:
e.g. GameManager loads scene, Finds some "SceneManager" component and gives it the player instance.
Then SceneManager can either provide it to other components, or others grab it from SceneManager.
if done this way, wait a frame before doing Find() to locate the Scene specific script.
yeah in my research I came across the Find() solution, but I had heard somewhere that Find() is not good or something so I stayed away from it
Id say its fine if used a singlular time when you loaded a new scene such as what i describe above.
If we limit it to that single instance then its not soo bad. You can also get the root objects of a newly loaded scene and find it amongst those.
yeah that wouldnt really work, as every object that damages the player would need to use that. That doesn't sound that good to me
The difference is one is easy but less flexible, the second way where a reference is passed more manually is harder but allows for easier testing and refactoring later.
It can be made easier if you just have a way to quickly grab and make a list of stuff to Init() and give dependencies to in your single scene script.
Many projects i work on use this approach.
You can look into dependency injection frameworks to do this stuff for you but tbh just pick what you want for now if you are learning stuff
alright, I will look into that, thanks
sorry to bother you, but I am still having trouble with this.
I tried with the singleton pattern, but the field where I would add the Player GameObject in the Editor of the other scene is empty.
There is a unity forum post that explains my issue perfectly, but once again, I could not make their solution work.
https://discussions.unity.com/t/assigning-object-references-across-several-scenes-with-dontdestroyonload/800909
Is there any chance you could provide further help to me?
Thanks in advance :)
The objects that depend on the player should not have a Serialized ref to it but instead either update their ref on scene load with the correct player instance or have them ref some script that manages the scene where the player reference can be updated.
E.g. Scene manager has a player reference, enemies and other things all ref scene manager to get the player.
On scene loads you tell the scene manager instance "this is the player reference, store it!"
I should remind you again the singleton pattern for the player also solves this.
Ofc don't do something like have each component find the player as that would be inefficient doing like 50+ finds.
Yeah I had tried with the singleton pattern, but that didn't solve my issue, as I still couldn't reference the player from the script in the second scene
what is "reference" in this case?
give me a minute so I can provide further screenshots to be able to clarify it a bit better
there isnt much more i can say, you just need to handle the dependencies better to support going between many scenes
Scene A has the Player GameObject with the PlayerHealth script attached to it.
When I unload Scene A and load Scene B I have set the Player GameObject to DontDestroyOnLoad.
The PlayerHealth script has a function called TakeDamage which I want to call from a GameObject in Scene B
//inside of PlayerHealth script
public void TakeDamage(float damage)
{
health -= damage;
lerpTimer = 0f;
durationTimer = 0;
overlay.color = new Color(overlay.color.r,overlay.color.g,overlay.color.b,1);
}
//Script in Scene B
public class DamagePlayer : MonoBehaviour
{
public PlayerHealth playerhealth;
// Start is called before the first frame update
void Start()
{
playerhealth.TakeDamage(20);
}
}
What I mean by not being able to set the reference is in the editor of Scene B I can not select the Player, as he is in a different scene
Yea you just cannot do this
I did try with the Singleton pattern in the PlayerHealth script, but I still wasn't able to call the TakeDamage function in the DamagePlayer script
No that will work, if the Player instance is stored in a static field, it should be usable anywhere (as long as you dont change it later)
What i explained earlier is you need to either do the singleton pattern correctly or give this DamagePlayer script the Player/PlayerHealth instance on the scene load.
So this would be a correctly implemented singleton pattern?
public class PlayerHealth : MonoBehaviour
{
public static PlayerHealth Instance;
private static float health;
private float lerpTimer;
[Header("Health Bar")]
public float maxHealth = 100f;
public float chipSpeed = 2f;
public Image frontHealthBar;
public Image backHealthBar;
[Header("Damage Overlay")]
public Image overlay;
public float duration;
public float fadeSpeed;
private float durationTimer;
public void Awake()
{
if(Instance == null) Instance = this;
else Destroy(gameObject);
}```
That means now I should be able to just say PlayerHealth.Instance.TakeDamage?
Id handle things like this: (where a central service passes around the player instance)
YES IT FINALLY WORKED
I was just incredibly stupid and using Instance.TakeDamage the entire time instead of PlayerHealth.Instance.TakeDamage
static fields are accessed via the Type name as they do not belong to an instance
You should do some reading into some core c# concepts then:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/static