Syncing Text using PUN in Unity - c#

I'm making a simple Word Builder type of game (where one player enters a word, and the other player enters a word starting with the last letter of the first player's word), and I can't get the Text to show up on both the screens.
I'm able to get the text to show up if I hard code it, like:
[PunRPC]
public void DisplayWord ()
{
MainWord.text = "Word";
}
But I can't get it to display the word a player just entered to both screens, I thought this code would word:
[PunRPC]
public void DisplayWord ()
{
MainWord.text = UsedString;
//UsedString is the word the (one of the) players just entered.
}
Any help would be greatly appreciated, thank you so much!
Here's the full code for entering a word:
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
using Photon.Pun;
public class DictionaryScript : MonoBehaviourPunCallbacks
{
List<string> DictA = new List<string> () {
"a",
"aa",
"aaa",
"aah",
"aahed",
"aahing",
"aahs",
"aal",
"aalii",
"aaliis",
"aals",
"aam",
"aani",
"aardvark",
"aardvarks",
"aardwolf",
"aardwolves",
"aargh",
"aaron",
"aaronic",
"aaronical",
"aaronite",
"aaronitic",
"aarrgh",
"aarrghh",
"aaru",
"aas",
"aasvogel",
"aasvogels"};
public List<string> DictAUsed = new List<string>() { };
public string UsedString;
public string NewString;
public InputField inputField;
public Text AddedWord;
public Text MainWord;
public Text TurnText;
public Text ConnectedText;
public Button StartButton;
public Canvas OverlayCanvas;
// Start is called before the first frame update
public void Awake()
{
if (PhotonNetwork.IsMasterClient)
{
StartButton.enabled = true;
OverlayCanvas.enabled = true;
}
else
{
StartButton.enabled = false;
OverlayCanvas.enabled = true;
}
}
void Start()
{
if (PhotonNetwork.InRoom)
{
ConnectedText.text = "Connected!";
}
}
public void StartGame ()
{
photonView.RPC("CanvasDisplay", RpcTarget.All);
}
public void MyWord (string newWord)
{
string newString = newWord.ToLower();
print(newString);
if (DictA.Contains(newString) && newString[0] == MainWord.text[0] && !DictAUsed.Contains(newString))
{
UsedString = newString;
Debug.Log(UsedString);
photonView.RPC("OnInput", RpcTarget.All);
}
else
{
print("This word does not exist!");
AddedWord.text = newString + " is not a valid word!";
}
inputField.text = "";
}
[PunRPC]
public void OnInput ()
{
DictAUsed.Add(UsedString);
AddedWord.text = "The word was: " + UsedString;
photonView.RPC("DisplayWord", RpcTarget.All);
}
[PunRPC]
public void DisplayWord ()
{
MainWord.text = UsedString;
//UsedString is the word the (one of the) players just entered.
}
[PunRPC]
public void CanvasDisplay()
{
//string Alphabet = "abcdefghijklmnopqrstuvwxyz";
string Alphabet = "aaaaaaaaaaaaaaaaaaaaaaaaaa";
MainWord.text = Alphabet[Random.Range(0, 25)].ToString();
StartButton.enabled = false;
OverlayCanvas.enabled = false;
}
}
I only have words starting with 'aa' for now, I'll add all the words once I can get it working.

UsedString is not synchronized in your network => Each player might have a different value for UsedWorld at the moment the RPC get called.
Why not pass on the UsedWord as argument to OnInput and DisplayWord?
Also why is DisplayWord even called via RPC at all? Since OnInput is alreay synchronized to ALL you could simply call the method right away
...
photonView.RPC(nameof(OnInput), RpcTarget.All, UsedWord);
...
[PunRPC]
public void OnInput (string usedString)
{
DictAUsed.Add(usedString);
AddedWord.text = "The word was: " + usedString;
// since this shall happen on any client as well
// why even call it via RPC?
// OnInput is called on ALL anyway so just do it right away
DisplayWord(usedString);
}
public void DisplayWord (string usedString)
{
MainWord.text = usedString;
}

