One function works different with two different calling - c#

The ESC button is used to pause/resume the game.
If I continue my game by pressing the UI resume button using "Continue()", it works well. But if I press again ESC button same function is called but the player controllers don't work until I click on the screen. Here is the screenshot of my scripts.
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
// Checks if the MainMenuCanvas is already open
if (mainMenuCanvas.activeSelf == false)
{
OpenMainMenue();
}
else
{
Continue();
}
}
}
// This function continues the Gameplay
public void Continue()
{
Time.timeScale = 1;
SystemManager.soundManager.StopWatchAudio();
mainMenuCanvas.SetActive(false);
SystemManager.playerManager.LockMouse();
}
Here is the function:
public void LockMouse()
{
Debug.Log("LockMouse LockMouse");
EventHandler.ExecuteEvent(m_Character, "OnEnableGameplayInput", true);
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}

Related

Character movement stops on every second "Resume" button press

Im fairly new to Unity and I am trying to make a Pause overlay for my game. Currently Resume does not resume the character movement half of the time. So the first time I pause the game and click resume the overlay is disabled but I will not be able to move, but if I press escape again and then Resume it works fine on the second try. One thing to note is that it works as intended if I press escape while in the pause menu and the logic is exactly the same. Here is my C# script:
public class PauseGame : MonoBehaviour
{
public GameObject Canvas;
bool pausedGame = false;
// Make sure pause screen is not active on game start
void Start()
{
Canvas.GetComponent<Canvas>().enabled = false;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (pausedGame == false)
{
Time.timeScale = 0;
Canvas.GetComponent<Canvas>().enabled = true;
pausedGame = true;
}
else
{
Time.timeScale = 1;
Canvas.GetComponent<Canvas>().enabled = false;
pausedGame = false;
}
}
}
public void Resume()
{
Time.timeScale = 1;
Canvas.GetComponent<Canvas>().enabled = false;
pausedGame = false;
}
public void MainMenu()
{
SceneManager.LoadScene("MainMenu");
}
}
Let me know if I should add screenshots of my components.
Found the solution to this! For some reason the FirstPersonAIO controller did not get unpaused when I resumed the game. Where player is a public variable I added these two lines to my code and it fixed my problem:
controllerScript = player.GetComponent<FirstPersonAIO>();
controllerScript.ControllerPause();

Unable to get coroutine to start and stop when button is down

I am working on the walking sounds for my game, I am wanting it to play a sound and then wait and play the next. As it is walking I only want it to do this when w is pressed. I have been trying to use an Enumerator to do so but I am having issues where it will not start the function.
private IEnumerator audioPlayCoroutine;
public AudioSource[] steps;
public AudioSource[] cabinSteps;
private bool running;
void Start()
{
running = false;
audioPlayCoroutine = AudioPlay();
}
void Update()
{
if (Input.GetKey("w"))
{
if (running == false)
{
running = true;
}
}
if (running == true)
{
StartCoroutine(audioPlayCoroutine);
}
else if (running == false)
{
StopCoroutine(audioPlayCoroutine);
}
}
IEnumerator AudioPlay()
{
int ran = Random.Range(0, 4);
steps[ran].Play();
yield return new WaitForSeconds(2);
}
Okay, there are multiple reasons why it doesn't work:
For one running is never set to false. Once your player pressed w once, it will stay true.
Instead write
if (Input.GetKey("w"))
running = true;
else
running = false;
Additionally you start and stop your Coroutine multiple times.
Instead you should either check, whether the running status either changed or you should just check running in your coroutine.
It could then look like this:
void Start() {
running = false;
audioPlayCoroutine = AudioPlay();
StartCoroutine(audioPlayCoroutine);
}
void Update() {
if (Input.GetKey("w"))
running = true;
else
running = false;
}
IEnumerator AudioPlay()
{
while (true) {
if(!running)
yield return new WaitForSeconds(0);
int ran = Random.Range(0, 4);
steps[ran].Play();
// if you want it to play continuously, you can use the clip length for
// the sleep. This way it will start playing the next clip right after
// this one is done. If you don't want that, go with your code
yield return new WaitForSeconds(steps[ran].clip.length);
}
}
If your clip is actually 2 seconds long, you might also want to interrupt it from playing once your user stops pressing the button.

Unity 3d Animation

