Typewriter effect that shows one character per click on a button in Unity C# - c#

I need help with creating a code for a typewriter effect that only displays one character per click(ui button), I'm really new to Unity and coding as a whole, and I used a tutorial to use the typewriter effect, then i tried to make it so it only works as one character per click on the button, but it didn't work.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class TypeWriterEffect : MonoBehaviour {
public float delay = 0.1f;
public string fullText;
private string currentText = "";
public Button toggleButton;
bool toggle = false;
void Start () {
toggleButton.onClick.AddListener(Toggle);
}
void Toggle()
{
StartCoroutine(ShowText());
toggle = true;
}
IEnumerator ShowText(){
if (toggle == true)
{
for (int i = 0; i < fullText.Length; i++)
{
this.GetComponent<Text>().text = currentText;
currentText = fullText.Substring(0, i);
yield return new WaitForSeconds(delay);
}
toggle = false;
}
}
}

If you really want it to only display one character per click on a UI button, you can cut it down to something like this:
using UnityEngine;
using UnityEngine.UI;
public class TypeWriterEffect : MonoBehaviour
{
public string fullText;
public Button toggleButton;
public int carriage=0;
void Start () {
toggleButton.onClick.AddListener(Clicked);
GetComponent<Text>().text = fullText.Substring(0, carriage);
}
void Clicked()
{
carriage++;
GetComponent<Text>().text = fullText.Substring(0, carriage);
}
}

Related

How can I find all the ui text components in the hierarchy and then to disable/enable them?