Related

Pubnub null reference exception in unity

I am trying to get my leaderboard working in unity using pubnub. I tried to follow and alter this tutorial but when I run it in unity, nothing shows up:
In my code, the only thing that's different from the tutorial is the publish key and subscribe key, where I set to my own one.
this is the screenshot of the keys:
this is the screenshot of the storage and playback setting:
this is the screenshot of the pubnub function setting, it says "it's automatically set to on when a module is running":
this is the screenshot of the only module in the app:
this is my code, nothing is print to the console when I tried to set usernames and scores(see comment below):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PubNubAPI;
using UnityEngine.UI;
using SimpleJSON;
public class MyClass
{
public string username;
public string score;
public string refresh;
}
public class leaderboard : MonoBehaviour
{
public static PubNub pubnub;
public Text Line1;
public Text Line2;
public Text Line3;
public Text Line4;
public Text Line5;
public Text Score1;
public Text Score2;
public Text Score3;
public Text Score4;
public Text Score5;
public Button SubmitButton;
public InputField FieldUsername;
public InputField FieldScore;
//public static leaderboard instance;
//public Object[] tiles = {}
// Use this for initialization
void Start()
{
Button btn = SubmitButton.GetComponent<Button>();
btn.onClick.AddListener(TaskOnClick);
// Use this for initialization
PNConfiguration pnConfiguration = new PNConfiguration();
pnConfiguration.PublishKey = "pub-c-450b-redacted";
pnConfiguration.SubscribeKey = "sub-c-03aa-redacted";
pnConfiguration.LogVerbosity = PNLogVerbosity.BODY;
pnConfiguration.UUID = Random.Range(0f, 999999f).ToString();
pubnub = new PubNub(pnConfiguration);
Debug.Log(pnConfiguration.UUID);
MyClass fireRefreshObject = new MyClass();
fireRefreshObject.refresh = "new user refresh";
string firerefreshobject = JsonUtility.ToJson(fireRefreshObject);
pubnub.Fire() // This will trigger the leaderboard to refresh so it will display for a new user.
.Channel("submit_score")
.Message(firerefreshobject)
.Async((result, status) =>
{
if (status.Error)
{
Debug.Log(status.Error);
Debug.Log(status.ErrorData.Info);
}
else
{
Debug.Log(string.Format("Fire Timetoken: {0}", result.Timetoken));
}
});
pubnub.SubscribeCallback += (sender, e) =>
{
SubscribeEventEventArgs mea = e as SubscribeEventEventArgs;
if (mea.Status != null)
{
}
if (mea.MessageResult != null)
{
Dictionary<string, object> msg = mea.MessageResult.Payload as Dictionary<string, object>;
string[] strArr = msg["username"] as string[];
string[] strScores = msg["score"] as string[];
int usernamevar = 1;
//setting usernames, nothing is printed to the console
foreach (string username in strArr)
{
string usernameobject = "Line" + usernamevar;
GameObject.Find(usernameobject).GetComponent<Text>().text = usernamevar.ToString() + ". " + username.ToString();
usernamevar++;
Debug.Log(username);
}
//setting scores, nothing is printed to the console
int scorevar = 1;
foreach (string score in strScores)
{
string scoreobject = "Score" + scorevar;
GameObject.Find(scoreobject).GetComponent<Text>().text = "Score: " + score.ToString();
scorevar++;
Debug.Log(score);
}
}
if (mea.PresenceEventResult != null)
{
Debug.Log("In Example, SusbcribeCallback in presence" + mea.PresenceEventResult.Channel + mea.PresenceEventResult.Occupancy + mea.PresenceEventResult.Event);
}
};
pubnub.Subscribe()
.Channels(new List<string>() {
"leaderboard_scores"
})
.WithPresence()
.Execute();
//TaskOnClick();
}
public void TaskOnClick()
{
var usernametext = FieldUsername.text;// this would be set somewhere else in the code
var scoretext = FieldScore.text;
MyClass myObject = new MyClass();
myObject.username = FieldUsername.text;
myObject.score = FieldScore.text;
string json = JsonUtility.ToJson(myObject);
pubnub.Publish()
.Channel("submit_score")
.Message(json)
.Async((result, status) =>
{
if (!status.Error)
{
Debug.Log(string.Format("Publish Timetoken: {0}", result.Timetoken));
}
else
{
Debug.Log(status.Error);
Debug.Log(status.ErrorData.Info);
}
});
//Output this to console when the Button is clicked
Debug.Log("You have clicked the button!");
}
}
If there are any other things you would need to know, please let me know.
Sorry for my English. Thanks in advance.

