how to change multiple UI elements on runtime - unity3d

I have many elements on my UI. I want to change the entire UI color. Basically like a new "Skin" for my HUD/Menu in game.
What is the best way to do this?
In UIBuilder, I can select a selector class and change the color, and it applies to all elements. How can I do this in runtime?
I have looked into USS variables, but it doesn't look like I can edit those using C# on runtime.

The easiest answer I see is creating a UIManager class and placing it in the scene.
Your UI Manager will have an instance, thus making it a Singleton, here is the code that should be inside your UIManager
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class UIManager : MonoBehaviour
{
public static Singleton Instance { get; private set; }
public Color[] skinColours;
private void Awake()
{
// If there is an instance, and it's not me, delete myself.
if (Instance != null && Instance != this)
{
Destroy(this);
}
else
{
Instance = this;
}
}
public void ReskinUI(int skinIndex)
{
// Repeat this for RawImages, Buttons etc.
foreach (Image image in GameObject.FindObjectsOfType<Image>())
{
image.color = skinColours[skinIndex];
}
}
}
After your define your UIManager, you can use it in your code like this.
UIManager.Instance.ReskinUI(1);
The '1' there, corresponds to the skin index.
Let me know if this helps

Not sure what you are placing on your UI but there are only two generally, raw images and images.
Step 1. Create a script to gather the images and/or raw images and store a link to them
Step 2. Change the colour on those images.
Step 3. Ensure other things can grab your code to change the colour
Step 1:
/// <summary>
/// Gets all the images attached
/// </summary>
private void GetAllImagesInChildren()
{
allGraphics = new List<Graphic>();
foreach (Transform child in transform)
{
var image = child.gameObject.GetComponent<Image>();
if (image)
{
allGraphics.Add(image);
}
else
{
var rawImage = child.gameObject.GetComponent<RawImage>();
if (rawImage)
{
allGraphics.Add(rawImage);
}
}
}
}
Image and Raw image are both 'Graphic' types and they have the color attribute. Next just use GetComponent. It's also good practice to use GetComponent as little as needed hence storing the value. If you are only using RawImages feel free to switch the order.
Step 2:
/// <summary>
/// All raw images and images.
/// </summary>
private List<Graphic> allGraphics;
// Start is called before the first frame update
void Awake()
{
GetAllImagesInChildren();
}
/// <summary>
/// Sets the Color of all the UI elements attached
/// </summary>
/// <param name="newColor">New color</param>
public void SetUIColor(Color newColor)
{
foreach(Graphic graphic in allGraphics)
{
graphic.color = newColor;
}
}
Let's attach the method from step one into a new script, store graphics privately and call it on awake. Then because graphics is now private create a simple public method which just uses our stored values. You could easily overload this with Color32 just copy and paste the method with that.
All together:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIColourChanger : MonoBehaviour
{
/// <summary>
/// All raw images and images.
/// </summary>
private List<Graphic> allGraphics;
// Start is called before the first frame update
void Awake()
{
GetAllImagesInChildren();
}
/// <summary>
/// Sets the Color of all the UI elements attached
/// </summary>
/// <param name="newColor">New color</param>
public void SetUIColor(Color newColor)
{
foreach(Graphic graphic in allGraphics)
{
graphic.color = newColor;
}
}
/// <summary>
/// Gets all the images attached
/// </summary>
private void GetAllImagesInChildren()
{
allGraphics = new List<Graphic>();
foreach (Transform child in transform)
{
var image = child.gameObject.GetComponent<Image>();
if (image)
{
allGraphics.Add(image);
}
else
{
var rawImage = child.gameObject.GetComponent<RawImage>();
if (rawImage)
{
allGraphics.Add(rawImage);
}
}
}
}
}
Then simply the children of the object attached to this script are stored. Then just add:
public UIColourChanger ColorChanger;
or
[SerializeField]
private UIColourChanger colorChanger
To any other script and drag in this one into it to gain access to that public method.

