Debugging string is empty from one function yet populated in another - c#

I've either been starting at things for too long (highly likely) or something weird is going on with a particular property. When I debug the property _animalType from my PlayerController script Debug.Log("Animal Type is : " + _animalType); it's coming back as an empty string, yet when I debug it from CanvasController Debug.Log(player.GetComponent<PlayerController>().AnimalType); it shows that the string is populated with the correct data. Can anyone see what might be happening here? Thank you!
'CanvasController.cs'
public void PrepareAnimalData()
{
StartCoroutine(DoPrepareAnimalData());
Debug.Log("Send To Forest Button Pressed.");
}
IEnumerator DoPrepareAnimalData()
{
yield return new WaitForEndOfFrame();
RenderTexture tmp = RenderTexture.active;
RenderTexture.active = BackLayerController.RenderTexture;
TmpTexture2D.ReadPixels(new Rect(0, 0, RenderTextureSize.x, RenderTextureSize.y), 0, 0, false);
player = GameObject.FindGameObjectWithTag("Player");
PlayerController.animalTex = TmpTexture2D; // set PlayerController animalTex to TmpTexture2D
player.GetComponent<PlayerController>().TexToBytes(); // run function from PlayerController
player.GetComponent<PlayerController>().AnimalType = PageConfig.UniqueId; // set animalType in PlayerController
Debug.Log(PageConfig.UniqueId);
Debug.Log(player.GetComponent<PlayerController>().AnimalType);
}}
PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class PlayerController : NetworkBehaviour
{
public static Texture2D animalTex;
private byte[] textureBytes;
private string _animalType;
public string AnimalType
{
get
{
return _animalType;
}
set
{
_animalType = value;
}
}
private string _playerID;
public string PlayerID
{
get
{
return _playerID;
}
set
{
_playerID = value;
}
}
private void Awake()
{
GameObject gm = GameObject.FindGameObjectWithTag("GameManager");
}
void Update()
{
if (!isLocalPlayer)
return;
}
public void TexToBytes()
{
textureBytes = animalTex.GetRawTextureData();
DebugAnimalData();
}
public void DebugAnimalData()
{
Debug.Log("Byte Array Length is : " + textureBytes.Length);
Debug.Log("Animal Type is : " + _animalType);
Debug.Log("Player ID is : " + _playerID);
}
}

You called this (which shows it outputs the info)
player.GetComponent<PlayerController>().TexToBytes();
before you set it
player.GetComponent<PlayerController>().AnimalType = PageConfig.UniqueId; // set animalType in PlayerController

When TexToBytes is called, it internally invokes DebugAnimalData logging data. At this time, _animalType is still initialized to null. However, after this, your next statement is setting _animalType through Setter and thus, next Debug logs start logging the value

Related

Accessing none Monobehaviour class view Photonview

I'm trying to set up a function that updates a players sprites/colours based on a class that isn't derived from monobehaviour, but because of this it wont allow me to add it to the photonview.
My game has a class called PlayerDataClass that stores all the information for the local player. I haven't set this up as a monobehaviour class as I want to be able to access it without attaching it to a gameobject. However because of this I'm unable to access it with photonview.
Is there a way to do this? Or is there a better alternative?
I'm currently just logging the name of the ColorTheme variable attached to PlayerDataClass, but it just logs the local client variable rather than the client who called the function.
PlayerDataClass.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Photon.Pun;
[Serializable]
public class PlayerDataClass
{
[SerializeField] private string username;
[SerializeField] private string colorTheme;
[SerializeField] private string color1;
[SerializeField] private string color2;
public string Username {
get { return username; }
set {
username = value;
PhotonNetwork.NickName = value;
}
}
public string ColorTheme {
get { return colorTheme; }
set { colorTheme = value; }
}
public string Color1 {
get { return color1; }
set { color1 = value; }
}
public string Color2 {
get { return color2; }
set { color2 = value; }
}
}
NetworkPlayer.cs
using Photon.Pun;
using Photon.Realtime;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class NetworkPlayer : MonoBehaviourPun
{
public Vector3 m_NetworkPosition = Vector3.zero;
Rigidbody2D rb;
public PlayerDataClass m_Player = new PlayerDataClass();
void Awake()
{
// Import scripts
}
void Start()
{
rb = GetComponent<Rigidbody2D>();
if (!photonView.IsMine)
{
photonView.RPC("UpdateColor", RpcTarget.AllBuffered, null);
}
}
[PunRPC]
void UpdateColor()
{
Debug.Log("local color name is " + m_Player.ColorTheme);
}
}
It sounds like what you want is sync the m_Player.ColorTheme to other clients.
Your NetworkPlayer which is the "owner" of the PlayerDataClass instance is a MonoBehaviourPun so you can relay all requried sync calls through it .. like you basically already did with UpdateColor ... you just need to pass in a parameter:
[PunRPC]
void UpdateColor(string theme)
{
// Assign the received string
m_Player.ColorTheme = theme;
Debug.Log($"local color name is now \"{m_Player.ColorTheme}\"");
}
and call it like
// instead you should rather do this only if you ARE the owner of this view
// YOU want to tell OTHER users what your color is
if (photonView.IsMine)
{
// Pass in the string to be synced
// Rather use OthersBuffered since you don't want to receive
// your own call again
photonView.RPC(nameof(UpdateColor), RpcTarget.OthersBuffered, m_Player.ColorTheme);
}
You could also consider to make your entire PlayerDataClass a photon synchronizable Custom Type and send it over entirely.