Getting NullReferenceExeption when trying to GetComponentInParent from a instantiated buttom prefab

I'm instanciating buttons via script and need then to call a script in a parent object a few levels up
unity hierarchy
This is in the prefab script and gets called when one of the buttons gets clicked. Performance isn't relevant at all, so I just told it to go from the bottom up until it reaches the controller game object that has the mllhildTestController.cs script attached.
public void ClickMe()
{
string parentNode = ReturnLabel();
string path = this.GetComponentInParent<mllhildTestController>().path;
this.GetComponentInParent<mllhildTestController>().Clear();
this.GetComponentInParent<mllhildTestController>().Load(path, parentNode);
}
but it only results in an error
NullReferenceException: Object reference not set to an instance of an object
this.something is working fine, so it has to be an error in my logic with the GetComponentInParent<mllhildTestController>() part.
Could someone please help me?
EDIT: this function seems to work fine, but since it was asked
public string ReturnLabel()
{
return buttonText.text;
}
Controller script
public class mllhildTestController : MonoBehaviour
{
public mllhildTestLinq linq;
public mllhildTestDisplay display;
public mllhildTestButtons buttons;
public List<GameObject> listToStuff;
public string test = "smName";
public string smName = "mllhild";
public string displayText = "display.textWindow.font";
public string path = #"C:\SlaveMaker4\Slaves\";
// Start is called before the first frame update
void Start()
{
ClearText();
// linq.LinqTest(#"C:\SlaveMaker4\Rhia.xml");
// string filename = #"C:\SlaveMaker4\Rhia.xml";
// linq.QueryXML(filename, parentNode);
// Debug.Log(this.GetType().GetField("test").GetValue(this));
// Debug.Log(this.GetType().GetField(test).GetValue(this));
// Debug.Log(display.textWindow.font);
// Debug.Log(this.GetType().GetField("display").GetType().GetField("textWindow").GetType().GetField("font").GetValue(this));
// Debug.Log(typeof(TextMeshProUGUI).GetProperty(displayText).GetValue(this));
// Debug.Log(this.GetType().GetField(displayText).GetValue(this));
}
// Update is called once per frame
void Update()
{
}
public void SetText(string text)
{
display.textWindow.text = text;
}
public void AddText(string text)
{
display.textWindow.text += text;
}
public void ClearText()
{
display.textWindow.text = null;
}
public GameObject bfield;
public GameObject AddNewButtonList(string label)
{
GameObject b = Instantiate(bfield) as GameObject;
b.SetActive(true);
b.GetComponent<PrefabListButtoms>().title.text = label;
b.transform.SetParent(bfield.transform.parent, false);
return b;
}
public void Clear()
{
foreach(GameObject b in listToStuff)
{
Destroy(b);
}
listToStuff.Clear();
}
public void LoadButton() { Load(path, "Language" ); }
public void Load(string path, string parentNode)
{
string[] fileArray = Directory.GetFiles(path, "*.xml");
foreach (string xmlfile in fileArray)
{
GameObject blist = AddNewButtonList(xmlfile + "\n" + parentNode);
listToStuff.Add(blist);
//AddText("\n\n" + xmlfile + "\n");
//AddText("Parent-Node:" + parentNode + "\n");
//AddText("Child-Nodes:" + "\n");
linq.QueryXML(xmlfile, parentNode, blist);
}
}
}
You cant access directly because you have to find parent and then you find the desired children
so your first challenge is to find the parent of your component:
so first command is : GameObject.Find("NameofObj") or GameObject.FindWithTag("NameOfTag")
so after you just find the desired children component from this GameObject..and finally you could access to the method of script linked to child

