As I'm currently developing a Unity Engine based Game right now I need a PointerEnter EventTrigger to change my Text dynamically. Specifically:
If the user hovers with the Mouse in the MainMenu over a Text, I want an indicator on which Option he is pointing at.
So from Options the Text should turn to ▶ Options.
What I did is the following:
Text text;
string ContinueText = "▶ Continue";
void Awake()
{
// Set up the reference.
text = GetComponent<Text>();
}
public void Test()
{
text.text = ContinueText;
}
But if I hover over the Text I get
NullReferenceException: Object reference not set to an instance of an object
pointing at text.text = ContinueText;
So I searched around the Web and found that void Update() is sometimes called before Awake(), the Error stays the same anyway. The Canvas-Text is named "Text_Options", in case you need that.
Thanks for helping me out!
Here is an working example.
A canvas with an empty gameobject (has a vertical layout group, but thats not relevant) that is a container for two text objects.
I've added two event triggers each, OnPointerEnter and OnPointerExit. Both text objects have my script HoverText on them:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class HoverText : MonoBehaviour
{
Text text;
public string content = "Text A";
public string contentHighlighted = "▶ Text A";
void Awake()
{
text = GetComponent<Text>();
text.text = content;
}
public void Highlight()
{
text.text = contentHighlighted;
}
public void UnHighlight()
{
text.text = content;
}
}
Text_A has itself as gameobject for it's both event triggers and Text_B itself respectively. The public strings for the two different text contents are set via inspector (default value from script is actually matching Text_A in my example).
That's it, works fine.
Related
I'm trying to make an app in Unity which requires your name and other details. I'm using the legacy Input Field to get the answers from the player which worked, but I can't seem to use the Input in any way other than Debug.Log.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ReadInput : MonoBehaviour
{
private string input;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void ReadStringInput(string s)
{
input = s;
Debug.Log(input);
}
}
I used this simple script to get the input but I have no clue how to actually use it in the game. It want it to say, for example, Welcome,(Person's Name/Input) outside of the log and actually into a text object.
If you right click in the hierarchy, under UI you can add a text object. I like to use a free package called Text Mesh Pro, which you can get in the asset store, but you don't need to.
Once you've made your text object, it should appear as a child of a gameobject called the Canvas. The text object should have a text field that you can access from script.
Text mytext;
public void UpdateMyText(string s)
{
mytext.text = s;
}
Here's the documentation
Just drag the text object into the script's mytext field in the inspector, and call that function when you want to update your text.
I'm currently trying to develop my first mini game (a VR musical experience).
I'm trying to have the value of a slider control an FMOD parameter, but nothing happens. Plus the function does not show in the On Value Changed of the slider...
I'm already using that slider to control the transparency of a material and if I try changing the FMOD parameter manually in the inspector it works just fine.
Here is the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FMODParameters : MonoBehaviour
{
FMODUnity.StudioEventEmitter changeVolume;
FMOD.Studio.EventInstance bass;
public string bassVolumeParameter;
public Slider slider;
void Start()
{
changeVolume = GetComponent<FMODUnity.StudioEventEmitter>();
bass = FMODUnity.RuntimeManager.CreateInstance("event:/Beat/2D/2D Bass");
slider = GetComponent<Slider>();
}
// Update is called once per frame
void Update()
{
SetBassVolume();
}
void SetBassVolume()
{
bass.setParameterByName(bassVolumeParameter, slider.value / 250);
}
}
Thanks in advance for the help! :)
The problem is that you have to add the function in the onValueChanged () listener.
To do it:
Select the gameObject with the Slider component;
Click the "+" button in the OnValueChanged () listener below;
In the empty field, under "Runtime only", drag the gameObject with
this script;
Click the box that now has the name "No Function";
In the component list, place the cursor over the script name, and
under the "Dynamic parameters" category, the SetBassVolume () method.
But first you should tweak the method a bit, like so:
void SetBassVolume(float _value)
{
bass.setParameterByName(bassVolumeParameter, _value / 250);
}
Good work!
Is there any way to cycle text with textmesh script?
I'm interested in cycling text so i can display different text on my 2D game.
I have try the script on this website. But I don't think it works. Maybe I'm doing something wrong?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class CyclingText : MonoBehaviour
{
public TMP_Text text;
void Update()
{
TextMeshPro textmeshPro = GetComponent<TextMeshPro>();
textmeshPro.SetText("The first number is {0} and the 2nd is {1:2} and the 3rd is {3:0}.", 4, 6.345f, 3.5f);
// The text displayed will be:
// The first number is 4 and the 2nd is 6.35 and the 3rd is 4.
}
}
Can someone provide me with an answer or explained what I done wrong?
You seem a bit confused about the use of TMP
1
If you set the TMP in the inspector as public you can simply
public TMP_text text;
And then simply drag the text inside the inspector and simply:
text.text = "Text displayed";
2
If you don't create a public variable but a private, you can:
private TMP_text text;
And then, if you script is in the text object you can:
text = this.gameObject.GetCOmponent<TextMeshPro>();
And
text.text = "Your text";
I'm trying to divide the screen to 2 and use them as 2 different buttons (L,R) in Unity. But for the ones who are playing first time, I want to show the buttons' text and image to teach them what they do, and after that I want to disable buttons' image and text, they will be still interactable but invisible.
First time screen
How can I ?
Way easier and more reliable than what you did would simply be do add something like this to your Button:
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(Button))]
[DisallowMultipleComponent]
public class HintsController : MonoBehaviour
{
private Image _image;
private Text _text;
private float _originalAlpha;
// optional to control if Hints should be enabled on starting the App
public bool enableAtStart;
private void Awake()
{
// GetComponentInChildren finds the component on this object or any
// child of this object recursively
// (true) : make sure you also find the components if this or the child objects
// are currently disabled
// On this way you don't even have to rely on that the Image is on the
// Button GameObject or below in the hierachy
_image = GetComponentInChildren<Image>(true);
_text = GetComponentInChildren<Text>(true);
if(_image)
{
_originalAlpha = _image.color.a;
}
// optional to controll if Hints should be enabled on starting the App
ShowHints(enableAtStart);
}
public void ShowHints(bool isVisible)
{
// Skip if no Image found
if (_image)
{
var color = _image.color;
color.a = isVisible ? _originalAlpha : 0;
_image.color = color;
}
// Skip if no Text found
if (_text)
{
_text.enabled = isVisible;
}
}
}
Then from any other script, you simply can do e.g.
// TODO somehow get the reference either to the button GameObject or the Button component
var button;
button.GetComponent<HintsController>().ShowHints(false);
To disable hints.
I used button.image.enabled = bool valuefor image component and button.transform.GetChild(0).gameObject.SetActive(bool value) for the text.
i would suggest just making an empty for each button in the scene view, name them left and right. drag you button images(sprites) onte the scene and size them to fill the camera with proper positioning. apply boxCollider2D to both of the parent game objects(the empties you created and named left and right.) then you will need some light scripting.
pseudo-wise i would say:
you will use:
void OnMouseDown(){
//button touched
}
to see if the button is pressed.
when your tutorial is over you will set the image and text invisible with the code you mentioned above or something similar. this script goes on each button.
I am trying to make an easy to use button inside the Unity Editor for Character and Item creation.
I will throw out a little extra info here to help explain my issue.
My game is structured like this;
Game Controller >> Character Script >> (PlayerName)Script
A character object has both the character script and a script named after it, on it.
I want to be able to click "Create New Character" in the Unity editor and it do the following;
1) Prompt for a Name to use.
2) Create Empty Game Object named Name from whatever the user typed in.
3) Create a new C# Script named the same, and add it to the object.
-I want the generated script to have some pre-determined "Character Template" code in it.
4) Attach the new Script to the new empty game object, and attach a "Character Script" to it as well.
Thanks in advance.
One last sub-question.
Would it be better to Access the PlayerNamedScript from the GameController by a public monobehaviour on the Character Script?
Or can the CharacterScript Dynamically extend the PlayerNamedScript, sibling.
I hope that is clear. Thanks again.
Try this out
Put the CharacterCreatorEditor.cs in a folder named Editor somewhere in your project.
CharacterCreatorEditor.cs
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
using System.Text.RegularExpressions;
public class CharacterCreatorEditor : EditorWindow {
#region Character Fields
//Add as many character specific fields / variables you want here.
//Remember to update the same thing in the "CharacterTemplate.txt"!
public string characterName = "John Doe";
public float characterHealth = 10;
public int characterCost = 1000;
public bool isBadGuy = false;
#endregion
private bool needToAttach = false; //A boolean that checks whether a newly created script has to be attached
private float waitForCompile = 1; //Counter for compile
GameObject tempCharacter; //A temporary GameObject that we assign the new chracter to.
//A Menu Item when clicked will bring up the Editor Window
[MenuItem ("AxS/Create New Character")]
public static void CreateNewChar () {
EditorWindow.GetWindow(typeof(CharacterCreatorEditor));
}
void OnGUI () {
GUILayout.Label("Here's a sample Editor Window. Put in more variables as you need below.");
GUILayout.Space(10);
//Note on adding more fields
//The code below is broken into groups, one group per variable
//While it's relatively long, it keeps the Editor Window clean
//Most of the code should be fairly obvious
GUILayout.BeginHorizontal();
GUILayout.Label("Character Name", new GUILayoutOption[0]);
characterName = EditorGUILayout.TextField(characterName, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label("Character Health", new GUILayoutOption[0]);
characterHealth = EditorGUILayout.FloatField(characterHealth, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label("Character Cost", new GUILayoutOption[0]);
characterCost = EditorGUILayout.IntField(characterCost, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label(string.Format("Is {0} a Bad Guy?", new object[] { characterName }), new GUILayoutOption[0]);
isBadGuy = EditorGUILayout.Toggle(isBadGuy, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUI.color = Color.green;
//If we click on the "Done!" button, let's create a new character
if(GUILayout.Button("Done!", new GUILayoutOption[0]))
CreateANewCharacter();
}
void Update () {
//We created a new script below (See the last few lines of CreateANewCharacter() )
if(needToAttach) {
//Some counter we just keep reducing, so we can give the
//EditorApplication.isCompiling to kick in
waitForCompile -= 0.01f;
//So a few frames later, we can assume that the Editor has enough
//time to "catch up" and EditorApplication.isCompiling will now be true
//so, we wait for the newly created script to compile
if(waitForCompile <= 0) {
//The newly created script is done compiling
if(!EditorApplication.isCompiling) {
//Lets add the script
//Here we add the script using the name as a string rather than
//it's type in Angled braces (As done below)
tempCharacter.AddComponent(characterName.Replace(" ", ""));
//Reset the control variables for attaching these scripts.
needToAttach = false;
waitForCompile = 1;
}
}
}
}
private void CreateANewCharacter () {
//Instantiate a new GameObject
tempCharacter = new GameObject();
//Name it the same as the Character Name
tempCharacter.name = characterName;
//Add the ChracterScript component. Note the use of angle braces over quotes
tempCharacter.AddComponent<CharacterScript>();
//Loading the template text file which has some code already in it.
//Note that the text file is stored in the path PROJECT_NAME/Assets/CharacterTemplate.txt
TextAsset templateTextFile = AssetDatabase.LoadAssetAtPath("Assets/CharacterTemplate.txt",
typeof(TextAsset)) as TextAsset;
string contents = "";
//If the text file is available, lets get the text in it
//And start replacing the place holder data in it with the
//options we created in the editor window
if(templateTextFile != null) {
contents = templateTextFile.text;
contents = contents.Replace("CHARACTERCLASS_NAME_HERE", characterName.Replace(" ", ""));
contents = contents.Replace("CHARACTER_NAME_HERE", characterName);
contents = contents.Replace("CHARACTER_HEALTH_HERE", characterHealth.ToString());
contents = contents.Replace("CHARACTER_COST_HERE", characterCost.ToString());
contents = contents.Replace("CHARACTER_BAD_GUY_HERE", isBadGuy.ToString().ToLower());
}
else {
Debug.LogError("Can't find the CharacterTemplate.txt file! Is it at the path YOUR_PROJECT/Assets/CharacterTemplate.txt?");
}
//Let's create a new Script named "CHARACTERNAME.cs"
using(StreamWriter sw = new StreamWriter(string.Format(Application.dataPath + "/{0}.cs",
new object[] { characterName.Replace(" ", "") }))) {
sw.Write(contents);
}
//Refresh the Asset Database
AssetDatabase.Refresh();
//Now we need to attach the newly created script
//We can use EditorApplication.isCompiling, but it doesn't seem to kick in
//after a few frames after creating the script. So, I've created a roundabout way
//to do so. Please see the Update function
needToAttach = true;
}
}
Put the below text file into the path "YOUR_PROJECT/Assets/CharacterTemplate.txt" If you don't, the code WON'T WORK!
CharacterTemplate.txt
using UnityEngine;
using System.Collections;
public class CHARACTERCLASS_NAME_HERE : MonoBehaviour {
public string characterName = "CHARACTER_NAME_HERE";
public float characterHealth = CHARACTER_HEALTH_HERE;
public int characterCost = CHARACTER_COST_HERE;
public bool isBadGuy = CHARACTER_BAD_GUY_HERE;
public void SomeMethod () {
}
}
Explanation of the code
First, the editor script takes all the input variables (should be fairly obvious what they are)
Once you click the done button, the following happen
A new GameObject is Instantiated
The instantiated GameObject is named the same as the Character Name in the Editor (eg. John Doe)
The CharacterScript (your common script) is attached
The template text file ("CharacterTemplate.txt") is read, and all the data is replaced with the data you entered in the Editor Window
This is then written to a new script file
We refresh the Asset Database, and wait until the newly created script is compiled (eg. JohnDoe.cs)
Lastly attach the script to the GameObject instantiated in Step 1
For your second question, what you'll need to do is to have all your PlayerNamedClass extend the same base class. This way, you can type the variable you'll expose in CharacterScript
So, for example, if you call the base class "NamedCharacterScripts"
In JohnDoe.cs
public class JohnDoe : NamedCharacterScripts
In JaneDoe.cs
public class JaneDoe : NamedCharacterScripts
In CharacterScript.cs
public NamedCharacterScripts namedCharacterScript;
void Awake () {
//This will assign JohnDoe.cs for the GameObject named "John Doe" &
//JaneDoe.cs to the GameObject named "Jane Doe"
namedCharacterScript = GetComponent<NamedCharacterScripts>();
}
Hope this answers your questions. If you have trouble, just leave a comment
My script is not production-ready like Venkat's answer, but it should be easier to understand for educational purposes.
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
[ExecuteInEditMode]
public class CharacterTools : MonoBehaviour
{
[SerializeField, HideInInspector]
private string className;
private bool waitForCompile = false;
private void Update()
{
if (string.IsNullOrEmpty(className))
return;
if (waitForCompile && EditorApplication.isCompiling)
waitForCompile = false;
if (!waitForCompile && !EditorApplication.isCompiling)
{
var gameObject = new GameObject(className);
Debug.Log("Attempting to add " + className);
var c = gameObject.AddComponent(className);
className = null;
}
}
[ContextMenu("Create character")]
private void CreateCharacter()
{
string name = "Number" + Random.Range(0, 100).ToString();
string nameTemplate = "{0}Character";
string contentTemplate = #"using UnityEngine;
public class {0} : MonoBehaviour
{{
}}
";
var className = string.Format(nameTemplate, name);
var path = Application.dataPath + "/" + className + ".cs";
var scriptFile = new StreamWriter(path);
scriptFile.Write(string.Format(contentTemplate, className));
scriptFile.Close();
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceSynchronousImport);
AssetDatabase.Refresh();
this.className = className;
this.waitForCompile = true;
}
}
Usage:
Add this script to any object on scene.
Right click on just added component in inspector.
Choose “Create character”.
Wait few seconds.