input of inputfield in unity becomes null when executed for pun2 - c#

basically, I am trying to display input of inputfield on the instantiated photon object using photon.rpc . However, input of inputfield does not even write anything on the console. Here is my solution
// ----------------------------------------------------------------------------
// <copyright file="CharacterInstantiation.cs" company="Exit Games GmbH">
// Photon Voice Demo for PUN- Copyright (C) 2016 Exit Games GmbH
// </copyright>
// <summary>
// Class that handles character instantiation when the actor is joined.
// It adds multiple prefabs support to OnJoinedInstantiate.
// </summary>
// <author>developer#photonengine.com</author>
// ----------------------------------------------------------------------------
namespace ExitGames.Demos.DemoPunVoice
{
using UnityEngine;
public class CharacterInstantiation : OnJoinedInstantiate
{
TextMesh output;
PhotonView photonView;
int i = 0;
public delegate void OnCharacterInstantiated(GameObject character);
public static event OnCharacterInstantiated CharacterInstantiated;
public new void OnJoinedRoom()
{
if (this.PrefabsToInstantiate != null)
{
GameObject o = PrefabsToInstantiate[(PhotonNetwork.player.ID - 1) % 4];
Debug.Log("Instantiating: " + o.name);
Vector3 spawnPos = Vector3.zero;
if (this.SpawnPosition != null)
{
spawnPos = this.SpawnPosition.position;
}
Vector3 random = Random.insideUnitSphere;
random = this.PositionOffset * random.normalized;
spawnPos += random;
spawnPos.y = 0;
Camera.main.transform.position += spawnPos;
o = PhotonNetwork.Instantiate(o.name, spawnPos, Quaternion.identity, 0);
if (CharacterInstantiated != null)
{
CharacterInstantiated(o);
}
photonView = o.GetPhotonView();
}
}
public void ReadStr(string s)
{
Debug.Log(s);
Debug.Log("readStr" + s);
photonView.RPC("ReadStringInput", PhotonTargets.All, s);
}
}
}
and i have a script under each prefab to be instantiated
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
public class ReadInput : MonoBehaviour
{
private string input;
TextMesh output;
[PunRPC]
public void ReadStringInput(string s)
{
Debug.Log(s);
output = GetComponentInChildren<TextMesh>();
output.text = s;
}
}
There is no other error message and seems to properly call targeted function, but one problem is string input of the inputfield becomes null value, and it displays "" on the console on both functions. I correctly assigned ReadStr on "on End Edit" of inputfield, but it is very frustration that whatever input i put, it becomes a null value. I'd greatly appreciate if anyone helps me with this matter.

Related

Recycling a Button for individual object - Unity3D

