Unity animation from foreach loop c# - c#

I have a UI text that I update in script off camera then uses an animation to have it slide across the screen. The script uses a foreach loop since the text change and number of times the animation runs are variable. It always skips the third animation (it will print the effect in console but will not play that animation), even when 4 or 5 effects are called.
private Animation Anim;
public Text NBtext;
public GameObject NBEffect, Tut, TouchInput;
public IEnumerator NiceBowlingEffects(List<string> Effects, bool FirstFrame)
{
Anim = GetComponent<Animation>();
NBEffect.SetActive(true);
yield return new WaitForSeconds(.2f); //give frame ect a chance to load.
foreach (var Effect in Effects)
{
NBtext.text = Effect;
Print(Effect);
Anim.Play();
yield return new WaitForSeconds(Anim.clip.length);
}
NBEffect.SetActive(false);
if (FirstFrame)
{
Tut.SetActive(true);
}
TouchInput.SetActive(true);
}

try changing "WaitForSeconds" to "WaitForSecondsRealtime" in the foreach loop, and tell me if it fixed it

Hopefully this helps someone but to finally get this to work for Nice Bowling I had to add a time delay between changing the text and playing the animation. Here's the code that's running on Nice Bowling right now.
public IEnumerator NiceBowlingEffects(List<string> Effects, bool FirstFrame)
{
Anim = GetComponent<Animation>();
NBEffect.SetActive(true);
yield return new WaitForSecondsRealtime(.1f); //give frame ect a chance to load.
foreach (var Effect in Effects)
{
NBtext.text = Effect;
yield return new WaitForSecondsRealtime(.1f); //text time to change
Anim.Play();
yield return new WaitForSecondsRealtime(Anim.clip.length +.01f);
}
NBEffect.SetActive(false);
if (FirstFrame)
{
Tut.SetActive(true);
Tut.GetComponent<UISprite>().Trigger();
}
TouchInput.SetActive(true);
}

Related

I want to activate a same animation for few different objects trough FOR loop. Animation don't sync and go in random intervals. Here is the code:

So, firstly, my scene is made out of 9 empty objects each one having spikes that have animation to pop out of the floor. I am making a game where you should avoid spikes and other projectiles. I tested this first with sprite renderer and changing colors, it worked perfectly. But when I want to activate animations using trigger (animations start from empty game state and go to their animations, then after it finishes they return to normal). I've looked trough every thing I could think of and I could not solve this. It always starts animations for 4-6 different animations and start them at the same time, but for some reason: AFTER FIRST SHOWING, every single time after first time spikes appear, 2/3 out of 4/6 always show late but start at same time. Weirdly first time it always works greatly. Any thoughts on what may cause this?
void Update()
{
if (spikeTimer > 0)
spikeTimer -= Time.deltaTime;
if (spikeTimer<0)
{
Function();
spikeTimer = spikeCooldown;
}
}
public void Function()
{
int x = Random.Range(4, 6);
List<int> included = new List<int>();
while (included.Count < x)
{
int y = Random.Range(1, 10);
if (!included.Contains(y))
{
included.Add(y);
}
}
foreach (int i in included)
{
print("aktiviran je broj" + i);
Spikes[i - 1].GetComponent<Spike>().ActivateSpike();
}
}
Now this is the ActivateSpike method that all Spikes in the scene contain
public void ActivateSpike()
{
SpriteRenderer sr = gameObject.GetComponent<SpriteRenderer>();
if (sr.color != Color.black)
{
sr.color = Color.black;
}
else
sr.color = Color.red;
/* Animator animator = gameObject.GetComponent<Animator>();
animator.SetTrigger("Activate");*/
}
You can see that I tried changing the sprite to square and changing its color, and it works perfectly...

How can make it so only 1 object of type "Ability" can be selected at once?

