Problem with implementing a dialogue system in Unity - c#

I'm trying to make my own visual novel in Unity.
I made a text manager script to load the text files and to read them correctly and a text box script to load the text onto the text box. In my hierachy I made two objects, one for the text box script and the other for the dialogue manager. (DialogueParserObj)
My goal was it to put the text file into the text box, which is seen as the dialogue string variable in the TextBox script so you could see the actual text file in the dialogue box I have marked. But it remains empty, and I don't know why and I don't get any errors.
I would really appreciate your help or other suggestions to go about a well structured dialogue system!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DialogueBox : MonoBehaviour
{
TextManager parser;
public string dialogue;
int lineNum;
public GUIStyle customStyle;
void Start()
{
dialogue = "";
parser = GameObject.Find("DialogueParserObj").GetComponent<TextManager>();
lineNum = 0;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Return))
{
dialogue = parser.GetContent(lineNum);
lineNum++;
}
}
void OnGUI()
{
dialogue = GUI.TextField(new Rect(100, 400, 600, 200), dialogue, customStyle);
}
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
public class TextManager : MonoBehaviour
{
string readPath;
List<string> stringList = new List<string>();
List<DialogueLine> lines = new List<DialogueLine>();
struct DialogueLine
{
public string name;
public string content;
public int pose;
public DialogueLine(string n, string c, int p)
{
name = n;
content = c;
pose = p;
}
}
void Start()
{
readPath = Application.dataPath + "/text.txt";
ReadFile(readPath);
}
public string GetName(int lineNumber)
{
if (lineNumber < lines.Count)
{
return lines[lineNumber].name;
}
return "";
}
public string GetContent(int lineNumber)
{
if (lineNumber < lines.Count)
{
return lines[lineNumber].content;
}
return "";
}
public int GePose(int lineNumber)
{
if (lineNumber < lines.Count)
{
return lines[lineNumber].pose;
}
return 0;
}
void ReadFile(string filePath)
{
StreamReader r = new StreamReader(filePath);
while (!r.EndOfStream)
{
string line = r.ReadLine();
if (line != null)
{
string[] lineValues = line.Split('|');
DialogueLine lineEntry = new DialogueLine(lineValues[0], lineValues[1], int.Parse (lineValues [2]));
stringList.Add(line);
}
}
r.Close();
}

Related

Loading Json File with Button Unity

I have been working on a customization system that allows a player to customize their skin color and particle trail of their character. I have the system working and am now attempting to save the data through JsonUtility and then load it. I plan on saving the data with the play button then transitioning to a new scene and having it load at start() of the new scene. But, for testing I have been using a load button as it should still work...but it doesn't.
My current SaveSystem script is supposedly working since the DebugLog "Save file created" for saving files appears when the button is pressed. But, when pressing the load button nothing changes yet the DebugLog "Save file found and loaded" still appears. I am kinda lost as to where to go and how to load the data into the Customization script since I am still new to C# Json and serializing in general.
Here are my 3 scripts:
SaveSystem Script
using UnityEngine;
using System.IO;
public static class SaveSystem
using UnityEngine;
using System.IO;
public static class SaveSystem
{
public static string directory = "/saveData";
public static string fileName = "MyData.txt";
public static void SavePlayer(Customization CurrentCustomization)
{
string dir = Application.persistentDataPath + directory;
if(!Directory.Exists(dir))
Directory.CreateDirectory(dir);
Debug.Log("Save file created");
string json = JsonUtility.ToJson(CurrentCustomization);
File.WriteAllText(dir + fileName, json);
}
public static Customization LoadPlayer()
{
string fullPath = Application.persistentDataPath + directory + fileName;
Customization CurrentCustomization = new Customization();
if(File.Exists(fullPath))
{
string json = File.ReadAllText(fullPath);
CurrentCustomization = JsonUtility.FromJson<Customization>(json);
Debug.Log("Save file found and loaded");
}
else
{
Debug.Log("Save file does not exist");
}
return CurrentCustomization;
}
}
CharacterCustomizaiton Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class CharacterCustomization : MonoBehaviour
{
public List<Customization> Customizations;
public int currentCustomizationIndex;
public Customization CurrentCustomization {get; private set;}
[SerializeField] private TextMeshProUGUI bodyColorText;
[SerializeField] private TextMeshProUGUI trailText;
public void Save()
{
SaveSystem.SavePlayer(CurrentCustomization);
}
public void Load()
{
CurrentCustomization = SaveSystem.LoadPlayer();
}
void Awake()
{
foreach(var customization in Customizations)
{
customization.UpdateSubObjects();
customization.UpdateRenderers();
}
}
public void SelectBodyColor(bool isForward)
{
currentCustomizationIndex = 0;
CurrentCustomization = Customizations[currentCustomizationIndex];
if(isForward)
{
CurrentCustomization.NextMaterial();
}
else
{
CurrentCustomization.PreviousMaterial();
}
bodyColorText.text = CurrentCustomization.materialIndex.ToString();
}
public void SelectLTrail(bool isForward)
{
currentCustomizationIndex = 1;
CurrentCustomization = Customizations[currentCustomizationIndex];
if(isForward)
{
CurrentCustomization.NextSubObject();
}
else
{
CurrentCustomization.PreviousSubObject();
}
trailText.text = CurrentCustomization.subObjectIndex.ToString();
}
public void SelectRTrail(bool isForward)
{
currentCustomizationIndex = 2;
CurrentCustomization = Customizations[currentCustomizationIndex];
if(isForward)
{
CurrentCustomization.NextSubObject();
}
else
{
CurrentCustomization.PreviousSubObject();
}
trailText.text = CurrentCustomization.subObjectIndex.ToString();
}
}
Customization Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Customization
{
public string DisplayName;
public List<Renderer> Renderers;
public List<Material> Materials;
public List<GameObject> SubObjects;
public int materialIndex;
public int subObjectIndex;
public void NextMaterial()
{
if(materialIndex == Materials.Count - 1)
{
materialIndex = 0;
}
else
{
materialIndex++;
}
UpdateRenderers();
}
public void PreviousMaterial()
{
if(materialIndex == 0)
{
materialIndex = Materials.Count - 1;
}
else
{
materialIndex--;
}
UpdateRenderers();
}
public void NextSubObject()
{
if(subObjectIndex == SubObjects.Count - 1)
{
subObjectIndex = 0;
}
else
{
subObjectIndex++;
}
UpdateSubObjects();
}
public void PreviousSubObject()
{
if(subObjectIndex == 0)
{
subObjectIndex = SubObjects.Count - 1;
}
else
{
subObjectIndex--;
}
UpdateSubObjects();
}
public void UpdateSubObjects()
{
for(var i = 0; i < SubObjects.Count; i++)
if (SubObjects[i])
SubObjects[i].SetActive(i == subObjectIndex);
}
public void UpdateRenderers()
{
foreach (var renderer in Renderers)
if (renderer)
renderer.material = Materials[materialIndex];
}
}

How can I use name of a conversation as a trigger to start a conversation instead using index?

Inside the manager script I have a method that start a dialogue name : StartDialogue:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DialogueManager : MonoBehaviour
{
public Text dialogueText;
public Text nameText;
public float sentencesSwitchDuration;
public bool animateSentenceChars = false;
public GameObject canvas;
public static bool dialogueEnded = false;
public DialogueTrigger trigger;
private Queue<string> sentence;
// Use this for initialization
void Start()
{
sentence = new Queue<string>();
}
public void StartDialogue(Dialogue dialogue)
{
canvas.SetActive(true);
nameText.text = dialogue.name;
sentence.Clear();
foreach (string sentence in dialogue.sentences)
{
this.sentence.Enqueue(sentence);
}
DisplayNextSentence();
}
public void DisplayNextSentence()
{
if (this.sentence.Count == 0)
{
EndDialogue();
return;
}
string sentence = this.sentence.Dequeue();
dialogueText.text = sentence;
StopAllCoroutines();
StartCoroutine(DisplayNextSentenceWithDelay(sentence));
}
public IEnumerator DisplayNextSentenceWithDelay(string sentence)
{
if (animateSentenceChars)
{
dialogueText.text = "";
foreach (char letter in sentence.ToCharArray())
{
dialogueText.text += letter;
yield return null;
}
}
yield return new WaitForSeconds(sentencesSwitchDuration);
DisplayNextSentence();
}
private void EndDialogue()
{
dialogueEnded = true;
if (trigger.dialogueNum == trigger.conversations[trigger.dialogueIndex].Dialogues.Count)
canvas.SetActive(false);
Debug.Log("End of conversation.");
}
}
Then in the trigger script I have a method name TriggerDialogue that get index number. For example index 0 it will start the dialoue/s of the first conversation. But in fact it's just starting the first dialogue from the dialogues List.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
[ExecuteInEditMode]
public class DialogueTrigger : MonoBehaviour
{
public List<Conversation> conversations = new List<Conversation>();
//public List<Dialogue> dialogue = new List<Dialogue>();
[HideInInspector]
public int dialogueNum = 0;
[HideInInspector]
public int dialogueIndex = 0;
private bool triggered = false;
private List<Dialogue> oldDialogue;
private bool activateButton = false;
public void TriggerDialogue(int dialogueIndex)
{
this.dialogueIndex = dialogueIndex;
if (conversations.Count > 0 &&
conversations[dialogueIndex].Dialogues.Count > 0)
{
if (triggered == false)
{
if (FindObjectOfType<DialogueManager>() != null)
{
FindObjectOfType<DialogueManager>().StartDialogue(conversations[dialogueIndex].Dialogues[dialogueNum]);
dialogueNum += 1;
}
triggered = true;
}
}
}
private void Update()
{
ButtonActivation();
if (DialogueManager.dialogueEnded == true)
{
if (dialogueNum == conversations[dialogueIndex].Dialogues.Count)
{
return;
}
else
{
FindObjectOfType<DialogueManager>().StartDialogue(conversations[dialogueIndex].Dialogues[dialogueNum]);
DialogueManager.dialogueEnded = false;
dialogueNum += 1;
}
}
}
public bool ActivateButton()
{
return activateButton;
}
private void ButtonActivation()
{
if (ConversationsChecks() == true)
{
foreach (string sentence in conversations[dialogueIndex].Dialogues[dialogueNum].sentences)
{
if (sentence != "")
{
activateButton = true;
}
else
{
activateButton = false;
}
}
}
else
{
activateButton = false;
}
}
public void SaveConversations()
{
string jsonTransform = JsonHelper.ToJson(conversations.ToArray(), true);
File.WriteAllText(#"d:\json.txt", jsonTransform);
}
public void LoadConversations()
{
string jsonTransform = File.ReadAllText(#"d:\json.txt");
conversations.Clear();
conversations.AddRange(JsonHelper.FromJson<Conversation>(jsonTransform));
}
private bool ConversationsChecks()
{
bool IsConversationsReady = false;
if (conversations.Count > 0 &&
conversations[dialogueIndex].Dialogues.Count > 0 &&
conversations[dialogueIndex].Dialogues[dialogueNum].sentences.Count > 0 &&
conversations[dialogueIndex].Dialogues[dialogueNum].name != "" &&
conversations[dialogueIndex].name != "")
{
IsConversationsReady = true;
}
else
{
IsConversationsReady = false;
}
return IsConversationsReady;
}
}
Then I have more two small classes :
Dialogue:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Dialogue
{
[Tooltip("Dialogue Name")]
public string name;
[TextArea(1, 10)]
public List<string> sentences = new List<string>();
}
And Conversation :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Conversation
{
[Tooltip("Conversation Name")]
public string name;
public List<Dialogue> Dialogues = new List<Dialogue>();
}
So now when I want to start a dialogue I'm calling the TriggerDialogue method like this example :
dialogueTrigger.TriggerDialogue(0);
Instead I want to do something like that :
dialogueTrigger.StartConversation("Opening Scene");
Or
dialogueTrigger.StartConversation("The last conversation");
And this is example screenshot of how the Inspector of the conversations and dialogues looks like :
Conversations
So if for example I want to start the first conversation somewhere in my game I will do :
dialogueTrigger.StartConversation("The Opening");
And it will start the dialogue/s inside the "The Opening" conversation.
Using the index is working fine but I want to use to start a conversation by the conversation name it will be easier.
Given that you are using a List<T>, if you move away from using the index to get the item you want, you will need to enumerate the collection each time to find that same item. The best you can do here, is change the data structure to a Dictionary, so you can search for it by the Key and avoid the performance hit. In order to also avoid having to remember what names you put to the conversations, perhaps it would be best to use an Enum.
So, create the enum:
public enum SceneConversations
{
OpeningScene = 1,
// ...
}
and start using
public class DialogueTrigger : MonoBehaviour
{
public Dictionary<SceneConversations, Conversation> conversations = new Dictionary<SceneConversations, Conversation>();
you can then use
public void StartConversation(SceneConversations conversationWanted) {}
and call it with
dialogueTrigger.StartConversation(SceneConversations.OpeningScene);
If I remember correctly, this has the added advantage that Unity will show you a drop-down for the possible values of SceneConversations, so that's also easier to handle.

Dynamic Scramble Game using Unity C# and PHP (Mysql as database)

I have here codes that scramble declared words based on this video.Below are the codes that depends on array of words I declared on Unity Editor. The problem is I want it to be dynamic, like it will fetch words into database. I wrote a code in php that retrieves data from db and a code on csharp that reads the php via WWW method. I can't merge this two process- scramble words and getting words from db, Please help me guys, Thank you.
this is my Unity setup for scramble word. as you can see I attached WordScrambe.cs to Core Gameobject and declared 2 words-"YES" and "YOURS".
CharObject.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CharObject : MonoBehaviour {
public char character;
public Text text;
public Image image;
public RectTransform rectTransform;
public int index;
[Header("Appearance")]
public Color normalColor;
public Color selectedColor;
bool isSelected= false;
public CharObject Init(char c)
{
character = c;
text.text = c.ToString ();
gameObject.SetActive (true);
return this;
}
public void Select()
{
isSelected = !isSelected;
image.color = isSelected ? selectedColor : normalColor;
if (isSelected) {
WordScramble.main.Select (this);
} else {
WordScramble.main.UnSelect();
}
}
}
WordScramble.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Word
{
public string word;
[Header("leave empty if you want randomized")]
public string desiredRandom;
public string GetString()
{
if (!string.IsNullOrEmpty (desiredRandom))
{
return desiredRandom;
}
string result = word;
while (result==word)
{
result = "";
List<char> characters = new List<char> (word.ToCharArray ());
while (characters.Count > 0)
{
int indexChar = Random.Range (0, characters.Count - 1);
//Debug.Log(characters[indexChar]);
result += characters [indexChar];
Debug.Log(word);
characters.RemoveAt (indexChar);
}
}
return result;
}// end of Getstring Method
}
public class WordScramble : MonoBehaviour {
public Word[] words;
[Header("UI REFERENCE")]
public CharObject prefab;
public Transform container;
public float space;
public float lerpSpeed=5;
List<CharObject> charobjects = new List<CharObject>();
CharObject firstSelected;
public int currentWord;
public static WordScramble main;
void Awake()
{
main = this;
}
// Use this for initialization
void Start () {
ShowScramble (currentWord);
}
// Update is called once per frame
void Update ()
{
RepositionObject ();
}
void RepositionObject()
{
if (charobjects.Count==0) {
return;
}
float center = (charobjects.Count -1) / 2;
for (int i = 0; i < charobjects.Count; i++)
{
charobjects[i].rectTransform.anchoredPosition= Vector2.Lerp(charobjects[i].rectTransform.anchoredPosition, new Vector2((i- center)* space, 0), lerpSpeed* Time.deltaTime) ;
charobjects [i].index = i;
}
}
//show a random word to the screen
public void ShowScramble()
{
ShowScramble (Random.Range (0, words.Length - 1));
}
//<summary>Show word from collection with desired index
public void ShowScramble(int index)
{
charobjects.Clear ();
foreach (Transform child in container) {
Destroy (child.gameObject);
}
//Words Finished
if (index > words.Length - 1) {
Debug.LogError ("index out of range, please enter range betwen 0-" + (words.Length - 1).ToString ());
return;
}
char[] chars = words [index].GetString ().ToCharArray ();
foreach (char c in chars)
{
CharObject clone = Instantiate (prefab.gameObject).GetComponent<CharObject> ();
clone.transform.SetParent (container);
charobjects.Add (clone.Init (c));
}
currentWord = index;
}
public void Swap(int indexA, int indexB)
{
CharObject tmpA = charobjects [indexA];
charobjects[indexA] = charobjects [indexB];
charobjects[indexB] = tmpA;
charobjects [indexA].transform.SetAsLastSibling ();
charobjects [indexB].transform.SetAsLastSibling ();
CheckWord ();
}
public void Select(CharObject charObject)
{
if (firstSelected)
{
Swap (firstSelected.index, charObject.index);
//Unselect
firstSelected.Select();
charObject.Select();
} else {
firstSelected = charObject;
}
}
public void UnSelect()
{
firstSelected = null;
}
public void CheckWord()
{
StartCoroutine (CoCheckWord());
}
IEnumerator CoCheckWord()
{
yield return new WaitForSeconds (0.5f);
string word = "";
foreach (CharObject charObject in charobjects)
{
word += charObject.character;
}
if (word == words [currentWord].word) {
currentWord++;
ShowScramble (currentWord);
}
}
}
Below are the codes for retrieving data from db using PHP and passing data to unity.
read.php
<?php
include '../../connection.php';
$query=mysqli_query($conn, "SELECT * FROM words");
while($fetch=mysqli_fetch_array($query)){
echo $get=$fetch["words"];
echo ",";
}
?>
fetch.cs-I attached this to Main Camera on Unity Editor for the mean time.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class fetch : MonoBehaviour {
public string[] dbWords;
IEnumerator Start(){
WWW words=new WWW("http://localhost/bootstrap/android/v2/read.php");
yield return words;
string wordsDataString=words.text;
print(wordsDataString);
dbWords=wordsDataString.Split(',');
}
}
In short I want to make a scramble game in unity that the words of it depends on the database . I have the process of word scramble(but static) and retrieving data from database but not connected to scramble game I made, means my project is not yet dynamic, I'm sorry for uncleared explanations.
Thank you and more power! :)
Welcome to SO!
It is not entirely clear where your problem lies, however I think you mean to say that you are not receiving a result from your database?
Let's start by moving your Database logic to a separate class for good practice.
Also the Start Method of a MonoBehaviour is of returntype void, and not an IENumerator. You need an IENumerator, which you can call with StartCoroutine.
Create a seperate class like below
public static class NetworkManager
{
public static IEnumerator Fetch(Action<string[]> callback)
{
WWW words=new WWW("http://localhost/bootstrap/android/v2/read.php");
yield return words;
string wordsDataString=words.text;
print(wordsDataString);
var result = wordsDataString.Split(',');
callback?.Invoke(result);
}
}
I cannot test your code that you had in your Fetch method because you are using it locally, but let's assume it works for now.
Notice the callback as a parameter.
This allows you to register an action that will fire once your database call is completed.
It is invoked in the last line of the method.
You can then call the method like this:
public class SomeClass : MonoBehaviour
{
StartCoroutine(NetworkManager.Fetch( (words) =>
{
// Do something with the words!
SomeMethod(words);
});
}
As soon as the Coroutine finishes, any code between the brackets is executed. In this case "SomeMethod" accepting words as a parameter will fire.
I hope this clarifies and answers your question!

How to call array element that has bool value true unity C#

I have four buttons using the same prefab and holding 4 text elements from an array out of which only one is assigned bool value to true. I am trying to access that true element when any of false element is clicked. i want to highlight true element when the false element is clicked. can anyone please help me to achieve this functionality?
using simpleobjectpool
taking reference from unity quiz game tutorial
Thanks
Answer Button Script
public class AnswerButton : MonoBehaviour
{
public Text answerText;
private AnswerData answerData;
private GameController gameController;
private bool isCorrect;
void Start()
{
gameController = FindObjectOfType<GameController>();
}
public void Setup(AnswerData data)
{
answerData = data;
answerText.text = answerData.answerText;
}
public void HandleClick()
{
gameController.AnswerButtonClicked(answerData.isCorrect);
{
if (answerData.isCorrect)
{
}
if (!answerData.isCorrect)
{
}
}
Answer Data Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class AnswerData
{
public string answerText;
public bool isCorrect;
}
QuestionData Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class QuestionData
{
public string questionText;
public AnswerData[] answers;
}
Game Controller Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System;
public class GameController : MonoBehaviour
{
public Text questionText;
public Text scoreDisplayText;
public SimpleObjectPool answerButtonObjectPool;
public Transform answerButtonParent;
public GameObject questionPanel;
public GameObject roundOverPanel;
public GameObject levelsPanel;
private DataController dataController;
private RoundData currentRoundData;
private bool isRoundActive;
private float timeBeetweenQuestions = 3.0f;
private List<GameObject> answerButtonGameObjects = new List<GameObject>();
private QuestionData[] questionPool;
private int questionIndex;
private int qNumber = 0;
private List<int> questionIndexesChosen = new List<int>();
public int playerScore = 0;
public int totalQuestions;
private static int pointAddedForCorrectAnswer;
public AudioSource answerButtonClicked;
public AudioSource wrongAnswerClicked;
void Start ()
{
dataController = FindObjectOfType<DataController>();
currentRoundData = dataController.GetCurrentRoundData();
questionPool = currentRoundData.questions;
playerScore = 0;
questionIndex = 0;
scoreDisplayText.text = "Score: " + playerScore.ToString();
isRoundActive = true;
ShowQuestion();
}
private void ShowQuestion()
{
RemoveAnswerButtons();
QuestionData questionData = questionPool[questionIndex];
questionText.text = questionData.questionText;
for (int i = 0; i < questionData.answers.Length; i++)
{
GameObject answerButtonGameObject =
answerButtonObjectPool.GetObject();
answerButtonGameObjects.Add(answerButtonGameObject);
answerButtonGameObject.transform.SetParent(answerButtonParent);
AnswerButton answerButton =
answerButtonGameObject.GetComponent<AnswerButton>();
AnswerButton.Setup(questionData.answers[i]);
}
}
private void RemoveAnswerButtons()
{
while (answerButtonGameObjects.Count > 0)
{
answerButtonObjectPool.ReturnObject(answerButtonGameObjects[0]);
answerButtonGameObjects.RemoveAt(0);
}
}
IEnumerator TransitionToNextQuestion()
{
yield return new WaitForSeconds(timeBeetweenQuestions);
ShowQuestion();
}
IEnumerator WaitForFewSeconds()
{
yield return new WaitForSeconds(timeBeetweenQuestions);
EndRound();
}
IEnumerator ReturnCorrectButtonColor()
{
Debug.Log("im correct");
GetComponent<Button>().image.color = Color.green;
yield return new WaitForSeconds(seconds: 2.9f);
GetComponent<Button>().image.color = Color.white;
}
IEnumerator ReturnWrongButtonColor()
{
Debug.Log("im wrong");
GetComponent<Button>().image.color = Color.red;
yield return new WaitForSeconds(seconds: 2.9f);
GetComponent<Button>().image.color = Color.white;
}
public void AnswerButtonClicked (bool isCorrect)
{
if (isCorrect)
{
playerScore += currentRoundData.pointAddedForCorrectAnswer;
scoreDisplayText.text = "Score: " + playerScore.ToString();
//play coorect answer sound
answerButtonClicked.Play();
StartCoroutine(ReturnCorrectButtonColor());
}
if (!isCorrect)
{
//play wrong answer sound
answerButtonClicked = wrongAnswerClicked;
answerButtonClicked.Play();
StartCoroutine(ReturnWrongButtonColor());
// buttons = GameObject.FindGameObjectsWithTag("Answer");
// {
// foreach (GameObject button in buttons)
// {
// if (button.GetComponent<AnswerButton>
//().answerData.isCorrect)
// {
// button.GetComponent<AnswerButton>
// ().StartCoroutine(ReturnCorrectButtonColor());
// }
// }
//}
}
if (qNumber < questionPool.Length - 1) /
{
qNumber++;
StartCoroutine(TransitionToNextQuestion());
}
else
{
StartCoroutine(WaitForFewSeconds());
}
}
public void EndRound()
{
isRoundActive = false;
questionPanel.SetActive(false);
roundOverPanel.SetActive(true);
}
//on button click return to main menu
public void ReturnToMenu ()
{
SceneManager.LoadScene("MenuScreen");
}
}
In order to highlight both Wrong (the clicked one) and the Right buttons you need to have access to both buttons. This means that you can't do highlighting from HandleClick method of your Answer Button Script, as it only has access to itself, e.g. to the Wrong button.
The good thing is that this method notifies GameController that the button has been clicked. GameController knows about all the buttons, so it can easily highlight both buttons.
So, instead of launching your highlight subroutines from Answer Button's HandleClick, you should do this from GameController's AnswerButtonClicked: identify both the Right button and the clicked button there and launch appropriate subroutines for them.
Update:
For instance, your ReturnCorrectButtonColor would look like:
IEnumerator ReturnCorrectButtonColor( GameObject button )
{
Debug.Log("im correct");
button.GetComponent<Button>().image.color = Color.green;
yield return new WaitForSeconds(seconds: 2.9f);
button.GetComponent<Button>().image.color = Color.white;
}
so in AnswerButtonClicked you identify which button to highlight as a correct answer button and pass it as a paramter to this method:
StartCoroutine(ReturnCorrectButtonColor(correctButton));

Scriptable object doesn't work on build

I'm hoping this might be something simple I'm missing.
I have a ScriptableObject script that looks like this:
using UnityEngine;
using System.Collections;
[CreateAssetMenu]
public class Item: ScriptableObject
{
public string iname;
public int iindex;
public Sprite sprite;
public GameObject itemObject;
public int value;
public string description;
public itemType itemtype;
public enum itemType
{
Consumable,
Equippable,
}
}
This works great in the editor, but if I publish to Android or Windows any script that references the ScriptableObject, it does not work. What am I missing?
For example the following block of code does not seem to execute at all:
for (int i = 0; i < 3; i++)
{
int lootnum = Random.Range(0, 4);
slot1 = itemdb[lootnum];
tlist[i] = itemdb[lootnum];
slotlist[i].transform.GetChild(0).GetComponent<Image>().sprite = itemdb[lootnum].sprite;
slotlist[i].transform.GetChild(0).GetComponent<Image>().enabled = true;
}
Those lists in the code are of the type Item defined in the above script. I'm not sure how to debug this as I get no errors or warnings in the editor.
Here is the script which populates the inventory. There's a bit of junk in there but it definitley works fine pressing play in the editor. Just not on build.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
public class Inventory : MonoBehaviour {
public int invSize;
public Item slot1;
public Item tslot1;
public Item tslot2;
public Item tslot3;
public GameObject t1;
public GameObject t2;
public GameObject t3;
public Sprite itemsprite;
public List<Item> itemdb = new List<Item>();
public List<Item> items = new List<Item>();
public List<Item> tlist = new List<Item>();
public Text stext;
public Text description;
public Item selectItem;
public GameObject selectSlot;
public Object test2;
public List<GameObject> slotlist = new List<GameObject>();
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
public void addItem(Item itemToAdd)
{
//items.Add(itemdb[0]);
for (int i = 0; i < 5; i++)
{
if (items[i] == null)
{
items[i] = itemToAdd;
itemsprite = itemToAdd.sprite;
return;
}
}
}
public void GenTreasure()
{
for (int i = 0; i < 3; i++)
{
int lootnum = Random.Range(0, 4);
slot1 = itemdb[lootnum];
tlist[i] = itemdb[lootnum];
slotlist[i].transform.GetChild(0).GetComponent<Image>().sprite = itemdb[lootnum].sprite;
slotlist[i].transform.GetChild(0).GetComponent<Image>().enabled = true;
}
}
public void Uptext(int indexx)
{
stext.text = tlist[indexx].iname;
selectItem = tlist[indexx];
selectSlot = slotlist[indexx];
description.text = selectItem.description;
}
public void Take(int index)
{
//items.Add(selectItem);
for (int i = 0; i < invSize; i++)
{
if (items[i] == null)
{
items[i] = selectItem;
// itemsprite = itemToAdd.sprite;
selectItem = null;
// tlist[i] = null;
// slotlist[i].transform.GetChild(0).GetComponent<Image>().sprite = null;
selectSlot.transform.GetChild(0).GetComponent<Image>().enabled = false;
return;
}
}
}
}
If the script is not in the scene, how does it get loaded? Is it using an asset bundle? If that is the case, then it's possible that the class is being stripped from the build. You can include the class in your link.xml to make sure it's included. Another option is to simply reference the script in an included scene anywhere.

Categories

Resources