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.
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 beginner on unity and game development. i'm trying to make a platformer game with unity, and i want to play a animation when the player is moving right or left, but the problem is that the isMoving variable for some reason is true animation is playing for a few moments (less than a second) and then is going to false again and the idle animation is playing.
My Animator (Exit time is disabled for all transitions):
My Movement script:
public class PlayerMovement : MonoBehaviour
{
private bool canPlayerJump;
private float horizontalInput;
private Animator animator;
// Start is called before the first frame update
void Start()
{
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && canPlayerJump)
{
GetComponent<Rigidbody>().AddForce(Vector3.up * 5, ForceMode.VelocityChange);
}
if (Input.GetKeyDown(KeyCode.D) || Input.GetKeyDown(KeyCode.A))
{
animator.SetBool("isMoving", true);
} else
{
animator.SetBool("isMoving", false);
}
horizontalInput = Input.GetAxis("Horizontal");
}
private void FixedUpdate()
{
GetComponent<Rigidbody>().velocity = new Vector3(horizontalInput * 5, GetComponent<Rigidbody>().velocity.y, 0);
}
private void OnCollisionEnter(Collision collision)
{
canPlayerJump = true;
Debug.Log(collision.gameObject.name);
}
private void OnCollisionExit(Collision collision)
{
canPlayerJump = false;
}
}
You using Update loop function that means this code will be executed each frame by unity. Similar to FixedUpdate, LateUpdate etc...
You can read more here: HERE
Once you pressing down you IF statement will be executed because you listening for BTN DOWN event. This means that TRUE will be returned only in one frame when you press actually button next frame it will return false. and your animations stops.
Try to change bool to Trigger
Or handle in another way bool var state.
Input.GetKeyDown
is only true in the one frame the button went down.
Returns true during the frame the user starts pressing down the key identified by the key KeyCode enum parameter.
You rather want to use Input.GetKey which stay true as long as the key stays pressed.
Returns true while the user holds down the key identified by the key KeyCode enum parameter
alternatively in order to not have redundant accesses you could also simply use
horizontalInput = Input.GetAxis("Horizontal");
animator.SetBool("isMoving", !Mathf.Approximately(horizontalInput, 0));
And as a general note: Cache the component references and don't use GetComponent over and over again!
[SerializeField] private Rigidbody _rigidbody;
private void Awake ()
{
if(!_rigodbody) _rigidbody = GetComponent<Rigidbody>();
}
then later everywhere use _rigidbdoy instead of GetComponent<Rigidbody>()
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
I have an NPC that my player can talk to when the players collider is colliding with the NPC, I do that using this piece of code:
private void OnTriggerStay2D(Collider2D other)
{
if (other.gameObject.tag == "InteractiveArea")
{
if (Input.GetKeyDown(KeyCode.E))
{
Debug.Log("PRESSED NPC");
CreateAndShowDialog();
}
}
}
However, this gets called really randomly, sometimes the first time I press "E", sometimes the second or third time, etc.
My rigidbodies:
The colliders I use are standard BoxCollider2D, my players collider is a trigger, the NPCs is not.
Why are some key press not detected in the OnTriggerStay function?
OnTriggerStay2D is called randomly. This is why you should never check for Input inside of it.
Set to a flag to true and false in the OnTriggerEnter2D and OnTriggerExit2D functions then check for that flag and input in the Update function which is called every frame. Also, always use CompareTag instead of other.gameObject.tag to compare tags.
private void Update()
{
if (Input.GetKeyDown(KeyCode.E) && triggerStay)
{
//
}
}
bool triggerStay = false;
void OnTriggerEnter2D(Collider2D collision)
{
Debug.Log("Entered");
if (collision.gameObject.CompareTag("InteractiveArea"))
{
triggerStay = true;
}
}
void OnTriggerExit2D(Collider2D collision)
{
Debug.Log("Exited");
if (collision.gameObject.CompareTag("InteractiveArea"))
{
triggerStay = false;
}
}
My guess would be because the value returned by Input.GetKeyDown is only true for the single (Update()) frame that the key was pressed, whereas physics (including OnTriggerStay) are called during physics frames, i.e. FixedUpdate()
Doing a bit of research I pull up this question which suggests:
I've been struggling with this issue all afternoon!
My OnTriggerStay and Update/FixedUpdate methods were not in sync resulting is split-second undesired effects.
I finally found the solution when I read in the OnTriggerStay docs that this function can be a co-routine. I simply added a WaitForFixedUpdate in the correct location in my OnTriggerStay and it worked. They now both run in sync with each other. This even corrects the issue in Update.
Another question has this as a solution (Programmer's answer):
OnTriggerStay will not call on every frame. One way to get around this is to have OnTriggerEnter, and OnTriggerExit set a bool. Then execute your code in the FixedUpdate().
While the documentation no longer says what this post says,
OnTriggerStay gets called every FixedUpdate.
"Note: OnTriggerStay function is on the physics timer so it wont necessary run every frame. "
That confirms my guess and that the documentation was changed to no longer include this note, for some unexplained reason.
You can do this :
bool eIsOnclick;
float wait = 0.03f;
float nextFire = 0.0f;
void Update() {
if(Input.GetKeyDown(keyKode.E))
eIsOnclick = true;
else if(nextFire < Time.time)
nextFire = Time.time + wait;
ebas = false;
}
void OnTriggerStay2D(Collider2D collision) {
if(eIsOnclick == true) {
// your cods
}
// not work in alwaays aquestions
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.