Pause button not working - c#

I am writing a pause button for my game (Game for mobile phones).
My Pause script:
using UnityEngine;
using System.Collections;
public class PauseScript : MonoBehaviour {
public bool paused;
// Use this for initialization
void Start () {
paused = false;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
paused = !paused;
}
if (paused)
{
Time.timeScale = 0;
}
else if (!paused)
{
Time.timeScale = 1;
}
}
public void Pause()
{
paused = !paused;
if (paused)
{
Time.timeScale = 0;
}
else if (!paused)
{
Time.timeScale = 1;
}
}
}
And Jump that is written like this jump = Input.GetButton("Fire1");
When I touch button my player jumps and the game does not pause.
How I can make my game pause and player doesn't jump?

Unity Docs: Time.timeScale
Except for realtimeSinceStartup, timeScale affects all the time and delta time measuring variables of the Time class.
if you want to actually use timeScale you need to use Time.deltaTime in your calculations. Like:
transfomr.position += Vector3.forward * speed * Time.deltaTime;
so, it's not going to magically pause all the scripts. Update(), FixedUpdate() and all the other MonoBehaviour functions will still get invoked normally. also, read about Time.deltaTime if you haven't already.

Related

How do I get my collision function into my private void Update() on Unity?

I have object 1 with rigid body and box collider, I want it to hit object 2 (also has collider and rigid body) so I can use the collision to stop object 1 for 5 seconds then have it move through object 2 whish has kinematics on
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TRAINMOVE : MonoBehaviour
{
private int speed = 200;
private Rigidbody rb;
// Start is called before the first frame update
void Start()
{
StartCoroutine(WaitBeforeMove());
}
// Update is called once per frame
private void Awake()
{
rb = GetComponent<Rigidbody>();
}
private void Update()
{
rb.AddForce(transform.up * speed * Time.deltaTime);
}
//void OnCollision(Collision stop)
// {
// if (stop.gameObject.name == "train trigger station1")
// {
// speed = 0;
// WaitBeforeMove();
// speed = 200;
// rb.AddForce(transform.up * speed * Time.deltaTime);
// }
// else
// {
// speed = 200;
// }
// }
IEnumerator WaitBeforeMove()
{
yield return new WaitForSeconds(5);
}
}
Thats not exactly how Coroutines work.
The method/message you are looking for is called OnCollisionEnter. If it is not exactly written like that and with the expected signature then Unity doesn't find it and never invokes it.
A Coroutine does not delay the outer method which runs/starts it.
A Coroutine has to be started using StartCoroutine otherwise it does nothing (or at least it only runs until the first yield statement).
private void OnCollisionEnter(Collision stop)
{
if (stop.gameObject.name == "train trigger station1")
{
StartCoroutine(WaitBeforeMove());
}
}
private IEnumerator WaitBeforeMove()
{
speed = 0;
// Note that without this you would have no force applied but still the remaining velocity it already has
rb.velocity = Vector3.zero;
yield return new WaitForSeconds(5f);
speed = 200;
}
The method/message OnCollisionEnter can be a Courine itself! So in your specific case you actually can just do
// By making this an IEnumerator Unity automatically starts it as a Coroutine!
private IEnumerator OnCollisionEnter(Collision stop)
{
if (stop.gameObject.name == "train trigger station1")
{
speed = 0;
rb.velocity = Vector3.zero;
yield return new WaitForSeconds(5f);
speed = 200;
}
}
Finally instead of permanently continue to add 0 force I would in general rather use a simple bool flag and pause the adding of force entirely.
You should AddForce not every frame but rather in FixedUpdate.
And then you should not multiply force by Time.deltaTime. Since it is applied in fixed time intervals in FixedUpdate it is already a frame-rate independent event.
private bool stopped;
private void FixedUpdate()
{
if(stopped) return;
rb.AddForce(transform.up * speed);
}
// By making this an IEnumerator Unity automatically starts it as a Coroutine!
private IEnumerator OnCollisionEnter(Collision stop)
{
if (stop.gameObject.name == "train trigger station1")
{
stopped = true;
rb.velocity = Vector3.zero;
yield return new WaitForSeconds(5f);
stopped = false;
}
}
I suggest instead of comparing a name you should rather use a Tag and use stop.gameObject.CompareTag("Station")

Prevent a player from spamming a key in C# (Unity)