For now I created array of Text and then dragging in the editor one by one to the inspector to the array.
The problem is that some Text ui are childs or childs of childs and it's not easy to find them all one by one.
How can I loop over the hierarchy or find all the text ui and then to disable/enable them ?
I need it for my game pause/resume.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class BackToMainMenu : MonoBehaviour
{
public Text[] uiTexts;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (Time.timeScale == 0)
{
SceneManager.UnloadSceneAsync(0);
DisableEnableUiTexts(false);
Cursor.visible = false;
Time.timeScale = 1;
}
else
{
Time.timeScale = 0;
MenuController.LoadSceneForSavedGame = false;
DisableEnableUiTexts(true);
SceneManager.LoadScene(0, LoadSceneMode.Additive);
Cursor.visible = true;
}
}
}
private void DisableEnableUiTexts(bool uiTextEnabled)
{
if (uiTexts.Length > 0)
{
foreach (Text ui in uiTexts)
{
if (uiTextEnabled)
{
ui.GetComponent<Text>().enabled = false;
}
else
{
ui.GetComponent<Text>().enabled = true;
}
}
}
}
}
Update :
I tried this :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class BackToMainMenu : MonoBehaviour
{
[ContextMenuItem("Fetch", nameof(FetchAllTexts))]
public Text[] uiTexts;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (Time.timeScale == 0)
{
SceneManager.UnloadSceneAsync(0);
DisableEnableUiTexts(false);
Cursor.visible = false;
Time.timeScale = 1;
}
else
{
Time.timeScale = 0;
MenuController.LoadSceneForSavedGame = false;
DisableEnableUiTexts(true);
SceneManager.LoadScene(0, LoadSceneMode.Additive);
Cursor.visible = true;
}
}
}
private void FetchAllTexts()
{
var tmp = new List<Text>();
for (var i = 0; i < SceneManager.sceneCount; i++)
{
foreach (var root in SceneManager.GetSceneAt(i).GetRootGameObjects())
{
tmp.AddRange(root.GetComponentsInChildren<Text>(true));
}
}
Text[] texts = tmp.ToArray();
uiTexts = texts;
}
private void DisableEnableUiTexts(bool uiTextEnabled)
{
if (uiTexts.Length > 0)
{
foreach (Text ui in uiTexts)
{
ui.enabled = uiTextEnabled;
}
}
}
}
but I don't see the "Fetch" ContextMenuItem anywhere. Tried right click on the object in hierarchy where the script is attached to tried in the Assets tried in the editor menu/s it's not there.
As said either use FindObjectsOfType
Text[] texts = FindObjectsOfType<Text>();
will return all active and enabled instances of Text.
However to get also disabled/inactive ones you can use
var tmp = new List<Text>();
for(var i = 0; i < SceneManager.sceneCount; i++)
{
foreach(var root in SceneManager.GetSceneAt(i).GetRootGameObjects)
{
tmp.AddRange(root.GetComponentsInChildren<Text>(true));
}
}
Text[] texts = tmp.ToArray();
which iterates over all loaded scenes and fetches ALL instances also currently inactive or disabled ones.
See
SceneManager.sceneCount
SceneManager.GetSceneAt
Scene.GetRootGameObjects
GameObject.GetComponentsInChildren
Then you can e.g. fetch this once either in Start or even earlier via the Inspector itself so you don't have to do it at every app start using [ContextMenuItem].
public class BackToMainMenu : MonoBehaviour
{
[ContextMenuItem("Fetch", nameof(FetchAllTexts)]
public Text[] uiTexts;
private void FetchAllTexts()
{
uiTexts = // One of the methods shown above
}
...
}
Why is this a good thing? As said this way you don't have to do it every time in Start and thus delaying the app start until it is done.
Instead you store all the references already via the Inspector in a SerializeField so when your app starts, this component already "knows" these references and you don't have to get them first.
Simply right click on the uiTexts field in the Inspector and hit Fetch
Then in general you would simply write
private void DisableEnableUiTexts(bool uiTextEnabled)
{
foreach (Text ui in uiTexts)
{
ui.enabled = uiTextEnabled;
}
}

How can I make a button to act like a toggle or maybe using a toggle and make the toggle to looks like a button?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GenerateUIButtons : MonoBehaviour
{
public Button buttonPrefab;
public GameObject parent;
public int numberOfButtons;
public float spaceBetweenButtons;
private Button[] buttons;
// Start is called before the first frame update
void Start()
{
buttons = new Button[Rotate.names.Length];
for (int i = 0; i < buttons.Length; i++)
{
buttons[i] = Instantiate(buttonPrefab) as Button;
buttons[i].name = Rotate.names[i];
buttons[i].transform.SetParent(parent.transform, false);
int j = i;
buttons[i].onClick.AddListener(() => ButtonClicked(j));
}
}
void ButtonClicked(int buttonNo)
{
Debug.Log("Clicked On " + buttons[buttonNo]);
}
// Update is called once per frame
void Update()
{
}
}
I want that inside the ButtonClicked when clicking on a button the text inside color will change to green and stay green for the clicked button. And if clicking on the same green button again change the color back to the original.
Like a switch.
I created a custom one few days ago, take a look on the code below.
Here you can see it in action: https://youtu.be/sl9EheTbmhE
ToggleButton.cs
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[RequireComponent(typeof(Image))]
public class ToggleButton : MonoBehaviour, IPointerClickHandler
{
public ToggleEvent CheckedChanged = new ToggleEvent();
Image _image;
Color _originalColor;
bool _checked;
[SerializeField] Color _checkedColor;
[SerializeField] ToggleButtonGroup _group;
[SerializeField]
public bool Checked
{
get
{
return _checked;
}
set
{
if (_checked != value)
{
_checked = value;
UpdateVisual();
CheckedChanged.Invoke(this);
}
}
}
void Start()
{
_image = GetComponent<Image>();
_originalColor = _image.color;
if (_group != null)
_group.RegisterToggle(this);
}
private void UpdateVisual()
{
_image.color = Checked ? _checkedColor : _originalColor;
}
public void OnPointerClick(PointerEventData eventData)
{
Checked = !Checked;
}
[Serializable]
public class ToggleEvent : UnityEvent<ToggleButton>
{
}
}
ToggleButtonGroup.cs
using System.Collections.Generic;
using UnityEngine;
public class ToggleButtonGroup : MonoBehaviour
{
List<ToggleButton> _toggles = new List<ToggleButton>();
public void RegisterToggle(ToggleButton toggle)
{
_toggles.Add(toggle);
toggle.CheckedChanged.AddListener(HandleCheckedChanged);
}
void HandleCheckedChanged(ToggleButton toggle)
{
if (toggle.Checked)
{
foreach (var item in _toggles)
{
if (item.GetInstanceID() != toggle.GetInstanceID())
{
item.Checked = false;
}
}
}
}
}

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.

How do I fix this Idle-Car Game Script

I am trying to have a game, in which everyone can buy cars (and I save that data to playerprefs). So I have 9 trails for the cars in my game and I am trying to write some code so that when you press a button the car & the trail for that car will show up.
When the button next to it is clicked, it saves that data so when people restart the game, they will still have the car & trail open and won't need to press the button again.
Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine; using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public Button[] TrailLevel;
public GameObject[] Cars, Trails;
public Text text;
public int CurrentCarToSpawn = 0;
private void Start()
{ }
private void FixedUpdate()
{
UpdateCar();
}
public void InstantiateCar()
{
TrailLevel[CurrentCarToSpawn].gameObject.active = false;
MineLevel[CurrentCarToSpawn+1].interactable = true;
PlayerPrefs.SetInt("TrailCountA", PlayerPrefs.GetInt("TrailCountA") + 1);
PlayerPrefs.Save();
CurrentCarToSpawn++;
UpdateCar();
}
void UpdateCar()
{
int TrailCountA= PlayerPrefs.GetInt("TrailCountA", 1);
for (int i = 0; i < TrailLevel.Length; i++)
{
if (i + 1 > TrailCountA)
{
TrailLevel.interactable = false;
}
if (TrailLevel.interactable)
{
Trains[CurrentCarToSpawn].gameObject.active = true;
Mines[CurrentCarToSpawn].gameObject.active = true;
}
}
text.text = PlayerPrefs.GetInt("TrailCountA").ToString();
}
}
From what I can see with your code, this is how I would approach it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine; using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public Button[] TrailLevel;
public GameObject[] Cars, Trails;
public Text text;
public int CurrentCarToSpawn = 0;
private void Start()
{
// Load the current car. ADDED
CurrentCarToSpawn = PlayerPrefs.getInt("savedSelection", 0);
// Since we are loading the last selection, we need to call our
// instantiation method so it can activate the appropriate
// GameObjects.
InstantiateCar();
}
private void FixedUpdate()
{
UpdateCar();
}
public void InstantiateCar()
{
TrailLevel[CurrentCarToSpawn].gameObject.active = false;
MineLevel[CurrentCarToSpawn+1].interactable = true;
PlayerPrefs.SetInt("TrailCountA", PlayerPrefs.GetInt("TrailCountA") + 1);
// Save that this is our current selection.
PlayerPrefs.SetInt("savedSelection", CurrentCarToSpawn);
PlayerPrefs.Save();
CurrentCarToSpawn++;
UpdateCar();
}
void UpdateCar()
{
int TrailCountA= PlayerPrefs.GetInt("TrailCountA", 1);
for (int i = 0; i < TrailLevel.Length; i++)
{
if (i + 1 > TrailCountA)
{
TrailLevel.interactable = false;
}
if (TrailLevel.interactable)
{
Trains[CurrentCarToSpawn].gameObject.active = true;
Mines[CurrentCarToSpawn].gameObject.active = true;
}
}
text.text = PlayerPrefs.GetInt("TrailCountA").ToString();
}
}