Unity Dialogue boxes

I'm trying to create a dialogue where the dialogue stops at a given count and then continues after a certain event happens. I've set the number of sentences to 6 at first and I did manage to make the conversation stop after the 3rd sentence
by setting the if statement in DisplayNextSentence() to ==> [sentence.Count == 3]
and make the player do something else but I don't know how to make the NPC continue its dialogue after finishing that certain event.
can you please enlighten me on how to do this? I did watch some youtube video but those videos either confused me or they didn't explain how that certain part work in detail but I found this method somehow easier to understand in my case.
container
[System.Serializable]
public class Dialogue {
//name of npc
public string name;
//sentences of the npc
[TextArea(3,10)]
public string[] sentences;
}
another class
public class DialogueTrigger : MonoBehaviour {
//calls the Dialogue class
public Dialogue dialogue;
//triggers the dialouge
public void TriggerDialogue()
{
FindObjectOfType<DialogueManager>().StartDialogue(dialogue);
}
}
manager
public class DialogueManager : MonoBehaviour {
private Queue<string> sentences;
public Text NPC_nameText;
public Text NPC_DialogueText;
void Start () {
sentences = new Queue<string>();
}
public void StartDialogue(Dialogue dialogue)
{
//Changes the name of the Name Text to given name
NPC_nameText.text = dialogue.name;
sentences.Clear();
//goes through the whole array of sentences
foreach(string sentence in dialogue.sentences)
{
sentences.Enqueue(sentence);
}
//displays the sentences
DisplayNextSentence();
}
public void DisplayNextSentence()
{
//condition if array sentence is finished looping
if (sentences.Count == 0)
{
//ends dialogue and goes to the next UI
EndDialogue();
return;
}
//Sentence appears in queue waiting for each sentence to finish
string sentence = sentences.Dequeue();
StopAllCoroutines();
StartCoroutine(TypeSentence(sentence));
}
void EndDialogue()
{
Debug.Log("End of Conversation");
}
IEnumerator TypeSentence(string sentence)
{
//types the characters for each sentence
NPC_DialogueText.text = "";
foreach (char letter in sentence.ToCharArray())
{
NPC_DialogueText.text += letter;
yield return null;
}
}
}

Unity array confusion

hello i'm trying to make a dialogue box using an array but i seem to be having a bit of an issue. instead of showing the different strings that's in DialogHolder class, it keeps on showing the DialogueManager instead.
From my understanding, I wanted to make it that the DialogHolder holds that dialogue and i got the idea of making it something like this -->
[DialogHolder = DialogueManager]
but the only thing that is showing is the DailogueManager with the test strings i placed to see if the dialogue changes
DailogHolder
public string dialogue;
private DialogueManager sentence;
public string[] NPC_name;
[TextArea(3, 10)]
public string[] dialogueLines;
void Start()
{
}
public void TriggerDialogue()
{
FindObjectOfType<DialogueManager>().ShowDialogue(dialogueLines);
FindObjectOfType<DialogueManager>().ShowName(NPC_name);
}
DialogueManager
//holds the text GameObject
public Text NPC_nameText;
public Text NPC_DialogueText;
public string[] names;
[TextArea(3, 10)]
public string[] dialogueLines;
public int currentlines;
void Start () {
//lets the box types the char individual
StopAllCoroutines();
}
void Update()
{
StartDialog();
}
public void StartDialog()
{
if (currentlines >= dialogueLines.Length)
{
currentlines = 0;
EndDialogue();
return;
}
NPC_DialogueText.text = "";
StartCoroutine(TypeSentence());
}
public void ShowDialogue(string[] dialogueLines)
{
NPC_DialogueText.text = dialogueLines[currentlines];
}
public void ShowName(string[] NPC_name)
{
//selected a name
NPC_nameText.text = NPC_name[0];
//this part works for some reason since it's taken from the DialogHolder class
}
//pressed by a button
public void NextLine()
{
currentlines++;
StopAllCoroutines();
}
void EndDialogue()
{
Debug.Log("End of Conversation");
}
IEnumerator TypeSentence()
{
//types the characters for each sentence
foreach (char letter in dialogueLines[currentlines].ToCharArray())
{
NPC_DialogueText.text += letter;
yield return null;
}
}
if i remove the [size] of the array in the DailogHolder class, i get an error that says [Array index is out of range] but if i just remove the strings that was saved inside that array, it wouldn't matter anyway since it just keeps on using the array in the DialogueManager class.
Please help, it works if i'm using only a single string and not an array but i need to learn how to print multiple lines