C# Unity Queue NullReferenceException

I am trying to create a simple dialogue system for my game in Unity. I've set up a special trigger for a Dialogue to start and the code is passing right variable but somehow it gets stuck at clearing the queue and throws a NullReferenceException.
I've seen through debugger that all variables and triggers work perfectly fine till cs:27 inside DialogueManager.cs. I've also checked the inspector to make sure everything is correctly assigned.
Dialogue class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Dialogue
{
public string name;
[TextArea(3,10)]
public string[] sentences;
}
DialogueTrigger class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NPC_DialogTrigger : MonoBehaviour
{
// Player
public Transform player;
// GameMaager to close
public GameObject Gameplay;
// Camera and Canvas to turn on
public GameObject DialogueManager;
// NPC Details
public GameObject InteractionNPCNameTextField;
public Transform interactionTransform;
public float radius = 3f;
private bool isBusy = false;
// DialogueStart
public GameObject DialogueStart;
void Start()
{
InteractionNPCNameTextField.gameObject.SetActive(false);
}
void Update()
{
float distance = Vector3.Distance(player.position, interactionTransform.position);
if (distance <= radius)
{
if (isBusy == false)
{
InteractionNPCNameTextField.gameObject.SetActive(true);
if (Input.GetKeyDown(KeyCode.E))
{
Dialogue();
Debug.Log("Started Dialogue procedure.");
}
}
}
else if (distance > radius)
{
InteractionNPCNameTextField.gameObject.SetActive(false);
}
}
public void Dialogue()
{
Gameplay.SetActive(false);
DialogueManager.SetActive(true);
DialogueStart.GetComponent<DialogueStart>().TriggerDialogue();
Debug.Log("Triggered Dialogue.");
}
void OnDrawGizmosSelected()
{
if (interactionTransform == null)
{
interactionTransform = transform;
}
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(interactionTransform.position, radius);
}
}
DialogueStart class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DialogueStart : MonoBehaviour
{
public Dialogue dialogue;
public void TriggerDialogue()
{
FindObjectOfType<DialogueManager>().StartDialogue(dialogue);
Debug.Log("Dialogue sent to dialogue manager.");
}
}
DialogueManager class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class DialogueManager : MonoBehaviour
{
public Text nameText;
public Text DialogueText;
private Queue<string> sentences;
public GameObject DialogueManagerUI;
void Start()
{
if (sentences == null)
{
sentences = new Queue<string>();
}
}
public void StartDialogue (Dialogue dialogue)
{
Debug.Log("Received dialogues: " + dialogue);
nameText.text = dialogue.name;
Debug.Log("Start Dialogue: " + sentences.Count);
sentences.Clear();
Debug.Log("Sentences Cleared: " + sentences);
foreach (string sentence in dialogue.sentences)
{
sentences.Enqueue(sentence);
}
DisplayNextSentence();
}
public void DisplayNextSentence()
{
if(sentences.Count == 0)
{
EndDialogue();
return;
}
string sentence = sentences.Dequeue();
DialogueText.text = sentence;
}
void EndDialogue()
{
Debug.Log("End of conversation.");
}
private void Update()
{
if (DialogueManagerUI.activeInHierarchy)
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
else if (!DialogueManagerUI.activeInHierarchy)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
}
Visual Studio doesn't give me any errors.
Unity error code -> Screenshot
Debugger right before issue -> Screenshot2
Seems to me like the Queue is never assigned to sentences and it remains empty.
If it is so - why?
It sounds like DialogueManager.StartDialogue probably via DialogueStart.TriggerDialogue is called from somewhere in either Awake or at least before your Start was executed.
Especially
DialogueManager.SetActive(true);
lets assume the DialogueManager object is inactive at first anyway. So maybe your stuff is called before it is set to active.
This might also be due to the Start where you set
InteractionNPCNameTextField.gameObject.SetActive(false);
so any component on this GameObject might not have its Start method getting called. Maybe you referenced the wrong GameObject here?
Debugging would help to figure out in which order your methods get called.
In general my thumb rule for initializing is
Do everything that depends only on yourself in Awake
Do everything that depends on other components being setup already in Start
This way you can (almost) always be sure that stuff is already initialized when you need it.
However, these are only guesses but
The simple solution here:
You could already solve this by simply initializing the sentences right away using
private readonly Queue<string> sentences = new Queue<string>();
now it is definitely initialized even before Start or Awake get called!

inherit variable value from class to sub class c#

I have 2 scenes each one have own script simply I want to get a value from script 1 and use it in script 2 which is loaded in the second scenes which happen is it always load the default value for this variable ex; if I call string variable which should have value (sas) it appears in the second script with null if integer it will be 0 although if I print it in the first script it will have the right value which "sas" .
look to method goforward () which update the variable x
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Trainbehavior : MonoBehaviour
{
public float force = (float)0.1;
private Rigidbody sph;
public GameObject button_goforward;
public GameObject button_goright;
public GameObject button_results;
public GameObject button_nextlevel;
public Text Results;
public String x ;
//public int g;
//public gamepbject panel ;
//panel.gameobject.setactive(true);
private void Start()
{
sph = GetComponent<Rigidbody>();
button_goforward.SetActive(false);
button_goright.SetActive(false);
button_results.SetActive(false);
button_nextlevel.SetActive(false);
}
private void OnTriggerEnter(Collider other)
{
if (other.name == "switchtrigger")
{
button_goforward.SetActive(true);
button_goright.SetActive(true);
button_results.SetActive(true);
Time.timeScale = 0;
}
}
public void goforward()
{
setx("sas"); // if a called print x it will be sas
// Results.text = "dzf";
}
public String getx()
{
return x;
}
public void setx(String x)
{
this.x = x;
}
second script
in the update iam trying to get the value x by
finalresults.text = trains.getx();
public class cases : Trainbehavior
{
Trainbehavior trains;
public Text finalresults;
public string cx;
// Start is called before the first frame update
void Start()
{
trains = GetComponent<Trainbehavior>();
/*var trainscript = gameObject.GetComponent<Trainbehavior>();
if (trainscript)
{
finalresults.text = Results.GetComponent<UnityEngine.UI.Text>().text;
}*/
}
// Update is called once per frame
void Update()
{
// finalresults.text = trains.x;
finalresults.text = trains.getx(); // if i called print(x) it will be null !
/*
var trainscript = gameObject.GetComponent<Trainbehavior>();
if (trainscript)
{
// GameObject x = trainscript.GameObject.Find("test");
finalresults.text = cx;
print(cx);
}*/
}
}
If I understand your question you just want to call your getx function and return the value you set to x in the first script. However Unless you call that goForward function your not setting x and I don't see where your doing that. It looks like your saying when you do call goforward you get what you want which makes sense. you just need to call that goforward function in your second script to set x to a value before you call getx.
Your not inheriting x when you do this your just setting a public variable which is fine. you can either set the value to your public variable x in that function or anywhere in that class.

Text variables don't persist in multiple levels

I want to show the player name and the team name in multiple levels. I've created a gameobject with a singleton that calls servidor to load this variables. It works in the first level but not in the others. The gameobject persists but doesn't save the PlayerName and TeamName. How can I get it?
This is my code:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class GlobalControl2 : MonoBehaviour
{
private static GlobalControl2 instance = null;
private Text PlayerName;
private Text TeamName;
void Awake ()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(this.gameObject);
}
else
{
Destroy(this.gameObject);
}
}
public void Start()
{
PlayerName = GameObject.Find ("PlayerName").GetComponent<Text> ();
TeamName = GameObject.Find ("TeamName").GetComponent<Text> ();
new GameSparks.Api.Requests.AccountDetailsRequest ()
.SetDurable(true)
.Send ((response) => {
PlayerName.text = response.DisplayName;
} );
new GameSparks.Api.Requests.GetMyTeamsRequest()
.SetDurable(true)
.Send(teamResp => {
if(!teamResp.HasErrors)
{
foreach(var teams in teamResp.Teams)
{
Debug.Log("Equipo: " + teams.TeamId);
TeamName.text = teams.TeamId;
}
}
} );
}
}
Currently you are trying to persist Scene specific objects over multiple scenes
The data type "Text" is a unity object.
Try using "String" instead, in the example bellow you will see that PersistentPlayerName and PersistentTeamName will be available in the next scene and PlayerName and TeamName will not. This is always the risk that multi-scene singletons have.
Please do take note, that this should not required if PlayerName and TeamName is on the same gameobject as GlobalControl2 (the one you call DontDestroyOnLoad on)
I am not suggesting that you do it exactly as it is typed bellow, but this should be enough to set you on the right path, if not, add a comment and i will explain further.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class GlobalControl2 : MonoBehaviour
{
private static GlobalControl2 instance = null;
private string PersistentPlayerName;
private string PersistentTeamName;
private Text PlayerName;
private Text TeamName;
void Awake ()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(this.gameObject);
}
else
{
Destroy(this.gameObject);
}
}
public void Start()
{
PlayerName = GameObject.Find ("PlayerName").GetComponent<Text> ();
TeamName = GameObject.Find ("TeamName").GetComponent<Text> ();
new GameSparks.Api.Requests.AccountDetailsRequest ()
.SetDurable(true)
.Send ((response) => {
PlayerName.text = PersistentPlayerName = response.DisplayName;
} );
new GameSparks.Api.Requests.GetMyTeamsRequest()
.SetDurable(true)
.Send(teamResp => {
if(!teamResp.HasErrors)
{
foreach(var teams in teamResp.Teams)
{
Debug.Log("Equipo: " + teams.TeamId);
TeamName.text = PersistentTeamName = teams.TeamId;
}
}
} );
}
}