I m a newbie to Unity3d and was just playing with unity animation, i was trying to implement 2 Main UI Button such as when either of them is pressed it should check the condition whether a animation is already played before by 2nd button available if yes then remove those gameobject from scene using reverse animation else play the default animation attach to the particular button.
Problem is out of 6 case only 4 are getting operational 2 of them are not executing (marked in the code as Case Not Operational)
Animation anim;
private bool isOpen = false;
private bool open = false;
// Start is called before the first frame update
void Start()
{
anim = GetComponent<Animation>();
//isOpen = false;
//open = false;
}
// Update is called once per frame
void Update()
{
}
void OnGUI()
{
isOpen = GUI.Toggle(new Rect(50, 50, 200, 100), isOpen, "IsOpen");
open = GUI.Toggle(new Rect(65, 65, 200, 100), open, "Open");
}
public void ButtonControl()
{
string name = EventSystem.current.currentSelectedGameObject.name;
if (name == "Main Button 1")
{
if (isOpen == false && open == false)
{ Debug.Log("False False 1");
Anim1();
isOpen = true;
}
else if (isOpen == false && open == true) // case not operational
{ Debug.Log("False True 2");
ReverseAnim_2();
open = false;
Anim1();
isOpen = true;
}
else if(isOpen == true)
{
Debug.Log("True 3");
ReverseAnim_1();
isOpen = false;
}
}
else if (name == "Main Button 2")
{
if (open == false && isOpen == false)
{ Debug.Log("False False 4");
Anim2();
open = true;
}
else if(open == false && isOpen == true) // case not operational
{ Debug.Log("False True 5");
ReverseAnim_1();
isOpen = false;
Anim2();
open = true;
}
else if(open == true)
{
Debug.Log("True 6");
ReverseAnim_2();
open = false;
}
}
}
void ReverseAnim_1()
{
anim["1"].speed = -1;
anim["1"].time = anim["1"].length;
anim.Play();
}
void Anim1()
{
anim["1"].speed = 1;
anim.Play();
}
void Anim2()
{
anim["2"].speed = 1;
anim.Play();
}
void ReverseAnim_2()
{
anim["2"].speed = -1;
anim["2"].time = anim["2"].length;
anim.Play();
}
The problem is that you have two Main_B2 scripts and they are each tracking their own values for the isOpen and open fields.
One solution for this could be to make the fields static so that they are in common across all instances of Main_B2.
Animation anim;
private static bool isOpen = false;
private static bool open = false;
If you do this, your code should work as intended - each instance of Main_B2 would then be referring to the same fields whenever they reference isOpen or open.
With that said, static fields can get kind of sloppy if you ever want to try and re-use code so a better option might be to have only one instance of Main_B2 somewhere else such as the Canvas, instead of one on each button.
Then you could have in it public GameObject fields that you can drag the button objects into, and private Animation fields for the animations.:
public GameObject button1
public GameObject button2
private Animation anim1
private Animation anim2
Then in Start:
anim1 = button1.GetComponent<Animation>();
anim2 = button2.GetComponent<Animation>();
And then wherever you referred to anim you would refer to anim1 or anim2 instead:
void ReverseAnim_1()
{
anim1.["1"].speed = -1;
anim1.["1"].time = anim1["1"].length;
anim1.Play();
}
void Anim1()
{
anim1["1"].speed = 1;
anim1.Play();
}
void Anim2()
{
anim2["2"].speed = 1;
anim2.Play();
}
void ReverseAnim_2()
{
anim2["2"].speed = -1;
anim2["2"].time = anim2["2"].length;
anim2.Play();
}
Your scripts 'anim' variable is an Animation. Normally to adjust animation parameters you set them on an Animator, not Animation. But perhaps your solution can work.
For clarity. An animator organizes how animations play out, when, for how long and how they transition.
I would personally advise you to use an animator with behaviour patterns and transitionings between animations. Instead of the current approach.
Either that or use one of the many Tweening asset packs from the asset store. They are specifically made to create UI effects like what you describe.
At least consider these solutions if you keep being stuck :-)

Putting references on unity button so that I can use a function from another script

