Preserving object after a reload scene - unity3d

In a scene of my quiz game I have an animation object that changes for another animation when a button to move to the next question is pressed (the button reload the scene). I would like to keep the animation, the last animation referenced to the object, after the scene is reloaded, but I don't know how. The object always returns to its normal state (the first animation).
I currently have a script called 'tower' referenced to the object where I make a static object and a DontDestroyOnLoad function:
public static SpriteRenderer towerAnimation;
void Awake()
{
DontDestroyOnLoad(gameObject);
towerAnimation = GetComponent<SpriteRenderer>();
}
And this code in the Update of 'GameManager' script:
public static int counterQuestionChances = 2;
void DestroyTower()
{
if (counterQuestionChances == 1)
{
Tower.towerAnimation.SetTrigger("error 1");
}
else
{
if (counterQuestionChances == 0)
{
Tower.towerAnimation.SetTrigger("error 2");
}
}
But it doesn't work. I'm taking shots in the dark because I don't know how to solve this. I'd appreciate if you could give me any ideas that can help me with this. Thanks!

You're going to have to use the SceneManagement library that Unity has so when the scene changes the method below called OnActiveSceneChanged gets called.
using UnityEngine.SceneManagement;
public class Tower : MonoBehaviour
{
public static SpriteRenderer towerAnimation;
public int storedCounter = 0;
void Awake()
{
DontDestroyOnLoad(gameObject);
towerAnimation = GetComponent<SpriteRenderer>();
SceneManager.activeSceneChanged += OnActiveSceneChanged;
}
private void OnActiveSceneChanged(UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.Scene currentScene)
{
//tower animation stuff here
}
}

Related

Loading a scene

I have a "Start Game" button
public static bool GameIsStart;
public void changeCamera ()
{
if (GameIsStart == true)
return;
GameIsStart = true;
SceneManager.LoadScene ("Game");
}
}
``
There is a script that I added to the Prefabs
public GameObject [] gameobject;
private bool gameobject_IS_Spawn;
private float RandomPositionforX;
private int RandomObjects;
private void Update ()
{
if (StartGame.GameIsStart &&! gameobject_IS_Spawn)
{
StartCoroutine (Spawngameobject ());
gameobject_IS_Spawn = true;
}
}
IEnumerator Spawngameobject ()
{
while (true)
{
if (StartGame.GameIsStart)
{
yield return new WaitForSeconds (1.3f);
RandomPositionforX = Random.Range (-2.28f, 2.28f);
RandomObjects = Random.Range (0, gameobject.Length);
Instantiate (gameobject [RandomObjects], new Vector2 (RandomPositionforX, 24f), Quaternion.identity);
}
}
}
}
There is a button on the "Game" scene to access the preview
public void ChangeScene ()
{
SceneManager.LoadScene ("preview");
}
}
I click on the button, the "Preview" scene is loaded, but the "Start game" button does not work.
If I put in the "Preview" button SceneManager.LoadScene ("Game")
then I restart the scene ("Game") and everything works.
But if SceneManager.LoadScene ("Preview") but the buttons don't work.
When switching between scenes, is it necessary to stop Coroutine
How can this problem be corrected?
Without seeing the code it's a bit harder to find where the problem is coming from.
The only thing that is coming to my mind is that it may be something related with how the scene is stored and loaded after.
According to the Scene Manager Documentation, you could save the scene1 in a variable and keep the DontDestroyOnLoad(scene1) on its awake method, then add something like:
Scene scene2 = SceneManager.GetActiveScene(); SceneManager.LoadScene(scene1); To the button that reloads the previous scene.

How to make button image change with on click anywhere on screen?

