Is there a way to activate a fade animation every time the game changes from one scene to the other, without the user doing somthing specific like hiting a pre-determined key?
Basically the transtions needs to start just because there is a change in scenes.
I have a bunch of scenes and i need to add a fade to black transition between them.
All tutorials i found need some specific key input or something happening while i only have a few videos with no possible interaction with the user (in most cases).
Just in case that's not possible (or inpractical for rookies) I guess i could hook up the animations to the user pushing buttons that send you to other scenes (could use help with that aswell). And the first scene could work with a timer/delay.
*Unity and visual studio update to latest stable builds.
So every time you need to change scene you actually need to first fade-out your screen, then run scene change and after new scene is loaded - fade screen in. You can do it like that:
1) Create new Canvas object in start scene of your project. Set canvas mode to "Screen Space - Overlay" and make sure Sort Order is set high enough so your canvas will be on top always.
new Canvas object
2) Create an empty Image on this Canvas and size it so it covers all the scree. Set Color to transparent. Dont forget to toggle "Raycast Target" of image off (or you won't be able to mouseclick through it)
new Image object
3) Add this script to your Canvas object:
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class SceneChanger : MonoBehaviour
{
enum FadeStatus
{
fading_id,
fading_out,
none
}
public static SceneChanger Instance;
public Image fadeImage;
public float fadeDuration;
private FadeStatus currentFadeStatus = FadeStatus.none;
private float fadeTimer;
private string sceneToLoad;
void Start()
{
if (Instance == null)
{
Instance = this;
SceneManager.sceneLoaded += OnSceneLoaded;
}
else
Destroy(gameObject);
DontDestroyOnLoad(gameObject);
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
//scene loaded, running fade-in
currentFadeStatus = FadeStatus.fading_id;
}
public void ChangeScene(string _name)
{
sceneToLoad = _name;
currentFadeStatus = FadeStatus.fading_out;
}
void Update()
{
if(currentFadeStatus != FadeStatus.none)
{
fadeTimer += Time.deltaTime;
if(fadeTimer > fadeDuration) //done fading
{
fadeTimer = 0;
if (currentFadeStatus == FadeStatus.fading_out)
{
SceneManager.LoadScene(sceneToLoad);
fadeImage.color = Color.black;
}
else
fadeImage.color = Color.clear;
currentFadeStatus = FadeStatus.none;
}
else //still fading
{
float alpha = 0;
if (currentFadeStatus == FadeStatus.fading_out)
alpha = Mathf.Lerp(0, 1, fadeTimer / fadeDuration);
else
alpha = Mathf.Lerp(1, 0, fadeTimer / fadeDuration);
fadeImage.color = new Color(0, 0,0, alpha);
}
}
}
}
4) Go back to Editor and assign your transparent Image to its field on SceneChanger script and adjust fadeDuration (time of one fade in seconds)
5) Now you can change scenes from code using
SceneChanger.Instance.ChangeScene("YourSceneName");
6) Don't forget to add all needed scenes to build settings, otherwise it won't work.
build settings
7) You DON'T need to add SceneChanger on other scenes, it will be saved between scenes due to DontDestroyOnLoad().
Related
I'm trying to come up with a generic rule that I can add to any GameObject. Items like tables, chairs etc that once collided and interacted fade in the white text, then after a few seconds the text fades out.
Ideally I'd be able to offset the position of this text with a Vector3 so I can position it around my character
At the moment I have, some code but the CrossFade.Alpha doesn't seem to work. this might or might not be the best way to go about this, I'm open to new ideas
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Qwerty : MonoBehaviour
{
public float Radius = 1f;
public Text TextToUse;
[SerializeField] private LayerMask playerMask;
private bool isInSphere;
// Start is called before the first frame update
void Start()
{
isInSphere = false;
}
// Update is called once per frame
void Update()
{
isInSphere = Physics.CheckSphere(transform.position, Radius, playerMask);
if (isInSphere && Input.GetKey(KeyCode.F) == true)
{
// Check if collision is detected and F is pressed
isInSphere = true;
Debug.Log("Hello");
//Fade in over 2 seconds
TextToUse.CrossFadeAlpha(1, 2f, false);
}
else if (!isInSphere && !Input.GetKey(KeyCode.F))
{
//Fade out on leave over 2 seconds
isInSphere = false;
TextToUse.CrossFadeAlpha(0, 2f, false);
}
}
}
Description
Tweens the alpha of the CanvasRenderer color associated with this Graphic.
Creates a fading effect on a Graphic with a CanvasRenderer attached. Choose an alpha level to fade to, and pick the speed of the fade to see a smooth fade over time. UI Images and Text are some of the elements that you are able to apply this effect to.
CrossFade.Alpha needs a canvas that has CanvasRenderer attached to work.
This is the script taken from the tanks asset store and I want to convert the shooting which is currently being done by space bar to Ui Shoot button. It should fire the bullet.
Like I want that when my button is pressed it should charge as to how much velocity is imparted to the bullet and it soon as I release it the bullet should be fired.
Also, I was thinking of a fill image which can show that thing in the button as well.
public class TankShooting: MonoBehaviour
{
//public int m_PlayerNumber = 1; // Used to identify the different players.
public Rigidbody m_Shell; // Prefab of the shell.
public Transform m_FireTransform; // A child of the tank where the shells are spawned.
public Slider m_AimSlider; // A child of the tank that displays the current launch force.
//public AudioSource m_ShootingAudio; // Reference to the audio source used to play the shooting audio. NB: different from the movement audio source.
//public AudioClip m_ChargingClip; // Audio that plays when each shot is charging up.
//public AudioClip m_FireClip; // Audio that plays when each shot is fired.
public float m_MinLaunchForce = 15f; // The force is given to the shell if the fire button is not held.
public float m_MaxLaunchForce = 30f; // The force is given to the shell if the fire button is held for the max charge time.
public float m_MaxChargeTime = 0.75f; // How long the shell can charge for before it is fired at max force.
private string m_FireButton; // The input axis that is used for launching shells.
private float m_CurrentLaunchForce; // The force that will be given to the shell when the fire button is released.
private float m_ChargeSpeed; // How fast the launch force increases, based on the max charge time.
private bool m_Fired; // Whether or not the shell has been launched with this button press.
private float nextFireTime;
private void OnEnable()
{
// When the tank is turned on, reset the launch force and the UI
m_CurrentLaunchForce = m_MinLaunchForce;
m_AimSlider.value = m_MinLaunchForce;
}
private void Start ()
{
// The fire axis is based on the player number.
m_FireButton = "Fire1"; //+ m_PlayerNumber;
// The rate that the launch force charges up is the range of possible forces by the max charge time.
m_ChargeSpeed = (m_MaxLaunchForce - m_MinLaunchForce) / m_MaxChargeTime;
}
public void Update()
{
// The slider should have a default value of the minimum launch force.
m_AimSlider.value = m_MinLaunchForce;
// If the max force has been exceeded and the shell hasn't yet been launched...
if (m_CurrentLaunchForce >= m_MaxLaunchForce && !m_Fired)
{
// ... use the max force and launch the shell.
m_CurrentLaunchForce = m_MaxLaunchForce;
Fire (m_CurrentLaunchForce, 1);
}
// Otherwise, if the fire button has just started being pressed...
else if (Input.GetButtonDown (m_FireButton))
{
// ... reset the fired flag and reset the launch force.
m_Fired = false;
m_CurrentLaunchForce = m_MinLaunchForce;
// Change the clip to the charging clip and start it playing.
//m_ShootingAudio.clip = m_ChargingClip;
//m_ShootingAudio.Play ();
}
// Otherwise, if the fire button is being held and the shell hasn't been launched yet...
else if (Input.GetButton (m_FireButton) && !m_Fired)
{
// Increment the launch force and update the slider.
m_CurrentLaunchForce += m_ChargeSpeed * Time.deltaTime;
m_AimSlider.value = m_CurrentLaunchForce;
}
// Otherwise, if the fire button is released and the shell hasn't been launched yet...
else if (Input.GetButtonUp (m_FireButton) && !m_Fired)
{
// ... launch the shell.
Fire (m_CurrentLaunchForce, 1);
}
}
public void Fire (float launchForce, float fireRate)
{
if (Time.time > nextFireTime)
{
nextFireTime = Time.time + fireRate;
// Set the fired flag so only Fire is only called once.
m_Fired = true;
// Create an instance of the shell and store a reference to it's rigidbody.
Rigidbody shellInstance =
Instantiate (m_Shell, m_FireTransform.position, m_FireTransform.rotation) as Rigidbody;
// Set the shell's velocity to the launch force in the fire position's forward direction.
shellInstance.velocity = m_CurrentLaunchForce * m_FireTransform.forward;
// Change the clip to the firing clip and play it.
//m_ShootingAudio.clip = m_FireClip;
//m_ShootingAudio.Play ();
// Reset the launch force. This is a precaution in case of missing button events.
m_CurrentLaunchForce = m_MinLaunchForce;
}
}
}
There is Very Easy Solution for this:
Create A Function In Your Script
ShootTheBullet()
and The Create A UI Button and Click on Add Button In your Button's Component Event
"On Click"
Drag and Drop The gameObject that you have attached your C# script From Hierarchey that Contains "ShootTheBullet()" and then click On Right Option Select your Script an Select That Function.
Now you are ready to Shoot Bullets With UI Button.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteAlways]
public class SkyBox : MonoBehaviour
{
public Material[] skyboxes;
public Camera skyboxCamera;
public float skyboxMoveSpeed = 2f;
private int index = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
SwitchSkybox();
}
if (RenderSettings.skybox == skyboxes[1])
{
RenderSettings.skybox.SetFloat("_Rotation", Time.time * skyboxMoveSpeed);
}
}
public void SwitchSkybox()
{
index++;
if (index == skyboxes.Length)
{
index = 0;
}
RenderSettings.skybox = skyboxes[index];
if (RenderSettings.skybox == skyboxes[1])
{
skyboxCamera.enabled = true;
Camera.current.enabled = false;
Time.timeScale = 1.0f;
}
else
{
skyboxCamera.enabled = false;
Camera.current.enabled = true;
Time.timeScale = 0.0f;
}
}
}
The script switch between skyboxes the default and my skybox and also switch between the currently active camera and the sky box camera.
But when I'm hitting the escape key it's throwing null exception in the editor on the line number 46 :
Camera.current.enabled = false;
The current of the Camera is null
I want to make that when I press the escape key it will switch to my skybox and to the skybox camera and also will pause the game (Later I will make a main menu when the game is paused).
This is the Camera.current, from the manual.
The camera we are currently rendering with.
Also worth noting the comment from Ruzihm.
The Unity engine typically assigns an already-instantiated instance of
Camera to Camera.current
So, from your scripts, I see 2 issues. The one directly related to this questions happens just in editor mode and I will start from that one.
Editor Issue: Camera.current is null
When working in the editor, Camera.current won't be just your own application's camera, but it could be any camera. It could even refer to the editor's scene view camera.
In this last case, if your scene view is not in focus (IE when you've focus on Game Window) Camera.current will be null.
Logical Issue: you couldn't switch back
When you try to switch back from skyboxCamera, your Camera.current will be the same skyboxCamera, and not your default camera. So you won't be able to retrieve the previous camera.
SOLUTION
Do not use Camera.current, but store all of your cameras in your script (this solution is also better for perfomance, since both Camera.current and Camera.Main are not performant scripts).
In your case you will need to add this piece of code to your script and use the EnableSkyBoxCamera method.
public Camera defaultCamera;
public Camera skyBoxCamera;
private Camera _currentCamera;
public void EnableSkyBoxCamera(bool enableSkyBox)
{
defaultCamera.enabled = !enableSkyBox;
skyBoxCamera.enabled = !enableSkyBox;
if (enableSkyBox) _currentCamera = skyBoxCamera;
else _currentCamera = defaultCamera;
}
If camera is null you can't set the enabled to false without getting a nullpointerexception. Instantiate the camera first or remove that line of code.
*** Edit ill take another crack at this
try
Camera.main.enabled = false;
instead of
Camera.current.enabled = false;
As per Unity docs in reference to Camera.current: 'Most of the time you will want to use Camera.main instead. Use this function only when implementing one of the following events: MonoBehaviour.OnRenderImage, MonoBehaviour.OnPreRender, MonoBehaviour.OnPostRender'
First, I want you to understand my English.
I manually change the camera's projection to orthographic using the source code.
Please refer to the code below.
using UnityEngine;
using System.Collections;
public class CameraOrthoController : MonoBehaviour
{
private Matrix4x4 ortho;
private Matrix4x4 perspective;
public float near = 0.001f;
public float far = 1000f;
private float aspect;
public static CameraOrthoController Instance
{
get
{
return instance;
}
set { }
}
//-----------------------------------------------------
private static CameraOrthoController instance = null;
//---------------------------------------------------
// Use this for initialization
void Awake()
{
if (instance)
{
DestroyImmediate(gameObject);
return;
}
// 이 인스턴스를 유효한 유일 오브젝트로 만든다
instance = this;
}
private void Start()
{
perspective = Camera.main.projectionMatrix;
}
public void StartMatrixBlender(float OrthoSize)
{
aspect = (Screen.width + 0.0f) / (Screen.height + 0.0f);
if (OrthoSize != 0f)
{
float vertical = OrthoSize;
float horizontal = (vertical * 16f) / 9f;
ortho = Matrix4x4.Ortho(-horizontal, horizontal, -vertical, vertical, near, far);
BlendToMatrix(ortho, 1f);
}
else
{
BlendToMatrix(perspective, 1f);
}
}
//---------------------------------------
private Matrix4x4 MatrixLerp(Matrix4x4 from, Matrix4x4 to, float time)
{
Matrix4x4 ret = new Matrix4x4();
int i;
for (i = 0; i < 16; i++)
ret[i] = Mathf.Lerp(from[i], to[i], time);
return ret;
}
IEnumerator LerpFromTo(Matrix4x4 src, Matrix4x4 dest, float duration)
{
float startTime = Time.time;
while (Time.time - startTime < duration)
{
Camera.main.projectionMatrix = MatrixLerp(src, dest, (Time.time - startTime) / duration);
yield return new WaitForSeconds(0f);
}
Camera.main.projectionMatrix = dest;
}
//-------------------------------------------------
private Coroutine BlendToMatrix(Matrix4x4 targetMatrix, float duration)
{
StopAllCoroutines();
return StartCoroutine(LerpFromTo(Camera.main.projectionMatrix, targetMatrix, duration));
}
//-------------------------------------------------
public void OnEvent(EVENT_TYPE Event_Type, Component Sender, object Param = null, object Param2 = null)
{
switch (Event_Type)
{
}
}
}
I use code this way.
CameraOrthoController.Instance.StartMatrixBlender(OrthographicSize);
This has worked well so far.
However, the problem occurred when i added particle system for effect.
The screen where the problem is occurring
In a normal state, the effect appears in front of the gameobject, as shown on the scene screen at the bottom of the picture above.
But if I use the code I wrote above to manipulate the camera, the effect will always be obscured by all gameobject, as if it were on the game screen at the top of the picture. Despite the fact that the effects are located in front of the game object.
At first, I thought it would be possible to solve it with layer sorting, but I don't think it's a layer problem because it's visible under normal camera conditions.
I want to know where the problem is with the above codes because I have to use them.
Please let me know if you know how to solve it.
Thank you.
When you modify Camera.projectionMatrix, the camera will no longer update its rendering based on the field of view. The particle will remain behind the GameObject until you call Camera.ResetProjectionMatrix() which ends the effect off setting the Camera.projectionMatrix property.
If this doesn't work, use multiple cameras to make the particle system always appear on top of the 3D object. Basically, you render the 3D Object and other objects with the main camera then render the Particle System with another camera.
Layer:
1.Create new layer and name it "Particle"
2.Change the Particle System layer to Particle
Main Camera:
1.Make sure that the main camera's Clear Flags is set to Skybox.
2.Change the Culling Mask to "Everything". Click on Everything which is a setting of Culling Mask and de-select/uncheck Particle.
3.Make sure that its Depth is set to 0.
The camera should not render the Particle System at this point.
New Camera:
1.Create new Camera. Make sure it's at the-same position/rotation as the main camera. Also remove the AudioListener that is attached to it.
2.Change Clear Flags to Depth only.
3.Change the Culling Mask of the camera to be Particle and make sure that nothing else is selected in the "Culling Mask"
4.Change Depth to 1.
This will make the Particle System to always display on top of every object rendered with the first or main camera.
If you want the Particle System to appear on top of a Sprite/2d Object instead of Mesh/3D Object, change the sortingOrder of the particle's Renderer to be bigger than the SpriteRenderer's sortingOrder. The default is 0 so changing the Particle's sortingOrder to 1 or 2 should be fine.
particle.GetComponent<Renderer>().sortingOrder = 2;
I am trying to have a simple animated loading screen between my menu scene and the game scene. I am trying to do this by loading the game scene in my loading scene asynchronously. I also want the loading screen to fade in and fade out.
I got the fade-in to work. However, I have two problems which I have been working on for hours, but without any succes. These problems are:
I cannot get the fade-out to work. I tried setting the 'allowSceneActivation' to false for my asynchronous loading, however this causes the loading to not occur at all. Removing this line makes the game load, but it then lacks the fade out.
The animation works very (and I mean VERY) choppy. I understand that the game is loading stuff, so I expect it to be bad, but it's litterally doing a frame every 2 seconds. I tried using a low thread priority (see code below), but no luck. I found people with similar problems, but the frames turned out reasonable when using a lower thread priority.
This is my code for the loading screen:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class LoadIntro : MonoBehaviour {
private bool loaded;
private bool fadingOut;
private bool loading;
AsyncOperation async;
void Start(){
loaded = false;
fadingOut = false;
loading = false;
Application.backgroundLoadingPriority = ThreadPriority.Low;
}
// Use this for initialization
void Update() {
//wait for loading screen to fade in, then execute once
if (!GameObject.Find ("SceneFader").GetComponent<Image> ().enabled && !loaded && !loading) {
loading = true;
async = Application.LoadLevelAsync(mainMenuButtons.leveltoload);
async.allowSceneActivation = false;
StartCoroutine (LoadLevel (async));
}
//if next scene is loaded, start fading out loading screen
if (loaded) {
GameObject.Find ("SceneFader").GetComponent<SceneFadeInOut> ().FadeToBlack();
fadingOut = true;
}
//when faded out, switch to new scene
if (GameObject.Find ("SceneFader").GetComponent<Image> ().color.a >= 0.95f && loaded) {
async.allowSceneActivation = true;
}
}
IEnumerator LoadLevel(AsyncOperation async){
yield return async;
Debug.Log("Loading complete");
loaded = true;
}
}
I have a seperate piece of code for the actual fading, which the code above calls:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class SceneFadeInOut : MonoBehaviour
{
public float fadeSpeed = 1.5f; // Speed that the screen fades to and from black.
private bool sceneStarting = true; // Whether or not the scene is still fading in.
public bool sceneEnding = false;
public string scene;
private Image fadeTexture;
void Awake ()
{
fadeTexture = GetComponent<Image>();
}
void Update ()
{
// If the scene is starting...
if(sceneStarting)
// ... call the StartScene function.
StartScene();
if (sceneEnding)
EndScene();
}
void FadeToClear ()
{
// Lerp the colour of the texture between itself and transparent.
fadeTexture.color = Color.Lerp(fadeTexture.color, Color.clear, fadeSpeed * Time.deltaTime);
}
public void FadeToBlack ()
{
// Lerp the colour of the texture between itself and black.
fadeTexture.color = Color.Lerp(fadeTexture.color, Color.black, fadeSpeed * Time.deltaTime);
}
void StartScene ()
{
// Fade the texture to clear.
FadeToClear();
// If the texture is almost clear...
if(fadeTexture.color.a <= 0.05f)
{
// ... set the colour to clear and disable the GUITexture.
fadeTexture.color = Color.clear;
fadeTexture.enabled = false;
// The scene is no longer starting.
sceneStarting = false;
}
}
public void EndScene ()
{
// Make sure the texture is enabled.
fadeTexture.enabled = true;
// Start fading towards black.
FadeToBlack();
// If the screen is almost black...
if (fadeTexture.color.a >= 0.95f) {
// ... reload the level.
if (scene == "") Application.Quit();
else Application.LoadLevel (scene);
}
}
}
Does anyone have an idea how to solve the issues described above? I've litterally tried every topic I could find, but none of them seem to work. Building my game did not resolve the issues either.
Many thanks in advance!
You are fading out when scene loading gets done. What are you expecting when loading is done? :)
//if next scene is loaded, start fading out loading screen
if (async.isDone) {
GameObject.Find ("SceneFader").GetComponent<SceneFadeInOut> ().FadeToBlack();
fadingOut = true;
}
Obviously it will change the scene and you code doesn't getting enough time to perform fade-out operation. :)
For instance if consider your point. You wrote,
//if next scene is loaded, start fading out loading screen
if (loaded) {
GameObject.Find ("SceneFader").GetComponent<SceneFadeInOut> ().FadeToBlack();
fadingOut = true;
}
//when faded out, switch to new scene
if (GameObject.Find ("SceneFader").GetComponent<Image> ().color.a >= 0.95f && loaded) {
async.allowSceneActivation = true;
}
in Update. Here your loaded check doing 2 things.
1- Start fading out.
2- Switching scene.
Again, why it should wait for fading it out completely while its getting loaded and you are checking alpha >= 0.95 which should execute at first frame when you get loaded to true, because I believe that in first frame alpha would be greater than 0.95.