Get value from other script file variable Unity C# - c#

I have a weird question. I want to get value from other script file, but actually it is quick easy. But this time I have an another case.
For example:
I have player.cs that save the data with datatype dictionary
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class player : MonoBehaviour {
public Dictionary <string, Dictionary <string, int> > product;
}
then I have margaretShop.cs that set the value of dictionary product
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Linq;
public class margaretShop : MonoBehaviour {
player Player;
// Use this for initialization
void Start () {
Player = GameObject.FindGameObjectWithTag ("player").GetComponent<player> ();
setValue("A", "id", "10");
setValue("A", "name", "A");
setValue("A", "qty", "4");
setValue("A", "price", "120");
}
// Update is called once per frame
void Update () {
}
void init() {
if (Player.product != null) {
return;
}
Player.product = new Dictionary<string, Dictionary <string, int> > ();
}
public int getValue(string nameproduct, string property) {
init ();
if (Player.product.ContainsKey (nameproduct) == false) {
return 0;
}
if (Player.product [nameproduct].ContainsKey (property) == false) {
return 0;
}
return Player.product [nameproduct] [property];
}
public void setValue(string nameproduct, string property, int value) {
init ();
if (Player.product.ContainsKey (nameproduct) == false) {
Player.product[nameproduct] = new Dictionary<string, int>();
}
Player.product [nameproduct] [property] = value; // This store to player.cs file product
}
public string[] getProductName() {
return Player.product.Keys.ToArray();
}
}
and then last I call it with another script file margaretSellScript.cs
using UnityEngine;
using System.Collections;
using System.Linq;
using UnityEngine.UI;
public class margaretSellScript : MonoBehaviour {
margaretShop mShop;
player Player;
// Use this for initialization
void Start () {
mShop = GameObject.FindGameObjectWithTag ("MargaretShop").GetComponent<margaretShop> ();
Player = GameObject.FindGameObjectWithTag ("player").GetComponent<player> ();
Debug.Log("QTY : " + mShop.getValue ("A", "qty"));
}
}
In this script: Debug.Log("QTY : " + mShop.getValue ("A", "qty")); why I can't get the value from player.cs product variable dictionary? The value must be "4" right?
The error is Object reference not set to an instance of an object
I have already call the gameobject like this at margaretSellScript.cs :
mShop = GameObject.FindGameObjectWithTag ("MargaretShop").GetComponent<margaretShop> ();
Player = GameObject.FindGameObjectWithTag ("player").GetComponent<player> ();
Any Idea?

But i see it is attacted. Just i am not set it active until i press
the button.
That's the problem. The component must be enabled in order for GetComponent<Script> () to find it. Enable it from the Editor as default. When game starts get the reference then disable it.
mShop = GameObject.FindGameObjectWithTag("MargaretShop").GetComponent<margaretShop>();
mShop.enabled = false; //disable it
If you have any code that runs in the Start() function of the margaretShop script, you can remove them and put them in a custom public function named initScript().
Now, when you press the Button, you can activate it with mShop.enabled = false;, then call the initScript() function to initialize your variables in the margaretShop script. That's it.

Related

How to make object appear when a certain torso is called using C# in Unity

This is the code I used for a tutorial
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Trial_Changer : MonoBehaviour
{
[Header("Sprite To Change")]
public SpriteRenderer bodyPart;
[Header("Sprites to Cycle Through")]
public List<Sprite> options = new List<Sprite>();
public static int currentTorsoOption = 0;
public void NextOption ()
{
currentTorsoOption++;
if (currentTorsoOption >= options.Count)
{ currentTorsoOption = 0; }
bodyPart.sprite = options[currentTorsoOption];
}
public void PreviousOption()
{
currentTorsoOption--;
if (currentTorsoOption <= 0)
{ currentTorsoOption = options.Count - 1; }
bodyPart.sprite = options[currentTorsoOption];
}
}
**This is the code I am using to try to say "if torso 2 is called, create object"
**
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpeechAppears : MonoBehaviour
{
public GameObject speechBubbleTOSpawn;
private int Torso = Trial_Changer.currentTorsoOption;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Torso == 2)
{
Instantiate(speechBubbleTOSpawn);
}
}
}
Except the torso just appears always.
What do I do to fix this?
I want an object to appear when torso 2 is on the screen but instead the object is just always present. What do I do ?
The culprit is this line :
private int Torso = Trial_Changer.currentTorsoOption;
Since you assign value Torso only once at the start of the game, its value always be the same.
Try this :
private int Torso => Trial_Changer.currentTorsoOption;
This change Torso from a field to a property, and when Torso is used, it will read the current value of Trial_Changer.currentTorsoOption.