I am very new to Unity and I have trouble understanding on click possibilities with my UI buttons etc.. In my project, I have a button which changes its image whenever I click on it and the way I made it is: I created this script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(Button))]
public class OnClickScript : MonoBehaviour
{
public static int spritenumber=1;
public Button mybutton;
public Sprite square;
public Sprite circle;
public Sprite triangle;
public int counter = 1;
void Start()
{
mybutton = GetComponent<Button>();
}
public void changeButton()
{
if (PAUSESCRIPTE.isPaused == false)
{
counter++;
if (counter == 1)
{
mybutton.image.overrideSprite = square;
spritenumber = 1;
soundmanagerscript.PlaySound("buttonpress");
}
if (counter == 2)
{
mybutton.image.overrideSprite = circle;
spritenumber = 2;
soundmanagerscript.PlaySound("buttonpress");
}
if (counter == 3)
{
mybutton.image.overrideSprite = triangle;
spritenumber = 3;
counter = counter - 3;
soundmanagerscript.PlaySound("buttonpress");
}
}
}
}
I attached this script to my button, selected sprites which I want to use and I added on On Click() function to the button.
Afterwards I decided that I no longer want to change the sprite of my button by clicking on the button itself but rather by clicking anywhere on the screen. I tried using Input.GetMouseButtonDown(0) but got no results since I used it incorrectly. Any help on, how to achieve what I want, is very welcome. Thanks in advance.
Here's how I'd do it:
using UnityEngine.UI;
using UnityEngine;
public class ButtonScript : MonoBehaviour
{
// Public objects
public Sprite[] sprites;
//Private objects/variables
private Image buttonImage;
private int spriteIndex;
void Start()
{
buttonImage = GetComponent<Image>(); // Get the image component of your button
spriteIndex = 0; // Set the index to 0
buttonImage.sprite = sprites[spriteIndex]; // Set the image to the first image in your sprite array
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
spriteIndex++; // Increment the index
if (spriteIndex > sprites.Length - 1) // Ensure that you stay within the array size
{
spriteIndex = 0;
}
buttonImage.sprite = sprites[spriteIndex]; // Set the image
}
}
}
However, you need to change the image settings to:
Image Type: simple
Use Sprite Mesh: true
(maybe) Preserve aspect: true
As an answer to your comment above, I will suggest you to have a button in the background and your pause button above. Then, replace your Update() method with an event OnClick() as you did before.
Your pause button will catch the left click and your background button will not.
Be sure to tick Interactable in the Button component.
Then you can safly remove the Image component of your background button, if you don't need it.
What it means is you can create (or modify) a class for your pause button
using UnityEngine.EventSystems;
public class PauseButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public bool IsMouseOver = false;
public void OnPointerEnter(PointerEventData eventData)
{
IsMouseOver = true;
}
public void OnPointerExit(PointerEventData eventData)
{
IsMouseOver = false;
}
// --
// Your OnClick method
// --
}
Note: the using eventSystems.
Now you can use this bool value within a code like amengelbrecht send you.
I'll will copy and paste his code from his answer, and add the bool value based on the previous class above.
public class BackgroundButtonScript : MonoBehaviour
{
// Public objects
public Sprite[] sprites;
public PauseButton pauseButton;
//Private variables
private Image buttonImage;
private int spriteIndex;
private void Start()
{
buttonImage = GetComponent<Image>(); // Get the image component of your button
spriteIndex = 0; // Set the index to 0
buttonImage.sprite = sprites[spriteIndex]; // Set the image to the first image in your sprite array
}
private void Update()
{
if (Input.GetMouseButtonDown(0) && !pauseButton.IsMouseOver)
{
spriteIndex++; // Increment the index
if (spriteIndex > sprites.Length - 1) // Ensure that you stay within the array size
{
spriteIndex = 0;
}
buttonImage.sprite = sprites[spriteIndex]; // Set the image
}
}
}
This will allow you to click anywhere on your screen except if the mouse is over your pause button. In this case, OnClick from the pause button will be called.
Be careful
If your game is is pause and the user left click anywhere but the pause button, depends on how your pause works, the Update() method of BackgroundButtonScript will be called and can lead to if (Input.GetMouseButtonDown(0) && !pauseButton.IsMouseOver).

Gun should shoot only when button is touched instead of entire screen