Need help creating an Input Field & Scroll View [Unity3d-C#]

I've been trying to create an input field which upon editing activate the scroll View below and display relevant information to the subject(ex:username,address...), but on calling the input field event to activate the scroll view it won't accept the function which I have created. Thank for reading my terrible English and help whoever you're.
public InputField username;
public InputField password;
public List<string> usernamelist;
public Button enter;
public ScrollRect usernamedataload;
// Use this for initialization
void Start () {
string temp = "";
if (PlayerPrefs.GetString ("username") == null) {
username.text = temp;
} else if (PlayerPrefs.GetString ("password") == null) {
password.text = temp;
} else {
username.text = PlayerPrefs.GetString ("username");
password.text = PlayerPrefs.GetString ("password");
}
usernamedataload.gameObject.SetActive (false);
}
// Update is called once per frame
void Update () {
enter.onClick.AddListener (enterKeyDown);
username.onValueChanged.AddListener(selectUsernameInput);
username.onEndEdit.AddListener (endEditingUsernameInput);
}
void selectUsernameInput(){
usernamedataload.gameObject.SetActive (true);
usernamedataload.content.GetChild (usernamelist);
}
void endEditingUsernameInput(){
usernamedataload.gameObject.SetActive (false);
}
It's very hard to understand this question but I can spot big problems already. You are suppose to register to a UI event once. Right now, you are registering to three events every frame in the Update() function. Move those code to the Start() function.
calling the input field event to activate the scroll view it won't
accept the function which I have created
Wrap delegate around the function you are passing in it. For example, username.onValueChanged.AddListener(delegate { selectUsernameInput(); });
Transform.GetChild takes int as parameter but you are passing List to it with usernamedataload.content.GetChild(usernamelist);. I can't tell why you are trying to do that but you should pass an int into it like (1,2,3,4).
You can get started with the code below. It fixes all the problems mentioned above and will compile.
public InputField username;
public InputField password;
public List<string> usernamelist;
public Button enter;
public ScrollRect usernamedataload;
// Use this for initialization
void Start()
{
string temp = "";
if (PlayerPrefs.GetString("username") == null)
{
username.text = temp;
}
else if (PlayerPrefs.GetString("password") == null)
{
password.text = temp;
}
else
{
username.text = PlayerPrefs.GetString("username");
password.text = PlayerPrefs.GetString("password");
}
usernamedataload.gameObject.SetActive(false);
enter.onClick.AddListener(enterKeyDown);
username.onValueChanged.AddListener(delegate { selectUsernameInput(); });
username.onEndEdit.AddListener(delegate { endEditingUsernameInput(); });
}
// Update is called once per frame
void Update()
{
}
void selectUsernameInput()
{
usernamedataload.gameObject.SetActive(true);
usernamedataload.content.GetChild(0);
}
void endEditingUsernameInput()
{
usernamedataload.gameObject.SetActive(false);
}
void enterKeyDown()
{
}

Categories

Resources