GetKeyDown sends multiple outputs

specifically it sends as many outputs as there are objects with the code in them that allows them to be interacted with, even if I press E when not looking at anything. I wanted to make an inventory system, but this causes all objects that have this code to be interacted with. I included all the scripts that im using for this system if that can help. I genuinely don't know what I did wrong
the interactor code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using System;
public class Interactable : MonoBehaviour
{
public LayerMask interactableLayerMask;
//ITEM VARIABLE
public Item item;
//PICK UP RADIUS
public float radius = 4f;
public void Interact()
{
Debug.Log("Interacted with " + transform.name);
PickUp();
}
//PICK UP INTERACTION
void PickUp()
{
Debug.Log("Picking up " + item.name);
bool wasPickedUp = Inventory.instance.Add(item);
if (wasPickedUp)
Destroy(gameObject);
}
//INTERACTION
void Update()
{
if (Input.GetKeyDown(KeyCode.E))
{
Debug.Log("Added item -----------------------------------------");
RaycastHit hit;
if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hit, radius))
{
Interactable interactable = hit.collider.GetComponent<Interactable>();
if (interactable != null)
{
Interact();
}
} else
{
Debug.Log("Nothing");
}
}
}
}
the Inventory code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
#region Singleton
public static Inventory instance;
void Awake()
{
if (instance != null)
{
Debug.LogWarning("More than one instance of Inventory found!");
return;
}
instance = this;
}
#endregion
public delegate void OnItemChanged();
public OnItemChanged onItemChangedCallback;
public int space = 20;
public List<Item> items = new List<Item>();
public bool Add (Item item)
{
if (!item.isDefaultItem)
{
if (items.Count >= space)
{
Debug.Log("Note enough space in inventory");
return false;
}
else
{
items.Add(item);
if (onItemChangedCallback != null)
onItemChangedCallback.Invoke();
}
}
return true;
}
public void Remove(Item item)
{
items.Remove(item);
if (onItemChangedCallback != null)
onItemChangedCallback.Invoke();
}
}
Item code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New Item", menuName = "Inventory/Item")]
public class Item : ScriptableObject
{
new public string name = "New Item";
public Sprite icon = null;
public bool isDefaultItem = false;
}
To my understanding, your code goes into the Input.GetKeyDown(KeyCode.E) for every object in the scene, but it does not add it to the inventory.
That is because you use the Update function in the Interactable class, which are your objects. Instead, try moving the exact same block of code into your Inventory class. Make sure you make your Interact method public, so you can call it.