I am currently doing the tutorial learn with code from unity, in this section there are bonus challenges, that do not help you in resolving it. It says that i have to prevent the player from spamming the spacebar key to spawn dogs.
I am new to C#, i started to looking online but i see something about CoRoutines and i still dont know what that is, is there a simple way to do this, searching online i found something like this, but i cant make it work.
I also tried to make some conditional like canSpawn but i do not know how to implement it well, and Unity gives me an error that i cant use && between a bool and a keypress event
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControllerX : MonoBehaviour
{
public GameObject dogPrefab;
public float time = 2.0f;
public float timer = Time.time;
// Update is called once per frame
void Update()
{
timer -= Time.deltaTime;
if (timer > time)
{
// On spacebar press, send dog
if (Input.GetKeyDown(KeyCode.Space))
{
spawnDog();
}
timer = time;
}
void spawnDog()
{
Instantiate(dogPrefab, transform.position, dogPrefab.transform.rotation);
}
}
You were close. One thing that might make it easier to understand the logic, is to just count up instead of trying to count down. So, in your case, the code would look like this:
void Update ( )
{
timer += Time.deltaTime;
if ( timer >= time )
{
if ( Input.GetKeyDown ( KeyCode.Space ) )
{
spawnDog ( );
timer = 0;
}
}
}
void spawnDog ( )
{
Instantiate ( dogPrefab, transform.position, dogPrefab.transform.rotation );
}
The timer keeps being added to, and when it's greater than your time value (in this case 2.0f), it allows you to press a key. IF a key is then pressed, the timer is reset to 0, and the player needs to wait time time (2.0f) before being able to press the space key again.
I used Coroutines for this task, it has a little bit more code but it works nicely.
public class PlayerControllerX : MonoBehaviour
{
public GameObject dogPrefab;
private bool isCoolDown = false;
private float coolDown = 1f;
private void Update( )
{
if (Input.GetKeyDown(KeyCode.Space))
{
if (isCoolDown == false)
{
SpawnDog( );
StartCoroutine(CoolDown( ));
}
}
}
IEnumerator CoolDown( )
{
isCoolDown = true;
yield return new WaitForSeconds(coolDown);
isCoolDown = false;
}
private void SpawnDog( )
{
Instantiated(dogPrefab, transform.position, dogPrefab.transform.rotation);
}
}
I am using my phone. I am sorry if i made some syntax error.
bool isReadyForInstantiate;
void Start(){
isReadyForInstantiate = true;
}
void Update(){
if(isReadyForInstantiate && Input.GetKeyDown(KeyCode.Space)){
StartCoroutine(PreventSpam());
Instantiate(dogPrefab, transform.position, Quaternion.identity);
}
}
IEnumerator PreventSpam(){
isReadyForInstantiate = false;
yield return new WaitForSeconds(2);
isReadyForInstantiate = true;
}
here my solution based on a StopWatch:
using UnityEngine;
using System.Diagnostics; // hides UnityEngine.Debug. if needed use qualified call
public class PlayerControllerX : MonoBehaviour
{
public GameObject dogPrefab;
public double dogDelayMillis = 2000d;
private Stopwatch stopWatch;
private void Start()
{
stopWatch = new Stopwatch();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
if (stopWatch.IsRunning)
{
if (stopWatch.Elapsed.TotalMilliseconds > dogDelayMillis)
{
stopWatch.Reset();
SpawnDog();
}
}
else
{
SpawnDog();
}
}
}
private void SpawnDog()
{
stopWatch.Start();
Instantiate(dogPrefab, transform.position, dogPrefab.transform.rotation);
}
}
Another example just for fun
public GameObject dogPrefab;
[Range(0f,2f)]
private float timer = 1.0f;
private float waitTime = 1.0f;
// Update is called once per frame
void Update()
{
// Delay Input Timer - only execute the spacebar command if timer has caught up with waitTime
if (timer < waitTime)
{}
// On spacebar press, send dog
else if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(dogPrefab, transform.position, dogPrefab.transform.rotation);
// Resets Timer
timer = 0;
}
// Run Timer every frame
timer += Time.deltaTime;
Debug.Log(timer);
}
}
I was stuck on the same exact thing, thank you. The code below is what I went with because it's short and sweet.
public GameObject dogPrefab;
[Range(0f,2f)]
private float timer = 1.0f;
private float waitTime = 1.0f;
// Update is called once per frame
void Update()
{
// Delay Input Timer - only execute the spacebar command if timer has caught up with waitTime
if (timer < waitTime)
{}
// On spacebar press, send dog
else if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(dogPrefab, transform.position, dogPrefab.transform.rotation);
// Resets Timer
timer = 0;
}
// Run Timer every frame
timer += Time.deltaTime;
Debug.Log(timer);
}
}