I've made a 3d game and I have a first person controller, control by a joystick. I want my player to shoot only when I touch a button on the screen, but now my player shoots if I touch anything on the screen. This is the script for the shoot function:
using UnityEngine;
using UnityEngine.UI;
public class Gun : MonoBehaviour
{
public float damage = 10f;
public float range = 100f;
public Camera fpsCam;
public Button button;
// Start is called before the first frame update
void Start()
{
//Calls the TaskOnClick/TaskWithParameters/ButtonClicked method when you click the Button
button.onClick.AddListener(TaskOnClick);
}
// Update is called once per frame
void Update()
{
Vector3 forward = transform.TransformDirection(Vector3.forward) * 10;
Debug.DrawRay(transform.position, forward, Color.green);
}
void Shoot()
{
RaycastHit hit;
if( Physics.Raycast(fpsCam.transform.position, fpsCam.transform.forward, out hit, range))
{
Debug.Log(hit.transform.name);
Target target = hit.transform.GetComponent<Target>();
if(target != null)
{
target.TakeDamage(damage);
}
}
}
void OnCollisionEnter(Collision collision)
{
Debug.DrawRay(collision.contacts[0].point, collision.contacts[0].normal, Color.green, 2, false);
}
void TaskOnClick()
{
Shoot();
}
}
Your Shoot() method runs whenever you press the "Fire1" button, since the only check you are doing is if (Input.GetButtonDown("Fire1")).
If you want to depend on a button to fire you need to take this part of the code out and call Shoot() whenever you click the button.
You can add the event to the button using code, as explained here
public Button m_YourFirstButton;
void Start()
{
//Calls the TaskOnClick/TaskWithParameters/ButtonClicked method when you click the Button
m_YourFirstButton.onClick.AddListener(TaskOnClick);
}
void TaskOnClick()
{
//Output this to console when Button1 or Button3 is clicked
Debug.Log("You have clicked the button!");
}
or you could call it from the inspector by referencing your Gun monobehaviour.

Unity3D VR app: fade to another scene after a certain time