Why when adding a script to a selected gameobject through another script it's adding the script to each object in the list twice?

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class GenerateAutomaticGuid : Editor
{
[MenuItem("GameObject/Generate Guid", false, 11)]
private static void GenerateGuid()
{
foreach (GameObject o in Selection.objects)
{
o.AddComponent<GenerateGuid>();
o.GetComponent<GenerateGuid>().GenerateGuidNum();
o.tag = "My Unique ID";
}
}
}
For example I'm selecting two gameobjects in the hierarchy right click and GenerateGuid I use a break point and it's making a loop on each object in the list Selection.objects twice so each object in the list have the script GenerateGuid twice. And I want it to add the script to each object once only.
This is the GenerateGuid script :
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateGuid : MonoBehaviour, IStateQuery
{
public string uniqueGuidID;
public SaveLoad saveLoad;
public GameObject naviParent;
private Guid guidID;
private bool isNaviChildOfKid = false;
public void GenerateGuidNum()
{
guidID = Guid.NewGuid();
uniqueGuidID = guidID.ToString();
}
private State m_state = new State();
public Guid UniqueId => Guid.Parse("E0B03C9C-9680-4E02-B06B-E227831CB33F");
private class State
{
public bool naviInHand;
}
public string GetState()
{
return JsonUtility.ToJson(m_state);
}
public void SetState(string jsonString)
{
m_state = JsonUtility.FromJson<State>(jsonString);
if (m_state.naviInHand == true)
{
transform.GetComponent<InteractableItem>().distance = 0;
transform.parent = GameObject.Find("Navi Parent").transform;//rig_f_middle;
transform.localPosition = GameObject.Find("Navi Parent").transform.localPosition;
transform.localRotation = Quaternion.identity;
transform.localScale = new Vector3(0.001f, 0.001f, 0.001f);
}
}
private void Update()
{
if(transform.IsChildOf(naviParent.transform) == false && isNaviChildOfKid == false)
{
m_state.naviInHand = true;
saveLoad.Save();
isNaviChildOfKid = true;
}
}
}
A screenshot of all the places I'm calling the GenerateGuid :
Maybe you executing GenerateGuid twice or by amount of gameobjects?
Can you show all places where you executing GenerateGuid
You can add a null check to your foreach loop to see if your object already has a GenerateGuid component and skip the process if it does:
foreach (GameObject o in Selection.objects)
{
if(!o.GetComponent<GenerateGuid>()){
o.AddComponent<GenerateGuid>();
o.GetComponent<GenerateGuid>().GenerateGuidNum();
o.tag = "My Unique ID";
}
}
It won't prevent your function from being called multiple times but it can prevent duplicate GenerateGuid components.

Unity Quiz Game Score in C#

