in my code theres this error
Assets/TextChangeScript.cs(14,29): error CS1525: Unexpected symbol (', expecting,', ;', or='
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TextChangeScript : MonoBehaviour
{
public Text m_MyText;
public Text OtherText;
void Start()
{
m_MyText.text = "There was once a mother and her child";
yield WaitForSeconds (3);
m_MyText.text = "The mother loved her child very dearly";
}
}
You are trying to call yield WaitForSeconds in a function that doesn't return an IEnumerator. You need to create a new function that returns IEnumerator and call it with StartCoroutine.
The code after the yield will be executed.
You can check the documentation. Unity is well documented.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class WaitForSecondsExample : MonoBehaviour
{
public Text m_MyText;
public Text OtherText;
void Start()
{
StartCoroutine(Example());
}
IEnumerator Example()
{
m_MyText.text = "There was once a mother and her child";
yield return new WaitForSeconds(3);
m_MyText.text = "The mother loved her child very dearly";
}
}
Use a Coroutine, Unity is well documented on how they work and you can use the link in Chopi's answer.
Now to avoid any confusion, normally in a function you will want a return to be the last call in your function as code behind it typically does not get called. This is not the case for an IEnumerator.
The line yield return new WaitForSeconds(3); returns an expression from a function and is used as a place to mark where execution is to continue, in this case in 3 seconds at that line.
Your start method is not an IEnumerator, and as far as I am tracking there isn't a way to yield in your start in Unity. You can start a coroutine in start and have that coroutine yield. Here is an example of a coroutine that will give you, your 3 second delay between your text:
using UnityEngine;
using UnityEngine.UI;
public class TextChangeScript : MonoBehaviour
{
public Text m_MyText;
public Text OtherText;
IEnumerator StoryText() {
m_MyText.text = "There was once a mother and her child";
yield return new WaitForSeconds (3);
m_MyText.text = "The mother loved her child very dearly";
yield return new WaitForSeconds (3);
m_MyText.text = "Then one day blah blah blah";
}
void Start()
{
StartCoroutine(StoryText());
}
void Update()
{
}
}
Here is an example of using a for loop to loop through text with a 3 second delay between them:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TextChangeScript : MonoBehaviour
{
public Text m_MyText;
public List<string> storyText;
IEnumerator StoryText() {
foreach (string sz in storyText)
{
text.text = sz;
yield return new WaitForSeconds(3); // in 3 seconds. execution will begin here and iterate to the next string in the storyText.
}
}
void Start()
{
StartCoroutine(StoryText());
}
void Update()
{
}
}
Edit:
Thanks to what R1PFake shared in the comments you can also do this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CenterName : MonoBehaviour {
public Text text;
public List<string> storyText;
// Use this for initialization
IEnumerator Start () {
foreach (string sz in storyText)
{
text.text = sz;
yield return new WaitForSeconds(3);
}
}
}
Related
I tried to make it so that it will change to the next scene after 3 seconds, but I will only get an error9 (Error photo). I added a code sample.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class ChangeSceneAfterThreeSeconds : MonoBehaviour
{
public void Start()
{
StartCoroutine("LoadSceneThing");
}
public IEnumerator LoadSceneThing(string sceneToChange)
{
yield return new WaitForSeconds(3);
SceneManager.LoadScene(sceneToChange);
}
}
just replace StartCoroutine("LoadSceneThing"); by StartCoroutine(LoadSceneThing("scene name"));
I'm trying to set up a dash ability that updates the player velocity, waits a set amount of time (dashTime) and then sets the canDash to false for another set amount of time (dashCooldown).
However the waitForSeconds don't seem to be working as the canDash bool only remains false for a split second before switching back to true.
PlayerAbilities.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerAbilities : MonoBehaviour
{
// Scripts & Data
[SerializeField] PlayerController s_PC;
internal PlayerData pd = new PlayerData();
private void Awake() {
pd.canDash = true;
}
// Dash
internal IEnumerator Dash()
{
pd.CanDash = false;
Debug.Log("dash, dash baby");
// Perform dash and update canDash
s_PC.rb2d.velocity = s_PC.s_PlayerMovement.moveInput * pd.dashSpeed;
yield return new WaitForSeconds(pd.dashTime); // Wait set time for dash to happen
s_PC.UpdateState(PlayerController.State.Normal); // Change state back to normal
// Cooldown dash
yield return new WaitForSeconds(pd.dashCooldown); // Cooldown dash
pd.CanDash = true;
}
}
PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// Scripts & Data
[SerializeField] internal PlayerAbilities s_PlayerAbilities;
[SerializeField] internal PlayerInput s_PlayerInput;
internal PlayerData pd = new PlayerData();
// Update is called once per frame
private void FixedUpdate()
{
// Check if user has control of player
if (pd.canControlPlayer)
{
// Update player state
switch (playerState)
{
case State.Normal:
s_PlayerMovement.Move();
break;
case State.Dash:
StartCoroutine(s_PlayerAbilities.Dash());
break;
case State.DodgeRoll:
StartCoroutine(s_PlayerAbilities.DodgeRoll());
break;
}
}
}
}
PlayerData.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
[Serializable]
public class PlayerData
{
// Dash
internal float dashSpeed = 50f;
internal float dashTime = 0.2f;
internal float dashCooldown = 5f;
internal bool canDash = true;
internal bool CanDash {
get { return canDash; }
set { canDash = value; }
}
}
PlayerInput.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerInput : MonoBehaviour
{
// Scripts & Data
[SerializeField] PlayerController s_PC;
internal PlayerData pd = new PlayerData();
// Input Actions
internal PlayerInputActions playerInputActions;
private void Awake() {
// Define new player input
playerInputActions = new PlayerInputActions();
}
private void Update()
{
// Check if player state is normal
if (s_PC.playerState == PlayerController.State.Normal)
{
// Check for button presses
if (playerInputActions.Movement.DodgeRoll.triggered)
s_PC.UpdateState(PlayerController.State.DodgeRoll);
}
}
}
The code is so unnecessarily complicated, you're just making one of a zillion simple mistakes somewhere
Follow normal debugging.
To begin with change this
yield return new WaitForSeconds(pd.dashCooldown);
to this
Debug.Log("test with number");
yield return new WaitForSeconds(20f);
Debug.Log("tested with number");
and go from there.
BTW there's something completely wrong at FixedUpdate(). For some reason you're call Dash (and others) every frame. That seems totally wrong. You'd call that sort of thing once on key down.
ALSO:
You've probably suffered this Gotchya:
https://stackoverflow.com/a/35166004/294884
due to all the bizarre variables.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
public class CompareObjects : MonoBehaviour
{
public float waitTime;
private GameObject[] allObjects;
public void Compare()
{
allObjects = FindObjectsOfType<GameObject>();
foreach (GameObject go in allObjects)
{
Debug.Log(go.name + " >>>>> " + go.scene.name + " >>>>> is active object");
StartCoroutine(Comparing());
}
}
IEnumerator Comparing()
{
yield return new WaitForSeconds(waitTime);
}
}
The idea is not to choke the whole editor and wait for the foreach loop to finish, but to make that it will loop over the first item wait a second then will continue to the next and so on.
The way it is now it's choking the editor, freezing it until the loop is over.
What I did so far and it's not working good yet :
I created a new editor script for a button in the inspector :
using UnityEngine;
using System.Collections;
using UnityEditor;
[CustomEditor(typeof(CompareObjects))]
public class CompareObjectsButton : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
CompareObjects myTarget = (CompareObjects)target;
if (GUILayout.Button("Compare Objects"))
{
myTarget.StartComparing();
}
}
}
Then in Compare Objects :
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
public class CompareObjects : MonoBehaviour
{
public float waitTime;
private Coroutine comparer;
private GameObject[] allObjects;
public void StartComparing()
{
if (comparer == null)
{
comparer = StartCoroutine(Compare());
}
}
public void StopComparing()
{
if (comparer != null)
{
StopCoroutine(comparer);
comparer = null;
}
}
IEnumerator Compare()
{
while (true)
{
allObjects = FindObjectsOfType<GameObject>();
foreach (GameObject go in allObjects)
{
Debug.Log(go.name + " >>>>> " + go.scene.name + " >>>>> is active object");
yield return new WaitForSeconds(waitTime);
}
}
}
}
But it's doing only one object and not all the objects.
StartCoroutine kind of acts in the same manner as starting a new thread, so when you call Compare all you are doing is looping through the game objects and creating event objects which, while running in the main thread, don't prevent the method which created it from running, so ultimately only the new event object waits the specified time while the main method continues to loop through the rest of the game objects and creating more event objects, sins it itself isn't calling any sleep functions, instead you should do something like this:
public void StartComparing()
{
if (comparer == null)
{
comparer = StartCoroutine(Compare());
}
}
public void StopComparing()
{
if (comparer != null)
{
StopCoroutine(comparer);
comparer = null;
}
}
IEnumerator Compare()
{
while (true)
{
allObjects = FindObjectsOfType<GameObject>();
foreach (GameObject go in allObjects)
{
Debug.Log(go.name + " >>>>> " + go.scene.name + " >>>>> is active object");
yield return new WaitForSeconds(waitTime);
}
}
}
private Coroutine comparer;
private GameObject[] allObjects;
public float waitTime;
StartComparing will start a coroutine of Compare which will go through all the objects, so, first object then wait the specified waitTime then the second object and so on, this is done until StopComparing is called.
Tested the code, here is a small (literally) preview of it, you will see that after changing the speed it logs the objects slower:
I'm trying to do a 2D platformer with a deaths counter, but I'm facing a problem.
Here is the script I attached to a 3D Text:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DeathCounter : Respawn
{
public Text DeathCount;
public void SetText(int text)
{
string deathsS = deaths.ToString();
DeathCount.text = deathsS;
}
}
And it does nothing.
I'm asking for help please.
What do I do ?
Here is the "Respawn" script, if needed:
using System.Collections;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
using UnityEngine;
public class Respawn : MonoBehaviour
{
public int deaths;
private Scene scene;
void Start()
{
scene = SceneManager.GetActiveScene();
}
void OnCollisionEnter2D(Collision2D col)
{
if(col.transform.CompareTag("Player"))
{
deaths = deaths + 1;
Debug.Log("You are dead");
System.Threading.Thread.Sleep(500);
SceneManager.LoadScene(0);
}
}
}
Thanks a lot for your help !
Have a nice day.
First thing I would do is remove the inheriting of Respawn from your DeathCounter class since it's not extending the functionality of Respawn. I would then set the function to use the passed in parameter to set the text value instead.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DeathCounter : MonoBehaviour
{
public Text DeathCount;
public void SetText(String text)
{
DeathCount.text = "Death Count: " + text;
}
}
Then, in your other class when doing your collision check you can pass the death count value as what to set your DeathCount text to.
using System.Collections;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
using UnityEngine;
public class Respawn : MonoBehaviour
{
public int deaths;
//Reference to your DeathCounter script
public DeathCounter dCounter;
private Scene scene;
void Start()
{
scene = SceneManager.GetActiveScene();
}
void OnCollisionEnter2D(Collision2D col)
{
if(col.transform.CompareTag("Player"))
{
deaths = deaths + 1;
//New line here, with passed in script for updating as a reference
dCounter.SetText(deaths.ToString());
Debug.Log("You are dead");
System.Threading.Thread.Sleep(500);
SceneManager.LoadScene(0);
}
}
}
Edit: One script version...
using System.Collections;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Respawn : MonoBehaviour
{
public int deaths;
//Reference to your Text, dragged in via the inspector
public Text deathCount;
private Scene scene;
void Start()
{
scene = SceneManager.GetActiveScene();
}
void OnCollisionEnter2D(Collision2D col)
{
if(col.transform.CompareTag("Player"))
{
deaths = deaths + 1;
//Just update the referenced UI text
deathCount.text = "Death Count: " + deaths;
Debug.Log("You are dead");
System.Threading.Thread.Sleep(500);
SceneManager.LoadScene(0);
}
}
}
The problem
basically lies in the LoadScene:
You increase the deaths value BUT then you reload the scene → you also reload the Respawn instance and therefore deaths again will have its original value so probably 0.
You didn't even call the SetText method but even if you would when the scene is reloaded also the Text component is reloaded and will have the original text like of you hadn't called the SetText method at all.
Solution
I'm order to fix it in this case I would use
public class Respawn : MonoBehaviour
{
public static int deaths{ get; private set; }
...
if the value is static it is not bound to a certain instance of Respawn but "lives" directly in the type Respawn. Therefore it keeps its current value also when reloading the scene. The {get; private set;} turns it from a field into a property which can be read by every other class but written only by the Respawn class.
Further you never want to use something like
System.Threading.Thread.Sleep(500);
in the Unity main thread. This completely freezes the main thread and if you e.g. later add any animations etc the app will simply freeze completely. Instead use a Coroutine like
void OnCollisionEnter2D(Collision2D col)
{
if(!col.transform.CompareTag("Player")) return;
deaths += 1;
Debug.Log("You are dead");
StartCoroutine(Reload());
}
private IEnumerator Reload()
{
yield return new WaitForSeconds(0.5f);
SceneManager.LoadScene(0);
}
Finally you have to set the Text after loading the scene so it gets updated also in the reloaded scene.
public class DeathCounter : Respawn
{
public Text DeathCount;
// automatically called when scene is reloaded
private void OnEnable()
{
DeathCount.text = deaths.ToString();
}
}
Sidenote:
In Respawn you store a
scene = SceneManager.GetActiveScene();
but later never use it but instead anyway use
SceneManager.LoadScene(0);
so I would get rid of that Start method .. it only causes unnecessary overhead.
I'm in C# and I want my handgun Muzzleflash to be inactive after each shot. I keep getting error message:
"Error CS8025 Feature 'local functions' is not available in C# 4. Please use language version 7 or greater."
WHEN I fix this I still get compiler errors and can't run game. It would be highly appreciated if you could take a look at code below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunFire : MonoBehaviour
{
public GameObject Flash;
void Update()
{
if (GlobalAmmo.LoadedAmmo >= 1)
{
if (Input.GetButtonDown("Fire1"))
{
AudioSource gunsound = GetComponent<AudioSource>();
gunsound.Play();
Flash.SetActive(true);
StartCoroutine(MuzzleOff());
GetComponent<Animation>().Play("GunShot");
GlobalAmmo.LoadedAmmo -= 1;
}
}
IEnumerator MuzzleOff()
{
yield return new WaitForSeconds(0.01f);
Flash.SetActive(false);
}
}
}
MuzzleOff() method is mistakenly put within the scope of Update() method. Please move it out as separate method.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunFire : MonoBehaviour
{
public GameObject Flash;
void Update()
{
if (GlobalAmmo.LoadedAmmo >= 1)
{
if (Input.GetButtonDown("Fire1"))
{
AudioSource gunsound = GetComponent<AudioSource>();
gunsound.Play();
Flash.SetActive(true);
StartCoroutine(MuzzleOff());
GetComponent<Animation>().Play("GunShot");
GlobalAmmo.LoadedAmmo -= 1;
}
}
}
IEnumerator MuzzleOff()
{
yield return new WaitForSeconds(0.01f);
Flash.SetActive(false);
}
}