I am trying to create a pause menu within my FPS game. However, when the game is paused, whenever I mouse over any of the buttons that appear I cannot click on them. I've tried disabling my FPS controller (I'm using the unity fps controller provided) script and checked my canvas has an event system etc.
Any suggestions would be a huge help! Here is my code for the pause menu I have :
public Transform menu;
public GameObject Player;
public GameObject Gun;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
Pause();
}
}
public void Pause()
{
if (menu.gameObject.activeInHierarchy == false)
{
menu.gameObject.SetActive(true);
Time.timeScale = 0;
Gun.GetComponent<Gun>().enabled = false;
Player.GetComponent<FirstPersonController>().enabled = false;
Cursor.lockState = CursorLockMode.None;
Cursor.lockState = CursorLockMode.Confined;
Cursor.visible = true;
}
else
{
menu.gameObject.SetActive(false);
Time.timeScale = 1;
Player.GetComponent<FirstPersonController>().enabled = true;
Gun.GetComponent<Gun>().enabled = true;
}
}
public void QuitToMain()
{
SceneManager.LoadScene("Menu 3D");
}
} ```
Does the pause menu work outside of the games pause state? Have you checked whether the buttons are obstructed by other UI objects that are in the way?
This link might help you to debug the UI issues:
https://answers.unity.com/questions/1148727/ui-button-not-working-2.html
Related
I am making a FPS Game. So, when I start the game, the cursor is locked and I can not see it.
When I press Escape key, now, I am able to see the Cursor and I can move it around and interact with it on my screen and I can not control the game camera now. That is fine. Now, I press Escape key again, and now, I can resume controlling the camera in game, but I can still see the cursor and I can move the camera in game while making the cursor interact with all the stuff even outside of my game window.
The Code
void Update()
{
LockAndUnlockCursor();
if(Cursor.lockState == CursorLockMode.Locked)
{
LookAround();
}
}
void LockAndUnlockCursor()
{
if(Input.GetKeyDown(KeyCode.Escape))
{
if(Cursor.lockState == CursorLockMode.Locked)
{
Cursor.lockState = CursorLockMode.None;
}
else if (Cursor.lockState == CursorLockMode.None)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
}```
In the editor this tends to bug out, you have to constantly set it in Update() by saving them into variables.
bool isCursorLocked;
Update() {
if (Input.GetKeyDown(blah))
isCursorLocked = !isCursorLocked;
if (isCursorLocked)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
else
{
// etc
just use variables and always set the cursor lock every Update(). If you don't want this code running always then you could use #if UNITY_EDITOR in a way to only set it every single update for unity editor
I'm developing a 2D mobile game where the player should tap on the screen to go up. I just added a pause button recently and I've noticed that when I click the button it counts as a tap on the screen, so the player goes up. Basically, in the same exact moment that I press the pause button, the player jumps and then the game freezes while he is in mid-air. Is there a way I could make so the button wouldn't count as a tap?
Here's the part of the player script that makes him move:
if (Input.GetMouseButtonDown (0) && isDead == false && isKnifeDead == false && UiStartScript.uiInstance.firstClickUi == true) {
rb.velocity = Vector2.up * velocity;
}
Heres's the part of the UI script for the pause button:
public void PauseGame()
{
Time.timeScale = 0;
}
My EventSystem:
EventSystem
My Button:
Button
An easy with no code required is to remove the code about detecting tap on screen and instead place a button that covers the whole screen (invisible button).
That button event would trigger the screen movement.
You can add extra buttons on top and Unity will automatically discard the tap from any other button below.
This way you can start adding UI all over without checking in code which should be considered.
In U. I script add
public GameObject PlayerConrtollerScript;
In your U.I Script, under the class Pausgame()
Add this code.
GameObject.PlayerControllerScript.SetActive = false;
When unpaused you need to add to your script that has the
Time. timeScale =1;
Add this code.
GameObject.PlayerControllerScript.SetActive = true;
After you have added the code mentioned above. Don't forget to add the player game object from your hierarchy into the Inspector with the U. I script, the space will be available to add a game object when you scroll down to your U. I script.
That will stop your player from moving around during pause.
This is the approach that I been done. I create a cople of tricks using Event System and Canvas for take advantage of the Mouse Input, you don't need the use of Updates functions for do the basic gameplay.
Here's my example project: TapAndJump on Github
Check the GameObjects called "Click Panel" and "Pause Button" and
respective linked methods.
JumpWithTap.cs
using UnityEngine;
public class JumpWithTap : MonoBehaviour
{
[SerializeField] private UIHandler uiHandler;
[SerializeField] private float jumpPower = 5f;
private Rigidbody2D rb2D;
private int counter;
#region Class Logic
public void Jump()
{
rb2D.velocity = Vector2.up * jumpPower;
uiHandler.SetNumberToCounter(++counter);
}
#endregion
#region MonoBehaviour API
private void Awake()
{
rb2D = GetComponent<Rigidbody2D>();
}
#endregion
}
UIHandler.cs
using UnityEngine;
using UnityEngine.UI;
public class UIHandler : MonoBehaviour
{
[SerializeField] private Text counterText;
[SerializeField] private Text pauseText;
[SerializeField] private Image clickPanel;
private bool isPaused = false;
public bool IsPaused
{
get { return isPaused; }
set
{
pauseText.gameObject.SetActive(value);
isPaused = value;
}
}
#region Class Logic
public void SetNumberToCounter(int number) => counterText.text = number.ToString();
public void DisableClickPanel() => clickPanel.raycastTarget = !clickPanel.raycastTarget;
public void PauseGame()
{
IsPaused = !IsPaused;
DisableClickPanel();
// Time.timeScale = IsPaused == true ? 0 : 1; // If you want keep the Physics (ball fall) don't stop the time.
}
#endregion
}
I guided by your code example and so on; be free that modify and request any issue.
When I press escape, the pause menu in my game should become visible to the user and the game time should freeze. However, the program seems to not recognize the input when I press escape. I have tried using different Keys and they did not work either. I went to make sure that it was the input that was the problem by doing a Debug.Log command and when I tested I was still not getting any signs of it triggering. Here is the code. I hope someone can help me out.
public static bool GameIsPaused = true;
public GameObject PauseMenuUI;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (GameIsPaused)
{
Resume();
}
else
{
Pause();
}
}
}
void Resume()
{
PauseMenuUI.SetActive(false);
Time.timeScale = 1f;
GameIsPaused = false;
}
void Pause()
{
PauseMenuUI.SetActive(true);
Time.timeScale = 0f;
GameIsPaused = true;
}
As we discussed in the comments, the GameObject which the PauseMenu-script is attached to was not active.
An inactive gameobject will have all its components disabled.
Update is called every frame, if the MonoBehaviour is enabled.
https://docs.unity3d.com/ScriptReference/MonoBehaviour.Update.html
So your update code did not run, hence never detecting when Escape was pressed.
I used OnMouseDown() to deactivate an object but i want the object to activate again in a few seconds. I have used WaitForSeconds() for other things but this time it just doesn't work
this is what i could gather by researching (the deactivating part works fine):
void Start()
{
StartCoroutine(wait());
}
void Update(){}
void OnMouseDown()
{
gameObject.SetActive(false);
}
IEnumarator wait()
{
yield return new WaitForSeconds(3);
gameObject.SetActive(true);
}
There are too many reasons your code isn't work right. You are doing it backwards. Your coroutine starts immediately when your program starts because wait() is called from the Start() function. When it starts, it pauses for 3 seconds and set your GameObject to SetActive(true);
If your GameObject is already visible to the screen, your code wont do anything because SetActive(true) will be called even when it is visible. If you fail to press/click on the screen before that 3 seconds, you wont be able to see SetActive(true); because your coroutine code would have finished running by that time.
Also, if you disable a GameObject, the coroutine attached to it will stop. The solution is to create a reference of the GameObject you want to disable then use that reference to disable and enable it from another script without problems.
Since provided a code, I fixed/re-wrote it for you. I replaced the OnMouseDown fucntion with something more robust.
All you have to do is create an empty GameObject. Attach this script to that empty GameObject. Then drag and drop that GameObject you want to disable and enable to the this "Game Object To Disable" slot in this script, from the Editor.
Do NOT attach this script to that GameObject you want to disable and enable.
Tested with cube and it worked.
using UnityEngine;
using System.Collections;
public class ALITEST: MonoBehaviour
{
//Reference to the GameObject you want to Disable/Enable
//Drag the Object you want to disable here(From the Editor)
public GameObject gameObjectToDisable;
void Start()
{
}
void Update()
{
//Keep checking if mouse is pressed
checkMouseClick();
}
//Code that checks when the mouse is pressed down(Replaces OnMouseDown function)
void checkMouseClick()
{
//Check if mouse button is pressed
if (Input.GetMouseButtonDown(0))
{
RaycastHit hitInfo = new RaycastHit();
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hitInfo))
{
//Check if the object clicked is that object
if (hitInfo.collider.gameObject == gameObjectToDisable)
{
Debug.Log("Cube hit");
StartCoroutine(wait()); //Call the function to Enable/Disable stuff
}
}
}
}
//This value is used to make sure that the coroutine is not called again while is it already running(fixes many bugs too)
private bool isRunning = false;
IEnumerator wait(float secondsToWait = 3)
{
//Exit coroutine while it is already running
if (isRunning)
{
yield break; //Exit
}
isRunning = true;
//Exit coroutine if gameObjectToDisable is not assigned/null
if (gameObjectToDisable == null)
{
Debug.Log("GAME OBJECT NOT ATTACHED");
isRunning = false;
yield break; //Exit
}
gameObjectToDisable.SetActive(false);
//Wait for x amount of Seconds
yield return new WaitForSeconds(secondsToWait);
//Exit coroutine if gameObjectToDisable is not assigned/null
if (gameObjectToDisable == null)
{
Debug.Log("GAME OBJECT NOT ATTACHED");
isRunning = false;
yield break; //Exit
}
gameObjectToDisable.SetActive(true);
isRunning = false;
}
}
Because you're calling StartCoroutine() in Start(), your coroutine will resume 3 seconds after the component is started. You want to call StartCoroutine(wait()) in OnMouseDown() so the GameObject will become active after that.
You cannot deactivate GameObject and continue Coroutine on it. If you deactivate GameObject that has runing Coroutine it will be stoped.
So if you want to do it right, you need Coroutine runing on other GameObject and from there actvating this GameObject.
If you need more help, ask.
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.