Related

How can I create a list with images and change which one is displayed in Unity

I'm trying to make a ui that has a video shown and after that video is done, it recommends 3 different videos, these videos are dependent on the video that was just watched.
Now did I manage to get the buttons to display different text with a list system.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UnityEngine.UI;
// using UnityEngine.Video;
public class Recommendations : MonoBehaviour
{
public Button Rec1;
public Button Rec2;
public Button Rec3;
private int[] recommendedButtonValues;
private float[] recommendedSliderValues;
public List<DescriptionContainer> descriptionContainer = new List<DescriptionContainer>();
public List<ImageContainer> ImageContainer = new List<ImageContainer>();
public VideoplayerScript VideoPlayer;
public void SetRecommendationButtons(int buttonValue, float sliderValue) {
CheckRecommendations(buttonValue, sliderValue);
Rec1.GetComponentInChildren<TextMeshProUGUI>().text = descriptionContainer[recommendedButtonValues[0]].descriptions[(int)recommendedSliderValues[0]];
Rec2.GetComponentInChildren<TextMeshProUGUI>().text = descriptionContainer[recommendedButtonValues[1]].descriptions[(int)recommendedSliderValues[1]];
Rec3.GetComponentInChildren<TextMeshProUGUI>().text = descriptionContainer[recommendedButtonValues[2]].descriptions[(int)recommendedSliderValues[2]];
private void CheckRecommendations(int buttonValue, float sliderValue) {
if (buttonValue == 0) {
if (sliderValue == 0) {
recommendedButtonValues = new[] { 2, 0, 0 };
recommendedSliderValues = new[] { 0f, 2f, 4f };
//currentInterviewPhoto = ImageContainer[recommendedButtonValues].images[(int)recommendedSliderValues];
}
else if (sliderValue == 1) {
recommendedButtonValues = new[] { 1, 0, 3 };
recommendedSliderValues = new[] { 1f, 4f, 0f };
}
}
//this is repeated multiple times but I dont think its needed to show to get the point across, both for multiple button as slider values.
public void OnClickButton1() {
VideoPlayer.buttonValue = recommendedButtonValues[0];
VideoPlayer.sliderValue = recommendedSliderValues[0];
Debug.Log("Recommendation pressed for the following video, Button value: " + recommendedButtonValues[0] + ". Slider value: " + recommendedSliderValues[0]);
//repeated for all three buttons
[System.Serializable]
public class DescriptionContainer {
[TextArea(10, 10)]
public List<string> descriptions;
}
All this works but I'm now trying to do something similar with an images but I cant really get a list to work with an images. The thing I want to do is have 3 different images, depending on the
recommendedButtonValues[0,1 or 2] and the recommendedSliderValues[0,1 or 2] it decides which one to show. I've tried creating a list with textures like this:
[System.Serializable]
public class ImageContainer
{
public List<Texture> images;
}
public void WhatImag1e()
{
Image1 = ImageContainer[recommendedButtonValues[0]].images[(int)recommendedSliderValues[0]];
}
But I got the error that Unity cant convert UnityEngine.Texture to UnityEngine.UI.Image.
So my questions is what kind of list can I make which does work? Or is this not possible with a list and does I need to do.
I havent copied my entire code since that seems like an overkill but if I missed something I can show it. I'm using Unity version 2019.4.18f1 for this.
A UI.Image is a sprite container, it has a property 'sprite' where you can set sprites and it will change the texture of the widget to the sprite passed.
In your case, if you have textures, you need to change your UI.Image to UI.RawImage (change component in the editor), which accepts textures in its property 'texture'.

How to load next scene when pressed a button while playing in unity

This what I tried,
I was watching Brackeys
public void PlayGame()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
};
Your script probably doesn't work if you have 1 scene, or the current scene is at the end of the list in Build Settings.
Also you can use it this way:
//Add scenes in inspector
[SerializeField] private List<Scene> _sceneList;
public void LoadNextScene()
{
int currentScene = SceneManager.GetActiveScene().buildIndex;
if (currentScene < _sceneList.Count)
SceneManager.LoadScene(_sceneList[currentScene + 1].buildIndex);
else
print("Its last scene");
}
You can use SceneManager.LoadScene() method to load the Scene by its name or index in Build Settings.
The SceneManager.GetActiveScene().buildIndex gives you the index number of the current scene and you can add an incremental value to navigate to the next scene.
To do that,
Create a new script named SceneController and methods as follows,
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneController : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void LoadMenuScene() {
SceneManager.LoadScene("MenuScene");
}
public void NextScene() {
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
public void ReloadScene() {
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
Add the script to the Canvas object
Add the method to the button OnClick event in the inspector
NB: You can also use name or index values to load the scene (like LoadMenuScene)
For more: https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadScene.html

Access variable from a different scene in Unity

I am fairly new to Unity and C# and am having some trouble. I am designing a 2d game, which has multiple levels. Each level contains a LevelManager which stores whether the level has been completed or not. They also have the DontDestroyOnLoad command in them. I want to access all the LevelManager gameObjects in my game and then store them in a level select scene. I want to use the win/lose bool to determine if the level has been completed so I can unlock the next level. To be clear, I want a way to access all the LevelManagers in my ENTIRE game and then store them as an array in a GameManager script. How do I do that?
Below is the LevelManager script which declares whether the level has been won or not.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneController : MonoBehaviour
{
private GameObject[] StartHouseCount;
private GameObject[] StartDragonCount;
private GameObject[] LiveDragonCount;
private GameObject[] FinishedHouseCount;
public int NumOfHouses;
public int NumOfFinishedHouse;
public int NumOfDragons;
public int LiveNumOfDragons;
public GameObject[] Players;
public GameObject CurrentPlayer;
[Header("Player")]
public float RefuelRate;
public float RepairRate;
public GameObject canvas;
public bool GameIsPaused = false;
private GameObject MainPlayer;
public bool Win = false;
public int Level;
// Start is called before the first frame update
void Start()
{
CurrentPlayer = Players[0];
StartHouseCount = GameObject.FindGameObjectsWithTag("House");
StartDragonCount = GameObject.FindGameObjectsWithTag("Dragon");
NumOfHouses = StartHouseCount.Length;
NumOfDragons = StartDragonCount.Length;
MainPlayer = Players[0];
}
// Update is called once per frame
void Update()
{
GameIsPaused = canvas.GetComponent<PauseMenu>().GameIsPaused;
LiveDragonCount = GameObject.FindGameObjectsWithTag("Dragon");
LiveNumOfDragons = LiveDragonCount.Length;
FinishedHouseCount = GameObject.FindGameObjectsWithTag("ThankYou");
NumOfFinishedHouse = FinishedHouseCount.Length;
if (Input.GetKeyDown(KeyCode.Alpha1))
{
CurrentPlayer = Players[0];
}
if (Input.GetKeyDown(KeyCode.Alpha2))
{
CurrentPlayer = Players[1];
}
if (NumOfFinishedHouse == NumOfHouses)
{
SceneManager.LoadScene("WinScene");
}
if (MainPlayer == null)
{
SceneManager.LoadScene("LoseScene");
}
if (MainPlayer.GetComponent<BasicHelicopterController>().CurrentFuel <= 0 || MainPlayer.GetComponent<BasicHelicopterController>().CurrentHealth <= 0)
{
SceneManager.LoadScene("LoseScene");
}
}
}
You can create a ScoreManager script to store scores of each level using PlayerPrefs and attach this script to a GameObject in the first scene.
public class ScoreManager: MonoBehavior {
public static ScoreManager Instance;
const string LEVEL_KEY = "SCORE_";
const string MAX_LEVEL_KEY = "MAX_LEVEL";
public static int MAX_LEVEL {
get { return PlayerPrefs.GetInt(MAX_LEVEL_KEY, 1); }
set {
if(value > MAX_LEVEL) {
PlayerPrefs.SetInt(MAX_LEVEL_KEY, value);
}
}
}
void Awake() {
if(Instance != null) {
Destroy(this.gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(this);
}
public void SaveScore(int level, float score) {
PlayerPrefs.SetFloat(LEVEL_KEY + level, score);
MAX_LEVEL = level;
}
public float GetScore(int level) {
return PlayerPrefs.GetFloat(LEVEL_KEY + level, 0);
}
public bool IsLevelUnlocked(int level) {
// You can write your own level-unlock logic here.
return level <= MAX_LEVEL;
}
...
}
Then you can just call its functions and properties from other scripts.
...
public void GameOver() {
ScoreManager.Instance.SaveScore(level, score);
}
...
Having all LevelManger scripts with DontDestroyOnLoad will cause a memory leak and sometimes it will affect the game performance.
First, DontDestroyOnLoad is not supposed to do this - main usage for this is to implement things like unity-singleton (easy-to-use template). It means, you`ll have one instance of levelManager, not one per level.
To do it in your way, you need to load all the scenes additively, and get all the LevelManager instances. Or you can load all scenes one-by-one, getting level name and it`s isPassed value from current LevelManager. It can take a while, and its a wrong way.
The right way is to store inter-scene data in ScriptableObject models. It`s like a MonoBehaviour, but not related to scene - it just lays somewhere in project.
So, in your case, you can create ScriptableObject called LevelProgress. It will store the list of all passed levels. It will have public method LevelPassed(string levelName), as a parameter you can use anything - levels name, levels index in build, scene itself, whatever. Every time, when player passes any level, your LevelManager (remove DontDestoryOnLoad from it), which has a reference to LevelProgress scriptable object, will call LevelProgress.LevelPasses(currentLevel). And then, if you need to know, was some level passed, or not, you can just check, is LevelProgress.PassedLevels list contains this level.
Additionally, you need to implement between-sessions persistance for this scriptable object. IMO, the best way for this is to use JSONUtility to convert ScriptableObject into JSON string, and then write it to PlayerPrefs.
I seemed to have figured it out. I created a gameObject containing a GameManagement script, that had the DontDestroyOnLoad line. I had also added a specific tag. I then searched for that object in each level and updated my values to that. The GameManagement script had an array of bools for levels completed and levels unlocked. Each levelmanager decided whether the level was won and updated that. Using that I determined what level was unlocked. I did though need to use Fire King's Awake Command. It ensures that there are no other copies of the script in the game. Solves my problems.

Simplest way to carry dialogue between scenes without use of Player Prefs, etc

I have been working on a dialogue system for my game and I was wondering if anyone knows how to keep the system between different scenes. I know you can use things such as Player Prefs but for one, I do not understand it and upon research, people do not generally recommend it for storing large complicated things. I managed to get close to doing so by using dontDestroy just as you would with a character, however, it did not work completely as the button to switch to the next line of text, of course, broke along with the singleton I created for my system. What would be the best way for me to go about this?
Here is all of my code just in case it is needed:
Making the scriptable object:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New Dialogue", menuName = "Dialogues")]
public class Dialogue : ScriptableObject
{
[System.Serializable]
public class Info
{
public string myName;
public Sprite portrait;
[TextArea(4, 8)]
public string mytext;
}
[Header("Insert Dialogue Info Below")]
public Info[] dialogueInfoSection;
}
Main code for system (sigleton breaks here while switching scenes):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MainDialogueManager : MonoBehaviour
{
public static MainDialogueManager instance;
private void Awake()
{
if(instance != null)
{
Debug.LogWarning("FIX THIS" + gameObject.name);
}
else
{
instance = this;
}
}
public GameObject DialogueBoX;
public Text dialogueNameofChar;
public Text characterSays;
public Image characterPortrait;
private float textDelay = 0.005f;
public Queue<Dialogue.Info> dialogueInfoSection = new Queue<Dialogue.Info>();
public void EnqueueDialogue(Dialogue db)
{
DialogueBoX.SetActive(true);
dialogueInfoSection.Clear();
foreach(Dialogue.Info info in db.dialogueInfoSection)
{
dialogueInfoSection.Enqueue(info);
}
DequeueDialogue();
}
public void DequeueDialogue()
{
if (dialogueInfoSection.Count==0)
{
ReachedEndOfDialogue();
return; /////
}
Dialogue.Info info = dialogueInfoSection.Dequeue();
dialogueNameofChar.text = info.myName;
characterSays.text = info.mytext;
characterPortrait.sprite = info.portrait;
StartCoroutine(TypeText(info));
}
IEnumerator TypeText(Dialogue.Info info)
{
characterSays.text= "";
foreach(char c in info.mytext.ToCharArray())
{
yield return new WaitForSeconds(textDelay);
characterSays.text += c;
yield return null;
}
}
public void ReachedEndOfDialogue()
{
DialogueBoX.SetActive(false);
}
}
Dialogue Activation:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MainDialogueActivation : MonoBehaviour
{
public Dialogue dialogue;
public void startActivationofDialogue()
{
MainDialogueManager.instance.EnqueueDialogue(dialogue);
}
private void Start()
{
startActivationofDialogue();
}
}
Go to next dialogue line:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MainDialogueButtons : MonoBehaviour
{
public void GoToNextDialogueLine()
{
MainDialogueManager.instance.DequeueDialogue();
}
}
How about something like this?
The idea is pretty similar to what you're doing, with a few tweaks:
I'm storing the active dialog in a scriptable object (DialogueSystem) so that it can persist between scenes. Each time I load a new scene, I check if there's an active dialog, and if I so I show the dialog popup in Start().
Whereas you remove the dialog section that you're currently showing to the player from the current dialog, I don't remove the current section until the player clicks to the next section. That's necessary because you may need to re-show the same section if you move to a new scene.
Make sure to create an instance of the DialogueSystem scriptable object and assign it to MainDialogueActivation and MainDialogManager
MainDialogActiviation has some testing code in it so you can hit a key to start a new dialog or switch between scenes.
MainDialogueActiviation.cs
using UnityEngine;
using UnityEngine.SceneManagement;
public class MainDialogueActivation : MonoBehaviour
{
public Dialogue dialogue;
// This scriptable object stores the active dialog so that you
// can persist it between scenes
public DialogueSystem dialogSystem;
private void Start()
{
// If we had an active dialog from the previous scene, resume that dialog
if (dialogSystem?.dialogInfoSections.Count > 0)
{
GetComponent<MainDialogueManager>().ShowDialog();
}
}
private void Update()
{
// Pressing D queues and shows a new dialog
if (Input.GetKeyDown(KeyCode.D))
{
GetComponent<MainDialogueManager>().EnqueueDialogue(this.dialogue);
}
// Pressing C ends the current dialog
if (Input.GetKeyDown(KeyCode.C))
{
this.dialogSystem.dialogInfoSections.Clear();
GetComponent<MainDialogueManager>().ReachedEndOfDialogue();
}
// Pressing S swaps between two scenes so you can see the dialog
// persisting
if (Input.GetKeyDown(KeyCode.S))
{
if (SceneManager.GetActiveScene().name == "Scene 1")
{
SceneManager.LoadScene("Scene 2");
}
else if (SceneManager.GetActiveScene().name == "Scene 2")
{
SceneManager.LoadScene("Scene 1");
}
}
}
}
MainDialogueManager.cs
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class MainDialogueManager : MonoBehaviour
{
// This scriptable object stores the active dialog
public DialogueSystem dialogSystem;
public GameObject DialogueBox;
public Text dialogueNameofChar;
public Text characterSays;
public Image characterPortrait;
private float textDelay = 0.005f;
// The game object for the dialog box that is instantiated in this
// scene
private GameObject dialogBoxGameObject;
/// <summary>
/// Shows the dialog window for the dialog that is in this object's
/// dialogSystem property.
/// </summary>
public void ShowDialog()
{
// Instantiate the dialog box prefab
this.dialogBoxGameObject = Instantiate(this.DialogueBox);
// I'd recommend putting a script on your "dialog box" prefab to
// handle this stuff, so that this script doesn't need to get a
// reference to each text element within the dialog prefab. But
// this is just a quick and dirty example for this answer
this.dialogueNameofChar = GameObject.Find("Character Name").GetComponent<Text>();
this.characterSays = GameObject.Find("Character Text").GetComponent<Text>();
this.characterPortrait = GameObject.Find("Character Image").GetComponent<Image>();
// If you have multiple response options, you'd wire them up here.
// Again; I recommend putting this into a script on your dialog box
GameObject.Find("Response Button 1").GetComponent<Button>().onClick.AddListener(ShowNextDialogSection);
GameObject.Find("Response Button 2").GetComponent<Button>().onClick.AddListener(ShowNextDialogSection);
ShowDialogSection(this.dialogSystem.dialogInfoSections.Peek());
}
/// <summary>
/// Puts a dialog into this object's dialogSystem property and
/// opens a dialog window that will show that dialog.
/// </summary>
public void EnqueueDialogue(Dialogue db)
{
foreach (Dialogue.Info info in db.dialogueInfoSection)
{
this.dialogSystem.dialogInfoSections.Enqueue(info);
}
ShowDialog();
}
/// <summary>
/// Removes the dialog section at the head of the dialog queue,
/// and shows the following dialog statement to the player. This
/// is a difference in the overall logic, because now the dialog
/// section at the head of the queue is the dialog that's currently
/// being show, rather than the previous one that was shown
/// </summary>
public void ShowNextDialogSection()
{
this.dialogSystem.dialogInfoSections.Dequeue();
if (this.dialogSystem.dialogInfoSections.Count == 0)
{
ReachedEndOfDialogue();
return;
}
Dialogue.Info dialogSection = this.dialogSystem.dialogInfoSections.Peek();
ShowDialogSection(dialogSection);
}
/// <summary>
/// Shows the specified dialog statement to the player.
/// </summary>
public void ShowDialogSection(Dialogue.Info dialogSection)
{
dialogueNameofChar.text = dialogSection.myName;
characterSays.text = dialogSection.mytext;
characterPortrait.sprite = dialogSection.portrait;
StartCoroutine(TypeText(dialogSection));
}
IEnumerator TypeText(Dialogue.Info info)
{
characterSays.text = "";
foreach (char c in info.mytext.ToCharArray())
{
yield return new WaitForSeconds(textDelay);
characterSays.text += c;
yield return null;
}
}
public void ReachedEndOfDialogue()
{
// Destroy the dialog box
Destroy(this.dialogBoxGameObject);
}
}
DialogSystem.cs
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName = "Dialogues/Dialog System")]
public class DialogueSystem : ScriptableObject
{
public Queue<Dialogue.Info> dialogInfoSections = new Queue<Dialogue.Info>();
}
Here's what my dialog box prefab looks like
Every scene needs an object (presumably a prefab to make it easy to add to every scene) that has MainDialogActiviation and MainDialogManager on it. Mine looks like this:
This might be a bit of an unpopular opinion but using Singleton's are fine. It's just that MonoBehaviour singletons are tricky, you can use Object.DontDestroyOnLoad(instance). But things get ugly because it doesn't get destroyed when the scene changes (good) but if you go back to the scene it will load another one (bad). There's a few ways to get around that like having the object destroy itself if there's already an instance or having a subscene.
I would suggest not using MonoBehaviour singletons and use ScriptableObject singletons. You can lazy instantiate by putting the asset in a resource folder and use Resource.Load like this.
public class ScriptableSingleton<T> : ScriptableObject where T : ScriptableSingleton<T> {
private static string ResourcePath {
get {
return typeof(T).Name;
}
}
public static T Instance {
get {
if (instance == null) {
instance = Resources.Load(ResourcePath) as T;
}
return instance;
}
}
private static T instance;
}
With this code you create a Singleton class say DialogueManager you create a DialogueManager.asset for it and put it in a "Resources" folder.

How to display a name and score list for players using happyfuntimes and unity3d

This is related to happyfuntimes plugin if you have used it .
I am trying to make a game on it and stuck at a point of displaying score along with name to display on large screen while user is playing on his mobile.(i have already tried to display name and score on mobile screens have seen in sample do not need that ). Please suggest how can this be done if you have used happyfuntimes plugin.
I could see the HFTgamepad input having public GameObject player name which I am trying to access ,do I have to make array ?
public string playerName;
I am trying to put these name on array.
Displaying anything in unity is really normal unity issue and not special to happyfuntimes. Games display highscore lists, item lists, inventory lists, etc... A list of players is no different
Use the GUI system display text.
According to the docs if you want to generate UI dynamically you should make a prefab
So basically you'd make a UI hierarchy in the scene. When a player is added to the game Instantiate your name-score prefab, search for the UI hierarchy gameObject (do that at init time), then set the parent of the preafab you just instantiated so it's in the UI hierarchy.
Look up the UI.Text components that represent name and score and set their text properties.
There's various auto layout components to help layout your scores
When a player disconnects Destroy the prefab you instantiated above.
OR ...
Conversely you can use the old immediate mode GUI. You'd make a GameObject, give it a component that has a OnGUI function. Somewhere keep a list of players. Add players to the list as they connect and remove them from the list as they disconnect. In your OnGUI function loop over the list of players and call the GUI.Label function or similar to draw each name and score
Here's a hacked up example.
Assuming you have a PlayerScript script component that's on each player that has a public accessor PlayerName for getting the player's name then you can make a GameObject and put a script like this on it.
using UnityEngine;
using System.Collections.Generic;
public class ExamplePlayerListGUI : MonoBehaviour
{
static ExamplePlayerListGUI s_instance;
List<PlayerScript> m_players = new List<PlayerScript>();
static public ExamplePlayerListGUI GetInstance()
{
return s_instance;
}
void Awake()
{
if (s_instance != null)
{
Debug.LogError("there should only be one ExamplePlayerListGUI");
}
s_instance = this;
}
public void AddPlayer(PlayerScript bs)
{
m_players.Add(bs);
}
public void RemovePlayer(PlayerScript bs)
{
m_players.Remove(bs);
}
public void OnGUI()
{
Rect r = new Rect(0, 0, 100, m_players.Count * 20);
GUI.Box(r, "");
r.height = 20;
foreach(var player in m_players)
{
GUI.Label(r, player.PlayerName);
r.y += 20;
}
}
}
PlayerScript can then call ExamplePlayerListGUI.GetInstance().AddPlayer in its Start function and ExamplePlayerListGUI.GetInstance().RemovePlayer in it's OnDestroy function
public PlayerScript : MonoBehaviour
{
private string m_playerName;
...
public string PlayerName
{
get
{
return m_playerName;
}
}
void Start()
{
...
ExamplePlayerListGUI playerListGUI = ExamplePlayerListGUI.GetInstance();
// Check if it exists so we can use it with or without the list
if (playerListGUI != null)
{
playerListGUI.AddPlayer(this);
}
}
void OnDestroy()
{
...
ExamplePlayerListGUI playerListGUI = ExamplePlayerListGUI.GetInstance();
if (playerListGUI != null)
{
playerListGUI.RemovePlayer(this);
}
}
}