I am a beginner in Unity and I am currently making a simple game. I have a problem where the button should reappear on the object I am getting contact with. It only shows on the first object that I put the script on.
What I wanted to do is to have a recyclable button that will appear whenever I have contact with objects like the "view" button in most of the games. What keeps happening in my project is that the collision is triggered but the position of the object is in the first object where I put the script to set it active and set the position. I put it in another object because I want the button to show in that object but it keeps appearing in the first object.
This is the script I used:
using UnityEngine;
using UnityEngine.UI;
public class InteractNPC : MonoBehaviour
{
//public Button UI;
[SerializeField] GameObject uiUse, nameBtn, dialogBox;
[SerializeField] TextAsset characterData;
// [SerializeField] UnityEngine.UI.Text dialogMessage;
private Transform head;
private Vector3 offset = new Vector3(0, 1.0f, 0);
// Start is called before the first frame update
void Start()
{
//uiUse = Instantiate(UI, FindObjectOfType<Canvas>().transform).GetComponent<Button>();
uiUse.gameObject.SetActive(true);
head = this.transform.GetChild(0);
uiUse.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
nameBtn.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
nameBtn.GetComponent<Button>().onClick.AddListener(onNameClick);
}
// Update is called once per frame
void Update()
{
uiUse.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
nameBtn.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
}
private void OnTriggerEnter(Collider collisionInfo)
{
if (collisionInfo.CompareTag("Player"))
{
//Character characterJson = JsonUtility.FromJson<Character>(characterData.text);
nameBtn.gameObject.SetActive(true);
// Text lbl = nameBtn.gameObject.GetComponentInChildren(typeof(Text), true) as Text;
// lbl.text = "BOBO";
// nameBtn.GetComponent<Button>().GetComponentInChildren<Text>().text = characterJson.name;
}
}
private void OnTriggerExit(Collider collisionInfo)
{
if (collisionInfo.CompareTag("Player"))
{
nameBtn.gameObject.SetActive(false);
}
}
// DIALOGUE SYSTEM
public void onNameClick()
{
Text dialogMessage, dialogName;
if (dialogBox.gameObject.activeInHierarchy)
{
dialogName = GameObject.Find("Canvas/DialogBox/DialogueName").GetComponent<Text>();
dialogMessage = GameObject.Find("Canvas/DialogBox/Dialogue").GetComponent<Text>();
if (dialogMessage != null && dialogName != null)
{
loadCharacterData(dialogMessage, dialogName);
Debug.Log("not null dialog message");
}
else
{
Debug.Log("null dialog message");
}
}
}
public void loadCharacterData(Text dialogMessage, Text dialogName)
{
Character characterJson = JsonUtility.FromJson<Character>(characterData.text);
dialogName.text = characterJson.name;
dialogMessage.text = characterJson.dialogs[0].choices[1];
}
}
Well your issue is that each and every instnce of your scrip will all the time overwrite
void Update()
{
uiUse.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
nameBtn.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
}
every frame.
What you want is set it only once in
[SerializeField] private Button nameBtn;
pivate Character character;
private void Start()
{
...
// do this only once!
character = JsonUtility.FromJson<Character>(characterData.text);
}
private void OnTriggerEnter(Collider collisionInfo)
{
if (collisionInfo.CompareTag("Player"))
{
nameBtn.gameObject.SetActive(true);
var lbl = nameBtn.gameObject.GetComponentInChildren<Text>(true);
lbl.text = characterJson.name;
var position = Camera.main.WorldToScreenPoint(head.position + offset);
uiUse.transform.position = position;
nameBtn.transform.position = position;
}
}
Further you will have another issue: Each and every instance of your script attaches a callback
nameBtn.GetComponent<Button>().onClick.AddListener(onNameClick);
that is not good! Now whenever you click the button once, the allback is fired for each and every instance of your script.
You would rather do this only if the click was actually invoked for the current object.
For this you could attach the listener only add-hoc when needed like e.g.
private void OnTriggerEnter(Collider collisionInfo)
{
if (collisionInfo.CompareTag("Player"))
{
...
nameBtn.onClick.RemoveListener(onNameClick);
nameBtn.onClick.AddListener(onNameClick);
}
}
private void OnTriggerExit(Collider other)
{
if (collisionInfo.CompareTag("Player"))
{
nameBtn.onClick.RemoveListener(onNameClick);
nameBtn.gameObject.SetActive(false);
}
}
ok we didn't know before your objects move
so well you will need to go back to what you had before and update the position continuously, BUT only while you are the current active object so e.g.
private static InteractNPC buttonOwner;
private Camera mainCamera;
void Update()
{
if(buttonOwner != this) return;
if(!mainCamera) mainCamera = Camera.main;
var position = mainCamera.WorldToScreenPoint(head.position + offset);
uiUse.transform.position = position;
nameBtn.transform.position = position;
}
private void OnTriggerEnter(Collider collisionInfo)
{
if (collisionInfo.CompareTag("Player") && !buttonOwner)
{
...
buttonOwner = this;
}
}
private void OnTriggerExit(Collider other)
{
if (collisionInfo.CompareTag("Player") && buttonOwner == this)
{
nameBtn.onClick.RemoveListener(onNameClick);
nameBtn.gameObject.SetActive(false);
buttonOwner = null;
}
}
As far as I see you never create a new Button, I guess that Unity may think, you want the same Button on all NPCs.
Maybe try to call the constructor for a new Button in the Start Method and see if it then generates a new Button per NPC.

How can I successfully store and load data from a game character?