I am making a quiz game in the unity from the unity live session quiz game tutorials everything is working fine except somehow the score isn't working when i Click the button it should add 10 score to the Score. Here are the tutorials : https://unity3d.com/learn/tutorials/topics/scripting/intro-and-setup?playlist=17117 and the code for my Game Controller :
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
public class GameController : MonoBehaviour {
public Text questionDisplayText;
public Text scoreDisplayText;
public Text timeRemainingDisplayText;
public SimpleObjectPool answerButtonObjectPool;
public Transform answerButtonParent;
public GameObject questionDisplay;
public GameObject roundEndDisplay;
private DataController dataController;
private RoundData currentRoundData;
private QuestionData[] questionPool;
private bool isRoundActive;
private float timeRemaining;
private int questionIndex;
private int playerScore;
private List<GameObject> answerButtonGameObjects = new List<GameObject>();
// Use this for initialization
void Start ()
{
dataController = FindObjectOfType<DataController> ();
currentRoundData = dataController.GetCurrentRoundData ();
questionPool = currentRoundData.questions;
timeRemaining = currentRoundData.timeLimitInSeconds;
UpdateTimeRemainingDisplay();
playerScore = 0;
questionIndex = 0;
ShowQuestion ();
isRoundActive = true;
}
private void ShowQuestion()
{
RemoveAnswerButtons ();
QuestionData questionData = questionPool [questionIndex];
questionDisplayText.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);
}
}
public void AnswerButtonClicked(bool isCorrect)
{
if (isCorrect)
{
playerScore += currentRoundData.pointsAddedForCorrectAnswer;
scoreDisplayText.text = "Score: " + playerScore.ToString();
}
if (questionPool.Length > questionIndex + 1) {
questionIndex++;
ShowQuestion ();
} else
{
EndRound();
}
}
public void EndRound()
{
isRoundActive = false;
questionDisplay.SetActive (false);
roundEndDisplay.SetActive (true);
}
public void ReturnToMenu()
{
SceneManager.LoadScene ("MenuScreen");
}
private void UpdateTimeRemainingDisplay()
{
timeRemainingDisplayText.text = "Time: " + Mathf.Round (timeRemaining).ToString ();
}
// Update is called once per frame
void Update ()
{
if (isRoundActive)
{
timeRemaining -= Time.deltaTime;
UpdateTimeRemainingDisplay();
if (timeRemaining <= 0f)
{
EndRound();
}
}
}
}
and my answer Button Code:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class AnswerButton : MonoBehaviour {
public Text answerText;
private AnswerData answerData;
private GameController GameController;
// Use this for initialization
void Start ()
{
GameController = FindObjectOfType<GameController> ();
}
public void Setup(AnswerData data)
{
answerData = data;
answerText.text = answerData.answerText;
}
public void HandleClick()
{
GameController.AnswerButtonClicked (answerData.isCorrect);
}
}
and Answer Data :
using UnityEngine;
using System.Collections;
[System.Serializable]
public class AnswerData
{
public string answerText;
public bool isCorrect;
}
If everything is working fine (the whole code gets executed correctly, which I presume at this point), you probably did not set the data correctly. In your Game Controller, you have the line
playerScore += currentRoundData.pointsAddedForCorrectAnswer;
in your AnswerButtonClicked method which should add an amount you defined to the score if the answer is correct. Since I presume that your whole code is running fine (I can't see your in-engine setup, only the code here, which looks like the one in the tutorial), this is probably the first location where to look at the error. This value is probably set in the Unity Inspector or via another script, so you may want to go check in other files or the Editor.
The next thing to check is, if the buttons are correctly linked via their event handler. This can be checked by looking at the inspector. In the tutorial series this step is done in part Click to answer at the end of the video.

C# script(child object) not allowing me to access in another script (which is the parent object) unity

I can access the object from the script however I want to directly change values of the object in the script and this is not allowing me to. Here is my scrip for the main script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using RTS;
public class QuestionMenu : MonoBehaviour {
public struct Question{
public string questionText;
public string answer;
public string solution1;
public string solution2;
public string solution3;
}
//public void QuestionObject(string QuestionText, string answer, string solution1, string solution2, string solution3){
//Debug.Log ("lol");
//}
public Question QuestionObject = new Question();
Canvas canvas;
public UserInput Player;
public Text QuestionText;
public Text Button1;
// Use this for initialization
void Start () {
canvas = GetComponent<Canvas>();
canvas.enabled = false;
ResourceManager.QuestionMenuOpen = false;
//instruction = GetComponent<Text>();
//Debug.Log (QuestionText);
Button1.text = "Crazy";
QuestionText.text = "Yo Bro";
}
// Update is called once per frame
void Update () {
////Debug.Log (QuestionObject.questionText);
if(ResourceManager.QuestionMenuOpen == true){
//QuestionObject.questionText = "bloo";
Pause ();
//QuestionText.text = "Question 1) Differentiate 3x\u2074 + 2x.";
//Button1.text = "12x\u00B3 + 2";
}
}
public void Pause (){
canvas.enabled = true;
Player.enabled = false;
Time.timeScale = 0.0f;
Cursor.visible = true;
//QuestionObject = Questions.QuestionObject;
Debug.Log (QuestionObject.questionText);
QuestionText.text = QuestionObject.questionText;
//ResourceManager.QuestionMenuOpen = true;
}
void Resume (){
Cursor.visible = false;
canvas.enabled = false;
Player.enabled = true;
Time.timeScale = 1.0f;
ResourceManager.QuestionMenuOpen = false;
}
}
And here is the script for my script:
using UnityEngine;
using System.Collections;
public class QuestionScript : MonoBehaviour {
// Use this for initialization
void Start () {
QuestionMenu.QuestionObject.answer = "asdf";
}
// Update is called once per frame
void Update () {
}
}
Edit: I wish to access the Object QuestionObject from the scrip shown above here is a screen shot of the gameObject which has both scripts attached to it
I think you misunderstood the Inheritance concept. When you declare a class like you do here :
public class Questions : QuestionMenu {
it means Question class has the same functions and variables with QuestionMenu class (I assume they are all public). But it doesnt mean you can connect 2 GameObjects to each other like that. When you set Question script on Parent that is another object (I mean Question object). And when you set QuestionMenu script on the Child it is totaly different and new object. Also they have no connection with eachother. What you should do is :
using UnityEngine;
using System.Collections;
public class Questions {
public Questions dpoint; // u can set this on unity editor by just draging and dropping the parent object here.
void Start () {
//or you can get it from code I belive
dpoint = transform.parent.GetComponent<Question>();
QuestionObject.questionText = "asd";
}
// Update is called once per frame
void Update () {
base.QuestionObject.questionText = "asd2";
}
}
I hope that I didnt misunderstand your question..
USE public static Question QuestionObject = new Question();
then you can access and change its values in child class like this
Parentclass.QuestionObject.value

Categories