Unity Script Error (Error CS0118)

Please help me fix the error.
The message is:
"Assets/Scripts/GameManager.cs(6,21): error CS0118: GameManager.character' is afield' but a `type' was expected"
The error is on (6, 21). Thanks.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class GameManager : MonoBehaviour {
public List<character> character = new List<character>(); <-- (ERROR CS0118)
bool ShowCharWheel;
public int SelectedCharacter;
public int xcount;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(Input.GetKeyDown(KeyCode.C)){
{
ShowCharWheel = true;
}
{
ShowCharWheel = false;
}
//Camera.main.GetComponent<SmoothFollow>().target = characters[SelectedCharacter].
if (ShowCharWheel)
{
GUILayout.BeginArea(new Rect(Screen.width - 64, Screen.height - 192,64,192));
{
if(GUILayout.Button(c.icon,GUILayout.Width(64),GUILayout.Height(64)))
foreach (character c in Characters)
{
SelectedCharacter = character.IndexOf(c);
}
}
}
GUILayout.EndArea();
}
}
}
[System.Serializable]
public class Character
{
public string name;
public Texture2D icon;
public GameObject prefab;
public GameObject instance;
public Transform HomeSpawn;
}
Needed more details other than code, so ignore this.
Do you perhaps just need to capitalize? C# is case sensitive.
public List<Character> characterList = new List<Character>();
I also renamed your variable for clarity.

Categories

Resources