An Unity3D button appears to be null while trying to disable it

What I'm trying to do is disable the button when the time is up. But I get an error while I set the button to be disable: it appears to be null.
The following script (RightButton.cs) includes a function called DisableButton that is invoked by the main script (TappingEngine.cs).
The statement that hangs inside the DisableButton function is btn.interactable = false;.
/* RightButton.cs */
using UnityEngine;
using UnityEngine.UI;
public class RightButton : MonoBehaviour {
Button btn;
// Use this for initialization
void Start () {
Debug.Log("Right button ready.");
}
public void Tap()
{
Debug.Log("Tap right! tot: " + TappingEngine.te.nTaps);
TappingEngine.te.Tap(TappingEngine.tapType_t.right);
}
public void DisableButton()
{
btn = this.GetComponent<Button>();
btn.interactable = false;
}
}
The following code is a part of the main script (which is quite long). However, someone advised me to post the full version for clarity.
(Focus on the two functions Update () and DisableButtons().)
/* TappingEngine.cs */
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class TappingEngine : MonoBehaviour {
public static TappingEngine te;
public int nTaps = 0;
public int GlobalTotal;
public int RightTaps;
public int LeftTaps;
public string FirstTap;
public int LastTap;
public int MaxChain;
public int FastestTwoTaps;
public int FastestTwoChainedTaps;
public GlobalTotalTaps GlobalTotalTaps_script;
public TotalRightTaps RightTotalTaps_script;
public TotalLeftTaps LeftTotalTaps_script;
public FirstTap FirstTap_script;
public RightButton RightButton_script;
const float TimeSpan = 5F;
public float Chrono;
public bool ChronoStart = false;
public bool ChronoFinished = false;
public float ElapsedPercent = 0F;
public enum tapType_t { right, left };
// Use this for initialization
void Start () {
GlobalTotal = 0;
te = this;
GlobalTotalTaps_script = FindObjectOfType(typeof(GlobalTotalTaps)) as GlobalTotalTaps;
RightTotalTaps_script = FindObjectOfType(typeof(TotalRightTaps)) as TotalRightTaps;
LeftTotalTaps_script = FindObjectOfType(typeof(TotalLeftTaps)) as TotalLeftTaps;
FirstTap_script = FindObjectOfType(typeof(FirstTap)) as FirstTap;
RightButton_script = FindObjectOfType(typeof(RightButton)) as RightButton;
}
// Update is called once per frame
void Update () {
if(ChronoStart) {
ElapsedPercent = (Time.time - Chrono) * 100 / TimeSpan;
if(ElapsedPercent >= 100F) {
DisableButtons();
//SceneManager.LoadScene("Conclusion", LoadSceneMode.Single);
}
}
Debug.Log("Elapsed time: " + (Time.time - Chrono));
}
private void DisableButtons()
{
RightButton_script.DisableButton();
}
public void OnTap() {
Debug.Log("Tap!");
}
public void Tap(tapType_t tapType) {
Manage_GlobalTotalTaps();
if(GlobalTotal == 1) {
Manage_FirstTap(tapType);
ChronoStart = true;
Chrono = Time.time;
}
Manage_LeftRight(tapType);
}
private void Manage_FirstTap(tapType_t tapType)
{
FirstTap = tapType.ToString();
FirstTap_script.FastUpdate();
}
private void Manage_LeftRight(tapType_t tapType)
{
if (tapType.Equals(tapType_t.left))
{
LeftTaps++;
LeftTotalTaps_script.FastUpdate();
}
else
{
RightTaps++;
RightTotalTaps_script.FastUpdate();
}
}
public void Manage_GlobalTotalTaps() {
GlobalTotal++;
GlobalTotalTaps_script.FastUpdate();
}
}
Below are a couple of screenshots that I hope will be useful.
Until now I have not yet figured out where the problem is. Moreover, the script of the button is very similar to that of the various Text objects that represent the statistics (the list on the right side of the screen).
With Text objects it works, with the Button object not.
I asked the same question on Unity3D Forum and I got the solution here.
One the game object where I attached the RightButton.cs there is a variable on line 24 Button btn; that needs to be set to public, so public Button btn;.
This makes appearing a new entry in the Inspector of the Right Button object (see the image below) and so in Unity3D drag and drop the Right Button GameObject into Right Button (Script)'s proper field (Btn in this case).

Categories