I'm trying to develop a VR app where you can move around and interact with music (moving the audio sources, and so on). So, you can't actually die in this app, which is why a fade to black on trigger wouldn't help me. I'm trying to get a fade to black and show the credits after a certain amount of time (specifically, when the music is over). Maybe even a fade out (black) and a fade in (to another scene containing the credits) would do the trick. I know very little about programming, so I could really use some help.
I'm using Unity3D 2018.2.9f1
The app is for the Samsung's Gear VR
Timer
For any stuff using timers or wait I find Coroutines most of the time the best options.
You could either get the audio clip length and than wait for it
public AudioClip clip;
private void Start()
{
StartCoroutine(Wait(clip.length));
}
private IEnumerator Wait(float seconds)
{
yield return new WaitForSeconds(seconds);
// start fadeout here
}
or you could wait until it finishes playing
public AudioSource source;
// or wherever you start the music adioclip
private void Start()
{
source.Play ();
yield return new WaitUntil(()=> !source.isPlaying);
// start fadeout here
}
Fading
Here it depends a lot ... do you really switch Scenes by using LoadScene etc or do you just want to enable/disable certain content within one Scene?
And do you have 3D objects with materials and renderers or only 2D content using Unity.UI components?
The simplest solution for sure would be to place one overlay Canvas with the desired color as Image and simply fade it in and out. This is actually already available in the AssetStore and basically does
Uses an Overlay Canvas on top of everything with a certain color and animates it's alpha value (again using a Coroutine)
Makes sure that canvas is DontDestroyOnLoad so it isn't removed when we switch scenes
FadeIn the Canvas/Image => Fades out the current Scene
Load the other scene
FadeOut the Canvas/Image => Fades in the new Scene
Here is the source code (just cleaned it up a little)
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class Fader : MonoBehaviour
{
private string _fadeScene;
private float _alpha;
private CanvasGroup _myCanvas;
private Image _bg;
private float _lastTime;
private bool _startedLoading;
private float _fadeInDuration;
//Set callback
private void OnEnable()
{
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
SceneManager.sceneLoaded += OnLevelFinishedLoading;
}
//Remove callback
private void OnDisable()
{
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}
public void InitiateFader(CanvasGroup canvasGroup, Image image, string scene, Color fadeColor, float fadeInDuration, float fadeOutDuration)
{
DontDestroyOnLoad(gameObject);
_fadeInDuration = fadeInDuration;
_fadeScene = scene;
//Getting the visual elements
_myCanvas = canvasGroup;
_bg = image;
_bg.color = fadeColor;
//Checking and starting the coroutine
_myCanvas.alpha = 0.0f;
StartCoroutine(FadeIt(FadeDirection.Out, fadeOutDuration));
}
private enum FadeDirection
{
In,
Out
}
private IEnumerator FadeIt(FadeDirection fadeDirection, float fadeDuration)
{
var timePassed = 0.0f;
switch (fadeDirection)
{
case FadeDirection.Out:
do
{
_alpha = Mathf.Lerp(0, 1, timePassed / fadeDuration);
_myCanvas.alpha = _alpha;
timePassed += Time.deltaTime;
yield return null;
} while (timePassed < fadeDuration);
_alpha = 1;
SceneManager.LoadSceneAsync(_fadeScene);
break;
case FadeDirection.In:
do
{
_alpha = Mathf.Lerp(1, 0, timePassed / fadeDuration);
_myCanvas.alpha = _alpha;
timePassed += Time.deltaTime;
yield return null;
} while (timePassed < fadeDuration);
_alpha = 0;
Initiate.DoneFading();
Debug.Log("Your scene has been loaded , and fading in has just ended");
Destroy(gameObject);
break;
}
}
private void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode)
{
//We can now fade in
StartCoroutine(FadeIt(FadeDirection.In, _fadeInDuration));
}
}
and
public static class Initiate
{
private static bool areWeFading;
//Create Fader object and assing the fade scripts and assign all the variables
public static void Fade(string scene, Color col, float fadeOutDuration, float fadeInDuration)
{
if (areWeFading)
{
Debug.Log("Already Fading");
return;
}
var init = new GameObject("Fader", typeof(Canvas), typeof(CanvasGroup), typeof(Image), typeof(Fader));
init.GetComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
var fader = init.GetComponent<Fader>();
areWeFading = true;
fader.InitiateFader(init.GetComponent<CanvasGroup>(), init.GetComponent<Image>(), scene, col, fadeOutDuration, fadeInDuration);
}
public static void DoneFading()
{
areWeFading = false;
}
}
than You call this in a dedicated component like in order to be able to do it e.g. in a button's onClick
public class DemoScript : MonoBehaviour
{
//name of the scene you want to load
public string TargetSceneName;
public Color LoadToColor = Color.black;
public float FadeInDuration = 1.0f;
public float FadeOutDuration = 1.0f;
public void GoFade()
{
Initiate.Fade(TargetSceneName, LoadToColor, FadeOutDuration, FadeInDuration);
}
}
or since it is static simply use
Initiate.Fade(TargetSceneName, LoadToColor, FadeOutDuration, FadeInDuration);
from anywhere.
Instead of the LoadSceneAsync you could also do your enabling and disabling stuff if you prefer to do it in only one scene.
However in VR it is actually a bad idea to fade to completely black and let the user see nothing. It might lead to disorientation and cybersickness ...

Reload GameScene without reloading UIScene in Unity3d

I have 2 scenes "GamePlay" and "GameUI".
I load GameUI additively with GamePlay
void Awake () {
if (!instance) {
instance = this;
} else {
Destroy(this.gameObject) ;
}
SceneManager.LoadScene ("GameUI", LoadSceneMode.Additive);
DontDestroyOnLoad(this.gameObject);
}
Now when I reload the "GamePlay" scene using
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
How can I prevent reloading "GameUI" scene?
You could add an MonoBehaviour that is attached to the GameUI which contains a static bool that indicates if the object exists. Make your whole UI Scene a child of one object with the following script.
public class UIExistance : MonoBehaviour
{
public static bool Exists { get; private set; }
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
UIExistance.Exists = true;
}
void OnDestroy()
{
UIExistance.Exists = false;
}
}
When you are in your posted Awake method you can check with if(!UIExistance.Exists) whether the UI is already in the scene.