Time.Timescale is not pausing the game

This is the script of a ball game that I am building.
The game is supposed to pause once it hits Time.timescale but it doesn't.
I need to know what I did wrong and what I need to change here.
I am a beginner in Unity and C# so i might have messed up everything.
If there is any other way to pause the game rather than using Time.timescale i would like to know it also.
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class PauseScript : MonoBehaviour
{
public bool paused = false;
void Start()
{
paused = false;
Time.timeScale = 1;
}
// Update is called once per frame
public void Pause()
{
if (Input.GetKeyDown("p") && paused == false)
{
Time.timeScale = 0;
paused = true;
}
if (Input.GetKeyDown("p") && paused == true)
{
Time.timeScale = 1;
paused = false;
}
}
}
Ball.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
public class Ball : MonoBehaviour
{
//configuration parameter
[SerializeField] Paddle paddleInitial;
[SerializeField] float horizontalPush = 2f;
[SerializeField] float verticalPush = 15f;
[SerializeField] AudioClip[] ballSounds;
//state parameter
Vector2 paddleToBallVector;
bool mouseButtonClicked = false;
//Cached COmponent References
AudioSource myAudioSource;
// Start is called before the first frame update
void Start()
{
paddleToBallVector = transform.position - paddleInitial.transform.position;
myAudioSource = GetComponent<AudioSource>();
}
// Update is called once per frame
void Update()
{
if (mouseButtonClicked == false)
{
stickBallToPaddle();
launchOnMouseClick();
}
if (Input.GetMouseButtonDown(1))
{
GetComponent<Rigidbody2D>().velocity = new Vector2(horizontalPush,verticalPush);
}
}
private void launchOnMouseClick()
{
if (Input.GetMouseButtonDown(0))
{
mouseButtonClicked = true;
GetComponent<Rigidbody2D>().velocity = new Vector2(horizontalPush, verticalPush);
}
}
private void stickBallToPaddle()
{
Vector2 paddlePosition = new Vector2(paddleInitial.transform.position.x, paddleInitial.transform.position.y);
transform.position = paddlePosition + paddleToBallVector;
}
//audio settings
private void OnCollisionEnter2D(Collision2D collision)
{
if (mouseButtonClicked)
{
AudioClip clip = ballSounds[UnityEngine.Random.Range(0, ballSounds.Length)];
myAudioSource.PlayOneShot(clip);
}
}
}
There are a couple of potential issues.
Your function should be called Update, or it won't run once per frame
Input.GetKeyDown returns if a key has started being pressed, but this persists on the current frame (it's only reset before the next Update call, so it will return true every time you call it in the same Update function block)
When you hit P, you check if the key is down then set the pause flag/timescale, but then you do another if check in the update method that does the opposite.
// Update is called once per frame
public void Pause()
{
// The p key is down and the game isn't paused, set timescale to 0 and paused to true...
if (Input.GetKeyDown("p") && paused == false)
{
Time.timeScale = 0;
paused = true;
}
// The p key is still down since we are on the same frame and paused flag is set so here we set timescale to 1 and paused to false...
if (Input.GetKeyDown("p") && paused == true)
{
Time.timeScale = 1;
paused = false;
}
}
You probably want to make sure only one of these conditions runs per update and ensure the function is called Update or it won't run once per frame
// Update is called once per frame
public void Update()
{
if (Input.GetKeyDown("p") && paused == false)
{
Time.timeScale = 0;
paused = true;
}
// Use else to make sure this block only gets executed if the above doesn't
else if (Input.GetKeyDown("p") && paused == true)
{
Time.timeScale = 1;
paused = false;
}
}
There are many ways to skin a cat so to speak; alternative code could look something like this:
public void Update()
{
if(Input.GetKeyDown("p"))
{
// Toggle paused
paused != paused;
// Use ternary operator to save lines because making code harder to read is fun
Time.timeScale = paused ? 0 : 1;
}
}
-- Edit:
Also make sure you are multiplying any vectors for movement etc by deltaTime each frame - otherwise your simulation will continue.
You may also need to explicitly handle paused for other aspects such as animations etc - it depends on how they are implemented, but as long as they consider the delta frame by frame they will react when timeScale is set to 0 as expected.

Unity power-up is not working as intended

First off, I am quite new to scripting so there's probably going to be a few flaws in my script.
So basically, I've made a script for the power up, but once my shot or the player touches the power up coin the fire rate does increase however it won't go back to the normal fire rate after 5 seconds... I have no idea what might be the cause, any advice would be helpful!
using UnityEngine;
using System.Collections;
public class FireRatePowerUp : MonoBehaviour {
private bool isPowerUp = false;
private float powerUpTime = 5.0f;
private PlayerShoot playerShoot;
private void Start()
{
playerShoot = PlayerShoot.FindObjectOfType<PlayerShoot>();
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Player" || collision.gameObject.tag == "Projectile")
{
StartCoroutine(PowerUpTime());
isPowerUp = true;
Destroy(gameObject);
if (collision.gameObject.tag == "Projectile")
{
Destroy(collision.gameObject);
}
}
}
IEnumerator PowerUpTime()
{
playerShoot.fireRate -= 0.13f;
yield return new WaitForSeconds(powerUpTime);
playerShoot.fireRate += 0.13f;
}
}
I think the issue here is that you're destroying the gameobject this script is attached to (the coin) and by so doing, the script itself is destroyed, therefor its code, coroutine or otherwise won't execute.
StartCoroutine(PowerUpTime());
isPowerUp = true;
Destroy(gameObject); //oops, our script has been destroyed :(
You would have to do this very differently, basically moving the bulk of the code to the PlayerShoot class.
Something like this (this being in PlayerShoot.cs)
public void ActivatePowerupFireRate(float time, float amt) {
StartCoroutine(DoActivatePowerupFireRate(time, amt));
}
public IEnumerator ActivatePowerupFireRate(float time, float amt) {
fireRate -= amt;
yield return WaitForSeconds(time);
fireRate += amt;
}
IEumerator is definately one of the ways you can solve this issue.
However I'm not a fan of them here's my solution if you have a timer in game.
public int timePassed = 0;
public int gotPowerUp = 0;
void Start(){
InvokeRepeating("Timer", 0f, 1.0f);
//Starting at 0 seconds, every second call Timer function.
}
void Timer(){
timePassed++; // +1 second.
}
That way when you obtained the powerup you can set gotPowerUp = timePassed. So you have the exact time when powerup is activated.
then you do something like
if( (gotPowerUp + 5) == timePassed ){
//5 seconds have passed.
//deactivate powerup here
}

quitting from a pause menu to restart from the title screen C#

The game restarts fine if you win or lose. The player has the option of going back to the title screen from either of those scenes. But the problem occurs when you pause the game and quit from the pause menu. If you do, the title screen is loaded but there is no music and no way to go navigate further. It does, for some reason, allow you to navigate to the credits (without music) and back to the title screen, but no further. The order is, title screen, tutorial screen, level 1. I don't know if it has anything to do with it, but the pause menu that shows is just a canvas that is enabled/disabled when you press space. Here's the pause script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class pauseScript : MonoBehaviour {
private bool isPaused = true;
public GameObject pauseMenuCanvas;
public AudioSource audioSource;
public AudioClip Paused;
public AudioClip notPressingStart;
void Awake ()
{
audioSource = GetComponent<AudioSource> ();
}
void Update ()
{
Sound ();
Pausing ();
}
void Pausing()
{
if (!isPaused && Input.GetKeyDown (KeyCode.Escape))
{
Application.LoadLevel ("titleScreen");
}
if (!isPaused) {
Time.timeScale = 0f;
pauseMenuCanvas.SetActive (true);
isPaused = false;
AudioListener.volume = 0f;
} else {
Time.timeScale = 1f;
pauseMenuCanvas.SetActive (false);
isPaused = true;
AudioListener.volume = 1f;
}
if (Input.GetKeyDown (KeyCode.Space)){
isPaused = !isPaused;
}
}
void Sound()
{
if (Input.GetKeyDown (KeyCode.Space))
audioSource.PlayOneShot (Paused, 7f);
}
}
Within:
if (!isPaused && Input.GetKeyDown (KeyCode.Escape))
{
Application.LoadLevel ("titleScreen");
}
if (!isPaused) {
Time.timeScale = 0f;
pauseMenuCanvas.SetActive (true);
isPaused = false;
AudioListener.volume = 0f;
}
When you check to see if "KeyCode.Escape" is pressed while "!isPaused == true", the "titleScreen" is loaded but the next line:
if (!isPaused)...
will always be true when going to the "titleScreen" which always turns the volume to 0
AudioListener.volume = 0f;

Categories