I was wrote a script that combines whale characters to create a new character. However, it is difficult to save and load data from a list of names, levels and locations of the newly created characters.
Whale data does not seem to be stored and loaded when the game is played.
I'd really thanks it if you could tell me where's wrong.
using system;
using System.Collections;
using System.Collections.General;
using system.IO;
using LitJson;
using UnityEngine;
using Random = UnityEngine.Random;
[System.Serializable]
Public class WhaleData
{
Public in dataLevel{get; set;// whale level
public Vector3 dataMousePosition{get; set;//the whale location
public string dataName{get; set;} //whale name
}
Public class Whale: MonoBehaviour
{
public int level;
Private pool isDrag;
Public GameObject NextPrepab;
Private Vector3 mousePosition;
Public WhaleData whaleData;
Private List[WhaleData] WhaleDatas = new List[WhaleData]();
private pool IsSave; //bool value to check for stored data
void start()
{
IsSave = PlayerPrefs.HasKey ("0_name"); //saved_level Check if a key value named //saved_level exists
//initialize all data values if no save data exists
If (!IsSave)
{
Debug.Log ("No data stored).");
PlayerPrefs.DeleteAll();
}
//recall value if save data exists
else
{
Debug.Log ("Stored Data").");
LoadData();
}
}
Private void Update ()
{
SaveData();
LoadData();
}
private void onMouseDown()
{
isDrag = true;
}
private void OnMouseDrag()
{
if (isDrag)
{
mousePosition.x = Input.mousePosition.x;
mousePosition.y = input.mousePositionY;
mousePosition.z = 10;
//change the mouse coordinates to the screen to world and set the position of this object
gameObject.transform.position = Camera.main.ScreenToWorldPoint(mousePosition);
// store the location of the whale in the whalData.dataMousePosition= gameObject.transform.position; //
}
}
private void onMouseUp()
{
//OverlapSphere : Return from the specified location to the collider array in contact within range
var colliders = Physics.OverlapSphere (transform.position, 0.1f);
foreach (var col in colliders) // arrangement of surrounding contacts
{
If (name!= col. gameObject.name) //if the name is different, go
{
If (level==col.gameObject.GetComponent[Whale>().level) //If the level of contact with the level stored in me is the same,
{
whatData.dataLevel = col.gameObject.GetComponent[Whale>().level; // store the level of the whale in the whalData class
var newWhale = Instantiate(NextPrepab, transform.position, quaternion.identity);
newWhale.name = Random.Range (0f, 200f).ToString(); //name is random.
dateData.dataName = name;// store the name of the whale in the whalData class
SaveData();
print(col.gameObject.name);
print(gameObject.name);
whatDatas.Add(whaleData);
Destroy (col.gameObject);
Destroy (gameObject);
// delete if there is any whale information with the same name as Whale's name that will disappear from the dateDatas list (use a simple calculation expression of the unknown method)
if (whaleDatas.Find(whaleData=>whaleData.dataName=colgameObject.GetComponent[Whale>(.name).dataName==colgameObject.GetComponent[Whale>(.name)
{
whaleDatasRemove (col.gameObject.GetComponent[Whale>(whaleData));
Destroy (col.gameObject);
Destroy (gameObject);
}
else
{
break;
}
break;
}
}
}
isDrag = false;
}
Public static void setVector3 (string key, Vector3 value)
{
PlayerPrefs.SetFloat (key + "X", value.x);
PlayerPrefs.SetFloat (key + "Y", value.y);
PlayerPrefs.SetFloat (key + "Z", value.z);
}
Public static Vector3 GetVector3 (string key)
{
Vector3 v3 = Vector3.zero;
v3.x = PlayerPrefs.GetFloat (key + "X");
v3.y = PlayerPrefs.GetFloat (key + "Y");
v3.z = PlayerPrefs.GetFloat (key + "Z");
return v3;
}
private void saveData()
{
for (int i=0; i <whaleDatas.Count; i++)
{
PlayerPrefs.SetString(i+"_name",whaleDatas[i‐dataName));
PlayerPrefs.SetInt(i+"_level",whaleDatas[i‐dataLevel));
Vector3 value = whatDatas[i].dataMousePosition;
string key = i + "_position";
SetVector3 (key,value);
PlayerPrefs.Save();
Debug.Log ("Saved");
}
}
private void LoadData()
{
for(int i=0; i <whaleDatas.Count; i++)
{
whaleDatas[i].dataName = PlayerPrefs.GetString(i+"_name");
whaleDatas[i].dataLevel = PlayerPrefs.GetInt(i+"_level");
string key = i + "_position";
whaleDatas[i].dataMousePosition = GetVector3(key);
}
}
}
Your code is actually broken in term of design.
First PlayerPref doesnt support boolean save by default.
IsSave = PlayerPrefs.HasKey //this will always return false.
thats why everytime you start the game all your saved data is deleted.
You can try this work around to save and load a boolean type How to save bool to PlayerPrefs Unity
Now, How on earth you decided to save and load data at update function?! , this is terrible and has huge performance cost if your data is huge. you just cant do it this way.
Instead, try to make events that store the data and load it instead, like once player enter a trigger box , the data is saved, and ofcourse you dont need to reload it if its saved , bec why you would have to load the data after its being saved?!!
Once again, dont read and write at Update Function like this all the time, this is bad design .

"AudioClip " does not take a constructor that takes 0 arguments

on this line, which is line 10 it says "AudioClip" does not take a constructor that takes 0 arguments. How to fix it? I know that AudioClip is a default class in Unity. What parameters shall I pass there or how to solve this issue?
AudioClip _clipRecord = new AudioClip()
int _sampleWindow = 128;
How to solve it?
public class MicInput : MonoBehaviour {
public static float MicLoudness;
private string _device;
//mic initialization
void InitMic(){
if(_device == null) _device = Microphone.devices[0];
_clipRecord = Microphone.Start(_device, true, 999, 44100);
}
void StopMicrophone()
{
Microphone.End(_device);
}
AudioClip _clipRecord = new AudioClip();
int _sampleWindow = 128;
//get data from microphone into audioclip
float LevelMax()
{
float levelMax = 0;
float[] waveData = new float[_sampleWindow];
int micPosition = Microphone.GetPosition(null)-(_sampleWindow+1); // null means the first microphone
if (micPosition < 0) return 0;
_clipRecord.GetData(waveData, micPosition);
// Getting a peak on the last 128 samples
for (int i = 0; i < _sampleWindow; i++) {
float wavePeak = waveData[i] * waveData[i];
if (levelMax < wavePeak) {
levelMax = wavePeak;
}
}
return levelMax;
}
void Update()
{
// levelMax equals to the highest normalized value power 2, a small number because < 1
// pass the value to a static var so we can access it from anywhere
MicLoudness = LevelMax ();
}
bool _isInitialized;
// start mic when scene starts
void OnEnable()
{
InitMic();
_isInitialized=true;
}
//stop mic when loading a new level or quit application
void OnDisable()
{
StopMicrophone();
}
void OnDestroy()
{
StopMicrophone();
}
// make sure the mic gets started & stopped when application gets focused
void OnApplicationFocus(bool focus) {
if (focus)
{
//Debug.Log("Focus");
if(!_isInitialized){
//Debug.Log("Init Mic");
InitMic();
_isInitialized=true;
}
}
if (!focus)
{
//Debug.Log("Pause");
StopMicrophone();
//Debug.Log("Stop Mic");
_isInitialized=false;
}
}
}
on this line, which is line 10 it says "AudioClip " does not take a constructor that takes 0 arguments. How to fix it?
----AudioClip _clipRecord = new AudioClip()----
---int _sampleWindow = 128;----
How to solve it?
In the AudioClip class add the following:
public AudioClip(){}
This issue arises because although you do initially get an empty ctor when you create a class, you lose that once you create a non-empty ctor so you MUST add the empty one if you wish to use it.
In the new unity version just change new AudioClip();
with
AudioClip _clipRecord = null;
Hope it helps

How to refresh playerprefs?

I'm making a Balloon popping game, and I want to get a prize for some amount of score for example if you made a score of 10 you get a sticker or if you made a score of 20 you get a keyholder, and if you have score 0 you get a try again text so the problem is that when I finish the game it displays the try again text then when you open a different program (like going to a folder or anything outside of unity the text refresh and then I get the right text. I have tried using update, LateUpdate and FixedUpdate but nothing changes.
Here is the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class CountDownTimer : MonoBehaviour
{
//public string levelToLoad;
public float timer = 60f;
public Text timerSeconds;
public GameObject panelWin, score, time, pausa;
public int _playerScore;
public Text premio;
// Use this for initialization
void Start ()
{
timerSeconds = GetComponent<Text>();
time.SetActive(true);
panelWin.SetActive(false);
Time.timeScale = 1;
}
// Update is called once per frame
void LateUpdate ()
{
timer -= Time.deltaTime;
timerSeconds.text = timer.ToString("f0");
if (timer <=0)
{
if (PlayerPrefs.HasKey("Points"))
{
_playerScore = PlayerPrefs.GetInt("Points");
if (_playerScore == 0)
{
premio.text = "Intenta de nuevo!";
}
else
{
if (_playerScore >= 1 && _playerScore <= 10)
{
premio.text = "Tu premio es: una calco Bebé a bordo";
}
else
{
if (_playerScore >= 11 && _playerScore <= 20)
{
premio.text = "Tu premio es: un llavero Huggies";
}
else
{
if (_playerScore >= 21 && _playerScore <= 30)
{
premio.text = "Tu premio es: un pack de toallitas";
}
else
{
if (_playerScore >= 31 && _playerScore <= 40)
{
premio.text = "Tu premio es: un pack de
pañales";
}
else
{
if (_playerScore >= 41 && _playerScore >= 50)
{
premio.text = "Tu premio es: un bolso
Huggies";
}
}
}
}
}
}
}
panelWin.SetActive(true);
score.SetActive(false);
//time.SetActive(false);
pausa.SetActive(false);
if (panelWin == true)
{
Time.timeScale = 0;
}
}
}
public void DoARestart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
public void Menu()
{
SceneManager.LoadScene("TitleScreen");
}
}
This is the GameController Script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameControllerScript : MonoBehaviour {
public Transform balloonPrefab;
public Text scoreDisplay;
public Text scoreDisplayWin;
public int _playerScore = 0;
//private int _multiplier = 1;
private float _timeSinceLastSpawn = 0.0f;
private float _timeToSpawn = 0.0f;
private List<Transform> _balloons;
private const int BALLOON_POOL = 30;
void Start () {
PlayerPrefs.SetInt("Points", 0);
_balloons = new List<Transform>();
for (int i = 0; i < BALLOON_POOL; i++) {
Transform balloon = Instantiate(balloonPrefab) as Transform;
balloon.parent = this.transform;
_balloons.Add(balloon);
}
SpawnBalloon();
GameStart();
}
/*void InitMultiplier() {
if (PlayerPrefs.HasKey("Multiplier")) {
_multiplier = Mathf.Max (1, PlayerPrefs.GetInt ("Multiplier"));
}
}*/
void InitPoints() {
if (PlayerPrefs.HasKey("Points"))
{
_playerScore = PlayerPrefs.GetInt("Points");
}
}
// Update is called once per frame
void Update () {
_timeSinceLastSpawn += Time.deltaTime;
if (_timeSinceLastSpawn >= _timeToSpawn)
{
SpawnBalloon();
}
}
void SpawnBalloon() {
_timeSinceLastSpawn = 0.0f;
_timeToSpawn = Random.Range (0.0f, 2.0f);
foreach (Transform b in _balloons) {
BalloonScript bs = b.GetComponent<BalloonScript>();
if (bs && !bs.isActive) {
bs.Activate();
break;
}
}
}
public void AddPoints(int points=1) {
_playerScore += points;
UpdateScoreDisplay();
}
public void GameOver() {
SavePoints();
SceneManager.LoadScene("TitleScreen");
}
void UpdateScoreDisplay() {
scoreDisplay.text = "Puntaje: " + _playerScore.ToString();// + "(x" +
_multiplier.ToString() + ")";
scoreDisplayWin.text = "Tu puntaje es: " + _playerScore.ToString();
}
public void GameStart() {
InitPoints();
//InitMultiplier();
UpdateScoreDisplay();
}
void OnApplicationPause() {
SavePoints();
}
void OnApplicationQuit() {
SavePoints();
}
void SavePoints() {
PlayerPrefs.SetInt("Points", _playerScore);
}
}
I dont have any errors on the console, would be very glad if anyone can help! Thanks!
Yep. You're not updating Points properly before it's used in CountDownTimer's LateUpdate()... Here is how your program flows:
In the GameController script, you set Points to 0 at Start().
In the CountDownTimer script, on every LateUpdate() (every frame), you check if playerPrefs.HasKey("Points"), which, from the first frame where GameController is enabled (runs Start()), which is probably the first game frame overall too, will result in true.
Right after that, you set _playerScore to Points (0), and selects a value for premio.text based on that.
Since...
Your GameController.GameOver() is probably not called in the first frame of the script/game, in fact, probably not called for several frames.
And since in the CountDownTimer.LateUpdate() (called every frame, including the first), from the first frame where GameControler.enabled == true (which is probably the first frame overall), Points will be there and equal 0.
In CountDownTimer.LateUpdate(), you will get "Intenta de nuevo!" from the first frame where GameControler.enabled == true (which is probably the first frame overall), for several frames, until GameControler.GameOver() is called.

Error CS0029: Cannot implicitly convert type `UnityEngine.GameObject[]' to `UnityEngine.GameObject'

I get the error on:
lad = GameObject.FindGameObjectsWithTag ("Ladder");
I'm just trying to disable all the ladders in the scene while the alarm is on and then enable them again once the alarm goes away. I'm not sure what the error means but need it fixed as soon as possible. I'm using C# and Unity 5. Thanks for any help you guys can provide!
using UnityEngine;
using System.Collections;
public class LevelAlarm : MonoBehaviour {
public bool alarmOn = false;
public bool bPlayerHidden = false;
// How long an alarm lasts for
[SerializeField]
private float alarmTimer = 5.0f;
private float alarmCurrentTimer = 0.0f;
public GameObject lad;
// Use this for initialization
void Start ()
{
lad = GameObject.FindGameObjectsWithTag ("Ladder");
}
// Update is called once per frame
void Update ()
{
// While alarm is on, run a timer
if (alarmOn)
{
alarmCurrentTimer += Time.deltaTime;
lad.SetActive(false);
// Timer is complete, alarm resets
if(alarmCurrentTimer >= alarmTimer)
{
alarmOn = false;
alarmCurrentTimer = 0.0f;
lad.SetActive(true);
}
}
}
}
GameObject.FindGameObjectsWithTag() returns an array of GameObjects, if you want first object of this array, use this:
void Start ()
{
var objects = GameObject.FindGameObjectsWithTag ("Ladder");
if(objects != null && objects.Length > 0)
{
lad = objects[0];
}
}
It's GameObject.FindGameObjectWithTag, not GameObject.FindGameObjectsWithTag, don't has character "s" after "Object".
Error CS0029: Cannot implicitly convert type UnityEngine.GameObject[]' toUnityEngine.GameObject'
This error simply means that you try to stop alarm whose tag are "Ladder".It creates an array and the function you use accept only one element of utilityEngine.GameObject. So you may use foreach loop to access all elements in the array by using :
public bool alarmOn = false;
public bool bPlayerHidden = false;
// How long an alarm lasts for
[SerializeField]
private float alarmTimer = 5.0f;
private float alarmCurrentTimer = 0.0f;
**public GameObject[] lad;**
// Use this for initialization
void Start ()
{
lad = GameObject.FindGameObjectsWithTag ("Ladder");
}
// Update is called once per frame
void Update ()
{
// While alarm is on, run a timer
if (alarmOn)
{
alarmCurrentTimer += Time.deltaTime;
**foreach(var eachLad in lad)
{
eachLad.SetActive(false);
}**
// Timer is complete, alarm resets
if(alarmCurrentTimer >= alarmTimer)
{
alarmOn = false;
alarmCurrentTimer = 0.0f;
**foreach(var eachLad in lad)
{
eachLad.SetActive(true);
}**
}
}
}

Categories