I am making an ability system in my game and am running into a few issues. I have set up a script that tells me which "ability" is closest to my cursor and changes the animation state if it is. With one of my abilities, the debug screen says "The closest ability is A" (which works) if selected, but if my cursor is closer to another, it says "The closest ability is A" followed by "The closest ability is B". This is screwing up my animations by triggering selected on both objects when only one should be selected. Where i my code is making this problem occur and how can I fix it so that only 1 ability can be selected at a time.
Thanks in advance!
Closest to cursor script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AtMouseCursor : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
ClosestAbility();
Vector2 cursorPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
transform.position = cursorPos;
}
void ClosestAbility()
{
float distanceToClosestAbility = Mathf.Infinity;
Ability closestAbility = null;
Ability[] allAbilities = GameObject.FindObjectsOfType<Ability>();
foreach (Ability currentAbility in allAbilities)
{
float distanceToAbility = (currentAbility.transform.position - this.transform.position).sqrMagnitude;
if (distanceToAbility < distanceToClosestAbility)
{
distanceToClosestAbility = distanceToAbility;
closestAbility = currentAbility;
UnityEngine.Debug.Log("The Closest Ability is " + closestAbility.name);
}
}
foreach (Ability currentAbility in allAbilities)
{
if (currentAbility != closestAbility)
{
currentAbility.GetComponent<Ability>().AbilityNotSelected();
}
else if (currentAbility == closestAbility)
{
currentAbility.GetComponent<Ability>().AbilitySelected();
}
}
}
}
Ability Script (Goes on ability prefabs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ability : MonoBehaviour
{
public Animator anim;
void Start()
{
anim = GetComponent<Animator>();
}
public void AbilitySelected()
{
UnityEngine.Debug.Log("Bruh im selscted");
anim.SetBool("isSelected", true);
}
public void AbilityNotSelected()
{
anim.SetBool("isSelected", false);
}
}
You just need to move your Log statement outside [after] the first loop. You won't know that it's actually the closest ability until you've checked all of them.
(And maybe add a check that allAbilities isn't null or empty.)
Update 1:
ClosestAbility() uses this.transform.position but Update() calls ClosestAbility() before updating said transform position. This looks like it would probably cause you to animate the ability closest to the old mouse position rather than the current mouse position. But it may not be noticeable if it's called every frame.
Update 2:
Code I had in mind:
void ClosestAbility()
{
float distanceToClosestAbility = Mathf.Infinity;
Ability closestAbility = null;
Ability[] allAbilities = GameObject.FindObjectsOfType<Ability>();
if ((allAbilities == null) || (allAbilities.Length == 0))
{
return;
}
foreach (Ability currentAbility in allAbilities)
{
float distanceToAbility = (currentAbility.transform.position - this.transform.position).sqrMagnitude;
if (distanceToAbility < distanceToClosestAbility)
{
distanceToClosestAbility = distanceToAbility;
closestAbility = currentAbility;
UnityEngine.Debug.Log(closestAbility.name + " is close, but there might be an ability that's closer still");
}
}
UnityEngine.Debug.Log("I checked all the abilities and " + closestAbility.name + " is the closest");
foreach (Ability currentAbility in allAbilities)
{
if (currentAbility != closestAbility)
{
currentAbility.GetComponent<Ability>().AbilityNotSelected();
}
else if (currentAbility == closestAbility)
{
currentAbility.GetComponent<Ability>().AbilitySelected();
}
}
UnityEngine.Debug.Log("Finished updating all the animations without any exceptions");
}
Update 3: I'm completely unfamiliar with Unity, but since currentAbility is an Ability, I wonder if the call to currentAbility.GetComponent<Ability>() is unnecessary at best and you could/should just have currentAbility.AbilityNotSelected()? Though if your animations ever turn on it must work at least some of the time, maybe. Still, I'd check if the GetComponent call is returning what you think it's returning.
UnityEngine.Debug.Log("The Closest Ability is " + closestAbility.name);
You are calling this for each ability in the list consecutively. So,
if (distanceToAbility < distanceToClosestAbility)
can be true two or more times in your initial foreach loop. The loop itself is fine. Just use
UnityEngine.Debug.Log("I checked all the abilities and " + closestAbility.name + " is the closest");
this code from IceGlasses code after your first foreach loop to log the closest ability.
The first main problem seems to be the calling
ClosestAbility();
before updating cursorPos and transform.position. This causes ClosestAbility function to use the transform.position value of the previous frame.
The second problem seems to be calling ClosestAbility function at every frame. So if one of the ability animations take longer than a frame and you move your cursor closer to another ability the second ability will also be triggered.
Unless you stop the first animation when the second animation starts playing OR unless you call ClosestAbility function if none of the animations are playing 2 or more animations can play at the same time.

WaitForSeconds() Coroutine causes Game to freeze Indefinitely (Edited)

I have a game with four scenes, a menu scene, a loading scene, and two game scenes. All is well, when I am transitioning from my menu scene to my game scenes, but whenever I transition from my game scenes back to my menu scene or reload the game scene, the loading scene simply stops responding. I get a warning message that says "NetworkManager detected a script reload in the editor. This has caused the network to be shut down" only when I try to reload the currently active game scene. This issue is also present when I play in the build! I used print statements to trace down where my code stopped running, and I figured out that it was the Yield Return New WaitForSeconds() which caused the game to freeze. Why is that?
I have two scripts that controls transitioning. One simple script called on UIButtons for telling the second more complex script called in the preload scene to load the scene it's supposed to load and create animations. I have made sure that I was loading on to the correct scene, and that all of the scenes were added into my build settings.
The following pictures show the loading scene not responding. The first picture shows what happens when I try to reload the current game scene, and the second picture shows what happens when I try to load the menu scene:
My Loading Scene Script:
public class LoadingScreenManager : MonoBehaviour {
[Header("Loading Visuals")]
public Image loadingIcon;
public Image loadingDoneIcon;
public Text loadingText;
public Image progressBar;
public Image fadeOverlay;
[Header("Timing Settings")]
public float waitOnLoadEnd = 0.25f;
public float fadeDuration = 0.25f;
[Header("Loading Settings")]
public LoadSceneMode loadSceneMode = LoadSceneMode.Single;
public ThreadPriority loadThreadPriority;
[Header("Other")]
// If loading additive, link to the cameras audio listener, to avoid multiple active audio listeners
public AudioListener audioListener;
AsyncOperation operation;
Scene currentScene;
public static int sceneToLoad = -1;
// IMPORTANT! This is the build index of your loading scene. You need to change this to match your actual scene index
static int loadingSceneIndex = 1;
public static void LoadScene(int levelNum) {
Application.backgroundLoadingPriority = ThreadPriority.High;
sceneToLoad = levelNum;
SceneManager.LoadScene(loadingSceneIndex);
}
void Start() {
if (sceneToLoad < 0)
return;
fadeOverlay.gameObject.SetActive(true); // Making sure it's on so that we can crossfade Alpha
currentScene = SceneManager.GetActiveScene();
StartCoroutine(LoadAsync(sceneToLoad));
}
private IEnumerator LoadAsync(int levelNum) {
ShowLoadingVisuals();
yield return null;
FadeIn();
StartOperation(levelNum);
float lastProgress = 0f;
// operation does not auto-activate scene, so it's stuck at 0.9
while (DoneLoading() == false) {
yield return null;
if (Mathf.Approximately(operation.progress, lastProgress) == false) {
progressBar.fillAmount = operation.progress;
lastProgress = operation.progress;
}
}
if (loadSceneMode == LoadSceneMode.Additive)
audioListener.enabled = false;
ShowCompletionVisuals();
//THE PRINT STATEMENT WORKS FINE RIGHT HERE! The value of waitOnLoadEnd is only 1
yield return new WaitForSeconds(waitOnLoadEnd);
//THE PRINT STATEMENT STOPS RUNNING RIGHT HERE!
FadeOut();
yield return new WaitForSeconds(fadeDuration);
if (loadSceneMode == LoadSceneMode.Additive)
SceneManager.UnloadScene(currentScene.name);
else
operation.allowSceneActivation = true;
}
private void StartOperation(int levelNum) {
Application.backgroundLoadingPriority = loadThreadPriority;
operation = SceneManager.LoadSceneAsync(levelNum, loadSceneMode);
if (loadSceneMode == LoadSceneMode.Single)
operation.allowSceneActivation = false;
}
private bool DoneLoading() {
return (loadSceneMode == LoadSceneMode.Additive && operation.isDone) || (loadSceneMode == LoadSceneMode.Single && operation.progress >= 0.9f);
}
void FadeIn() {
fadeOverlay.CrossFadeAlpha(0, fadeDuration, true);
}
void FadeOut() {
fadeOverlay.CrossFadeAlpha(1, fadeDuration, true);
}
void ShowLoadingVisuals() {
loadingIcon.gameObject.SetActive(true);
loadingDoneIcon.gameObject.SetActive(false);
progressBar.fillAmount = 0f;
loadingText.text = "LOADING...";
}
void ShowCompletionVisuals() {
loadingIcon.gameObject.SetActive(false);
loadingDoneIcon.gameObject.SetActive(true);
progressBar.fillAmount = 1f;
loadingText.text = "LOADING DONE";
}
}
Script on UIButtons that call the above script:
public class LoadingSceneButton : MonoBehaviour {
public void LoadSceneWithLoadingScreen(int sceneNumber){
if (sceneNumber < 0 || sceneNumber >= SceneManager.sceneCountInBuildSettings) {
Debug.LogWarning ("Can't Load Scene, because It Doesn't Exist!");
}
LoadingScreenManager.LoadScene (sceneNumber);
}
}
(1) Don't use "print", please use this:
Debug.Log("fadeDuration is ....... " , fadeDuration.ToString("f4");
add that line of code just before you call FadeOut and also please add it inside FadeOut
(2) problems with CrossFadeAlpha
Please note that CrossFadeAlpha is extremely difficult to use! It's a real pain! It only works on UnityEngine.UI.Graphic, and it's tricky when used with coroutines.
public static void FadeOut(this Graphic g)
{
g.GetComponent<CanvasRenderer>().SetAlpha(1f);
g.CrossFadeAlpha(0f,.15f,false);
}
(3) problems with loading a scene in Unity5 !!!
Yes there is a
known issue
where it gets stuck on 0.9. Maybe this is the main problem at hand.
check out ... http://answers.unity3d.com/answers/1146173/view.html
and ... http://answers.unity3d.com/answers/1073667/view.html
Some basic working code example....
public void LaunchSoundboard()
{
StartCoroutine(_soundboard());
}
private IEnumerator _soundboard()
{
Grid.music.Duck();
yield return new WaitForSeconds(.2f);
AsyncOperation ao;
ao = UnityEngine.SceneManagement
.SceneManager.LoadSceneAsync("YourSceneName");
while (!ao.isDone)
{
yield return null;
}
// here, the new scene IS LOADED
SoundBoard soundBoard = Object.FindObjectOfType<SoundBoard>();
if(soundBoard==null) Debug.Log("WOE!");
soundBoard.SomeFunctionInSoundboardScript();
}
Note that you wait on ".isDone", rather than watch the float.
(4) #You actually have to have a scene called "preload", which ONLY preloads.
unfortunately the menu scene can not be your preload scene.
You have to actually have a separate preload scene which does nothing but that, "preload".
Note that any "game managers" you have must be on the preload scene. It's a bit annoying but that's how it is.
The purpose of the "preload" scene is to hold any game managers you have.
The only scene that you mark "don't destroy on load" must be only the "preload" scene. It's that simple.
It's a bit of a nuisance but very simple and reliable.

Unity, C#: Delay on function not working? Waitforseconds?

I am creating a VR app using Google Cardboard in Unity and I have succeeded in switching from VR to a normal view with this function:
public GameObject[] cardboardObjects;
public GameObject[] monoObjects;
public bool switched = false;
// Turn on or off VR mode
void ActivateVRMode(bool goToVR) {
foreach (GameObject cardboardThing in cardboardObjects) {
cardboardThing.SetActive(goToVR);
}
foreach (GameObject monoThing in monoObjects) {
monoThing.SetActive(!goToVR);
}
Cardboard.SDK.VRModeEnabled = goToVR;
// Tell the game over screen to redisplay itself if necessary
//gameObject.GetComponent<GameController>().RefreshGameOver();
}
I then call this function on a button to switch to mono view:
public void Switch() {
ActivateVRMode(false);
switched = true;
Debug.Log (switched+"No VR!");
}
I then want to have the mono view on a timer, as in once the user switches to non-VR mode it remains in that for only a set amount of time (3 seconds or so) before switching back to VR.
I tried to do this by flipping a boolean and using WaitForSeconds, however the view remains in mono view and nothing happens:
IEnumerator Switchback()
{
yield return new WaitForSeconds(3);
ActivateVRMode(true);
switched = false;
Debug.Log (switched+"VR!");
}
void Update () {
if (switched == true) {
Switchback ();
}
//Debug.Log ("updating");
}
What am I doing wrong here?
You have forgotten to call the Switchback function as a Coroutine
Instead of calling Switchback() you need to call StartCoroutine(Switchback()) in your Update() function.

Return Gameobject to original position

I am using Unity for my project. What I am trying to do is when a button is pressed it moves a game object to a new position. Then when the same button is press again, the object returns to its original position.
My problem is with the while loop I am using; it just crashes Unity when I press this button. Am I using the while loop wrong or is there a better way of going about this?
Here is what I have so far:
public Gameobject TroubleMove;
public Gameobject TroubleAnchor;
public Gameobject TroubleMain;
public Gameobject CauseMain;
public Gameobject Cause;
public int OnOff = 1;
public void Change ()
{
switch (OnOff)
{
Case 1:
CauseMain.setActive (true);
Cause.setActive (true);
While (CauseMain == true)
{
CauseMove.transform.position = CauseAnchor.tranform.position;
}
OnOff += 1;
break;
Case 2:
CauseMain.setActive (false);
Cause.setActive (false);
OnOff _=1;
break;
}
}
I assume CauseMain is never being set to false and your while loop never exits.
Why do you need the while loop? Don't you want to change the cursor once? I would change while to if()
I will assume that the Change() is called in the OnClick() method.
Firsly, you should not use a while(true) loop when waiting for a user input or response. The while(true) loop will become a never ending loop and crash Unity / Device.
I am confuse with what your GameObjects really are but instead of while(true) loop, you should be using the Update() or FixedUpdate() method to transform the position (can be in relation to Time.DeltaTime). If I am not mistaken, this would be the skeleton of what could be done:
void Update () {
if(CauseMain) {
//TODO: Apply Transformation Changes
CauseMove.transform.position = CauseAnchor.tranform.position;
CauseMain = false;
}
}
This code snippet will only apply the transformation change whenever the player presses a button and once the position is set to "CauseMove", the check is disabled preventing an endless loop which will crash Unity.

Categories