I made a Button Prefab that I want to use to increase the health of my player. What I have a problem with is that my gainHealth function is in my Player Script and I tried referencing it in my addListeners. I just want the to Health Button to give my player Health when clicked, the problem is that this button is a prefab.
void AddListeners()
{
itemButton.onClick.AddListener(() => GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerHealth>().GainHealth(50));
}
void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Player"))
{
for (int i = 0; i < inventory.slots.Length; i++)
{
if (inventory.isFull[i] == false)
{
inventory.isFull[i] = true;
Instantiate(itemButton, inventory.slots[i].transform, false);
AddListeners ();
Destroy(gameObject);
break;
}
}
}
}
You can put a script on your button prefab, and look something like this.
public PlayerHealth P_Health;
void Start()
{
P_Health = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerHealth>();
}
//Reference this action as Onclickevent through the Inspector inside your button
void OnMyClick()
{
P_Health.GainHealth(50);
}
Once the button is instantiated it will keep a reference of the PlayerHealth object and call the "GainHealth" function once the button is clicked.
You should put the "OnMyClick()" (or how you like to name it) function in the On Click Event of the button in your prefab editor.
Your approach is possible by changing a little thing. Currently your trying to add the listener directly to your prefab. Instead of this you should add the listener to the Button you instantiated with your Prefab.
An example that should work:
public GameObject itemButtonPrefab; // drag your Prefab to this field in the inspector
public Button itemButton; // the "real" instance of your prefab in the scene
void AddListeners()
{
itemButton.onClick.AddListener(() => GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerHealth>().GainHealth(50));
}
void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Player"))
{
for (int i = 0; i < inventory.slots.Length; i++)
{
if (inventory.isFull[i] == false)
{
inventory.isFull[i] = true;
itemButton = Instantiate(itemButtonPrefab, inventory.slots[i].transform, false).GetComponent<Button>();
AddListeners ();
Destroy(gameObject);
break;
}
}
}
}
PS: This example should also work an is slightly more performant due to the fact you don't have to call the GetComponent-method:
public Button itemButtonPrefab; // drag your Prefab to this field in the inspector
public Button itemButton; // the "real" instance of your prefab in the scene
void AddListeners()
{
itemButton.onClick.AddListener(() => GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerHealth>().GainHealth(50));
}
void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Player"))
{
for (int i = 0; i < inventory.slots.Length; i++)
{
if (inventory.isFull[i] == false)
{
inventory.isFull[i] = true;
itemButton = Instantiate(itemButtonPrefab, inventory.slots[i].transform, false);
AddListeners ();
Destroy(gameObject);
break;
}
}
}
}

A pause menu using a button and click

I'd like to know how I can pause and unpause menu from the same button using the mouse pointer when I click on it.
Lets say I have this. C#
void Update () {
if (Button_Pause.OnPointerClick()) {
if(!active){
PauseGame();
}
else{
ResumeGame();
}
active = !active;
}
}
public void PauseGame()
{
Button_Pause = Button_Pause.GetComponent<Button> ();
Canvas_PauseMenu.enabled = true;
Button_Exit.enabled = true;
Button_Pause.enabled = true;
}
public void ResumeGame()
{
Canvas_PauseMenu.enabled = false;
Button_Exit.enabled = false;
Button_Pause.enabled = false;
}
In the first line, where I call the OnPointerClick I'm just guessing because I don't know what to do. What I've searched around, using click to show something it's having a TimeScale or something like that.
¿Can anyone help moi? Please.
Add a listener for your button and in your pause script set timescale to zero to pause the game
[SerializeField] private Button MyButton = null; // assign in the editor
void Start() { MyButton.onClick.AddListener(() => { pause();});
}
void pause(){
if (Time.timeScale == 1)
{
Time.timeScale = 0;
}
else
{
Time.timeScale = 1;
}
}
I managed to solve the issue. It might not be efficient but it does what I need.
I created 2 buttons in the same place. Those buttons are represented with different sprites (Pause & Play). "Pause" is visible since the start. When I click on it, the menu pops up, the "Pause" stop being active and the "Play" sprite button activates and pops up too. When I click on it, I unpause and goes back to the "Pause" sprite visible in the screen.
void Start () {
Canvas_PauseMenu = Canvas_PauseMenu.GetComponent<Canvas> ();
Button_Pause = Button_Pause.GetComponent<Button> ();
Button_Resume = Button_Resume.GetComponent<Button> ();
Canvas_PauseMenu.enabled = false;
Button_Resume.enabled = false;
Button_Resume.gameObject.SetActive (false);
}
// Update is called once per frame
public void PauseTest () {
if(!active){
PauseGame();
}
else{
ResumeGame();
}
}
public void BackToMainMenu()
{
Application.LoadLevel (0);
}
public void PauseGame()
{
Canvas_PauseMenu.enabled = true;
Button_Exit.enabled = true;
Button_Pause.enabled = false;
Button_Pause.gameObject.SetActive (false);
Button_Resume.enabled = true;
Button_Resume.gameObject.SetActive (true);
active = true;
Time.timeScale = 0;
}
public void ResumeGame()
{
Canvas_PauseMenu.enabled = false;
Button_Exit.enabled = false;
Button_Pause.enabled = true;
Button_Pause.gameObject.SetActive (true);
Button_Resume.enabled = false;
Button_Resume.gameObject.SetActive (false);
active = false;
Time.timeScale = 1;
}

Categories

Resources