Creating a start menu in Unity 3D - c#

I was trying to create a start menu to my unity game when I found this script that enables a hidden sprite as soon as the game starts. The script then disables it when the player presses the left mouse button or space. When I try to make multiple sprites show up and the disappear, using the same script, only one sprite appears. I'm also trying to find a way to change the scipt so that the payer have to click on the actual sprite to disable it instead of just pressing the space key.
This is the script:
using UnityEngine;
using System.Collections;
public class StartScreen : MonoBehaviour {
static bool sawOnce = false;
// Use this for initialization
void Start () {
if(!sawOnce) {
GetComponent<SpriteRenderer>().enabled = true;
Time.timeScale = 0;
}
sawOnce = true;
}
// Update is called once per frame
void Update () {
if(Time.timeScale==0 && (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0)) ) {
Time.timeScale = 1;
GetComponent<SpriteRenderer>().enabled = false;
}
}
}

It sounds as if you are looking to do something like this: http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnMouseDown.html
Also, I always create a separate scene for my main menu systems, as they have done in that link.

Related

How can I make another click on escape key that will return to the game?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class BackToMainMenu : MonoBehaviour
{
public PlayerCameraMouseLook cammouselook;
// Update is called once per frame
void Update ()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex - 1);
PlayerCameraMouseLook.mouseLookEnable = false;
cammouselook.enabled = true;
}
}
}
Now when pressing the escape key it's loading the main menu scene.
And in the main menu I have NEW GAME button but not RESUME.
Instead making a resume button I want that pressing the escape key again when the main menu scene is loaded it will return back to the game to the current position it is. Either if it's in a middle of a cutscene or just idle in the game.
So when pressing the escape key again it will back to the game and continue from the last point.
Another sub question : Should I use : LoadSceneMode.Additive ? Or when switching between the game play scene and the main menu it should remove the current active scene and then load the next one ?
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex - 1, LoadSceneMode.Additive);
The main menu scene is at index 0 the game scene at index 1.
What I tried :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class BackToMainMenu : MonoBehaviour
{
// Variables
private bool _isInMainMenu = false;
public GameObject mainGame;
public PlayerCameraMouseLook cammouselook;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (!_isInMainMenu)
{
SceneManager.LoadScene(0, LoadSceneMode.Additive);
PlayerCameraMouseLook.mouseLookEnable = false;
cammouselook.enabled = true;
// -- Code to freeze the game
mainGame.SetActive(false);
}
else
{
SceneManager.UnloadSceneAsync(0);
// -- Code to unfreeze the game
mainGame.SetActive(true);
}
_isInMainMenu = !_isInMainMenu;
}
}
}
And the Hierarchy :
The script is attached to the Back to main menu gameobject. And all the game objects are under Main Game.
First time when pressing the escape key it's loading to the main menu and main menu scene to the hierarchy. Second time pressing on the escape key it's starting the game over like a new game and removing unloading the main menu.
In both cases the game scene is stay in the hierarchy.
I will suggest you to add your main menu scene with the flag Additive as you mentioned.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class BackToMainMenu : MonoBehaviour
{
// Variables
private bool _isInMainMenu = false;
public PlayerCameraMouseLook cammouselook;
// Update is called once per frame
void Update ()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (!_isInMainMenu)
{
SceneManager.LoadScene(0, LoadSceneMode.Additive);
PlayerCameraMouseLook.mouseLookEnable = false;
cammouselook.enabled = true;
// -- Code to freeze the game
}
else
{
SceneManager.UnloadSceneAsync(0);
// -- Code to unfreeze the game
}
_isInMainMenu = !_isInMainMenu;
}
}
}
Take a look at the variable _isInMainMenu : it will track if you are in the main menu or not. Depends on the value, the Escape key will behave differently.
Note : I suggest you to type the current index of the scene in LoadScene / UnloadSceneAsync, unless you may want to change their index. In this scenario, type the scene name (Methods overload).
Now what I mean with // -- Code to freeze the game depends on your game :
You can have a unique GameObject that contains all the others GameObjects your scene has, and Enable / Disable it
myBigGameObject.SetActive(true/*or false*/);
Have a logic in MonoBehaviour to freeze the game while your in the main menu.
For example you can use the bool _isInMainMenu in Update() to stop them from doing their job ;
For example in this MonoBehaviour I created as an example :
public class ExampleMonoBehaviour : MonoBehaviour
{
private void Update ()
{
if (_isInMainMenu)
return;
print("I'm running !");
}
}
Have a Collection (List as an example) that stores every top hierarchy GameObjects and enable/disable them all as needed to behave the same as above.
Depends on how your code is, there is many other options.
I will highly suggest you to do the first or third option, unless you have a better approach.
The thing is, if you want to go back to the main menu, it shouldn't be very expansive (loading time, memory usage, ...) so you can disable GameObject from the main scene (third point) to restore them back quickly when you leave the main menu without reloading the entire scene. This would lead you to use serialization and deserialization.
Edited : Typo

How to resume game after pressing back in menu

Hey I am trying to make a pause menu in my game. When escape is pressed pause game go to menu, but now I want to be able to press back in menu and resume my game. So far I can only pause game and cant press back. Also if i press Play in menu it starts at my tutorial scene and not the current scene. Is there a smart way to do this? Without resetting my game.
`using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class MenuScript : MonoBehaviour
{
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.Escape))
{
if (Time.timeScale == 0)
{
Time.timeScale = 1;
}
else
{
Time.timeScale = 0;
}
SceneManager.LoadScene("Menu");
}
}
}`
I get that this isn't straightforward problem since you seem new to Unity.
You got the idea correctly, changing the time scale will freeze all agents on the scene. HOWEVER, if you load a new scene you'll need to reload the game scene - losing any data you had (and that is not what you want). My advice is creating an overlay element (UI) on the game scene and just show/hide it. There are multiple tutorials online use this as an starting point. Let me know if you require more help.
code sample
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.Escape))
{
if (Time.timeScale == 0)
{
Time.timeScale = 1;
pauseMenu.gameObject.setActive(true);
}
else
{
Time.timeScale = 0;
pauseMenu.gameObject.setActive(false);
}
}
}
You will need a reference to the pauseMenu game object attached on this script using the Unity editor.
Depending on what you need, this would work as well.
private bool _isPaused;
private void Update(){
if (Input.GetKeyUp(KeyCode.Escape))
{
_isPaused = !_isPaused;
if (_isPaused)
{
//Do Pause Logic here
}
else
{
//Do Unpause Logic Here
}
}
}

How to check if a certain animation state from an animator is running?

I created an animator called "m4a4animator". Inside it, the main function is called "idle" (nothing), and other 2 states: "shoot" (mouse0) and "reload" (R). These 2 animation states are transitioned to "idle". Now, everything is working... but the only problem I have is this: if I am in the middle of reloading and and press mouse0 (shoot), the animation running state immediately changes to shoot... but I want to block that.
Now, the question: How can I stop CERTAIN animation changes while an animation is running?
Here is my animator
And here is my script:
using UnityEngine;
using System.Collections;
public class m4a4 : MonoBehaviour {
public Animator m4a4animator;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (KeyCode.R)) {
m4a4animator.Play("reload");
}
if (Input.GetMouseButton(0)) {
m4a4animator.Play("shoot");
}
}
}
For the legacy Animation system, Animation.IsPlaying("TheAnimatonClipName) is used to check if the animation clip is playing.
For the new Mechanim Animator system, you have to check if both anim.GetCurrentAnimatorStateInfo(animLayer).IsName(stateName) and anim.GetCurrentAnimatorStateInfo(animLayer).normalizedTime < 1.0f) are true. If they are then animation name is currently playing.
This can be simplified like the function like the Animation.IsPlaying function above.
bool isPlaying(Animator anim, string stateName)
{
if (anim.GetCurrentAnimatorStateInfo(animLayer).IsName(stateName) &&
anim.GetCurrentAnimatorStateInfo(animLayer).normalizedTime < 1.0f)
return true;
else
return false;
}
Now, everything is working... but the only problem I have is this: if
I am in the middle of reloading and and press mouse0 (shoot), the
animation running state immediately changes to shoot... but I want to
block that.
When the shoot button is pressed, check if the "reload" animation is playing. If it is, don't shoot.
public Animator m4a4animator;
int animLayer = 0;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.R))
{
m4a4animator.Play("reload");
}
//Make sure we're not reloading before playing "shoot" animation
if (Input.GetMouseButton(0) && !isPlaying(m4a4animator, "reload"))
{
m4a4animator.Play("shoot");
}
}
bool isPlaying(Animator anim, string stateName)
{
if (anim.GetCurrentAnimatorStateInfo(animLayer).IsName(stateName) &&
anim.GetCurrentAnimatorStateInfo(animLayer).normalizedTime < 1.0f)
return true;
else
return false;
}
If you need to wait for the "reload" animation to finish playing before playing the "shoot" animation then use a coroutine. This post described how to do so.
There are other threads about that: https://answers.unity.com/questions/362629/how-can-i-check-if-an-animation-is-being-played-or.html
if (this.animator.GetCurrentAnimatorStateInfo(0).IsName("YourAnimationName"))
{
//your code here
}
this tells you if you are in a certain state.
Animator.GetCurrentAnimatorStateInfo(0).normalizedTime
this give you the normalized time of the animation: https://docs.unity3d.com/ScriptReference/AnimationState-normalizedTime.html
Try to play with those function, I hope that solve your problem

Why i'm getting error the animation clip name Up not found?

I have a GameObject empty i renamed it to be called: Elevator.
Under it as childs i have platform, platform1, and a button.
what i want to do is when the player ThirdPersonController is standing on platform and then click the button the elevator will move up and down none stop.
In the screenshot the Hierarchy and the script i called it Lift and the animations: Elevator and Up and Down. First i selected the Elevator then in the menu i did Window > Animation then i created animation called it Elevator but i didn't do with it anything. Then i created more two animations called them: Up and Down. When i play the Up the empty GameObject move up with the all the childes. When i play the down it's moving down.
The script Lift is attached to the Button. I also added a component Animation to the GameObject(Elevator).
This is the screenshot:
This is the c# script:
using UnityEngine;
using System.Collections;
public class Lift : MonoBehaviour {
private bool pressedButton = false;
private bool isElevatorUp = false;
GameObject target;
void OnMouseOver()
{
pressedButton = true;
}
void OnMouseExit()
{
pressedButton = false;
}
void OnMouseDown()
{
if(isElevatorUp == false)
{
target = GameObject.Find("Elevator");
target.GetComponent<Animation>().Play("Up");
isElevatorUp = true;
}
else
{
target = GameObject.Find("Elevator");
target.GetComponent<Animation>().Play("Down");
isElevatorUp = false;
}
}
void OnGUI()
{
if(pressedButton == true)
{
GUI.Box(new Rect(300, 300, 200, 20), "Press to use lift!");
}
}
}
In the Elevator Inspector i dragged to the Animation the Up animation clip.
When running the game i'm getting two messages:
With the sign '!' Default clip could not be found in attached animation list.
A warning: The AbimationClip 'Up' used by the Animation component "Elevator" must be marked as Legacy.
When i move the mouse over the button i see a small box: "Press to use lift!"
When i click the button i see error message:
The animation state Up could not be played because it couldn't be found!
Please attach an animation clip with the name 'Up' or call this function only for existing animations.

Pause don't works (Unity c#)

I writing runner game on Unity (C#) for mobile phones.
I made Pause button on screen, using Canvas - Button.
Also I made code for Pause in Platformer2DUserControl script.
Here it is code of this script:
using UnityEngine;
using UnitySampleAssets.CrossPlatformInput;
namespace UnitySampleAssets._2D
{
[RequireComponent(typeof(PlatformerCharacter2D))]
public class Platformer2DUserControl : MonoBehaviour
{
private PlatformerCharacter2D character;
private bool jump;
public bool paused;
private void Awake()
{
character = GetComponent<PlatformerCharacter2D>();
paused = false;
}
private void Update()
{
/*if (Input.GetButton("Fire1"))
{
}*/
if (!jump)
// Read the jump input in Update so button presses aren't missed.
jump = Input.GetButton("Fire1"); //&& CrossPlatformInputManager.GetButtonDown("Jump");
}
private void FixedUpdate()
{
// Read the inputs.
bool crouch = Input.GetKey(KeyCode.LeftControl);
// float h = CrossPlatformInputManager.GetAxis("Horizontal");
// Pass all parameters to the character control script.
character.Move(1, false, jump);
jump = false;
}
public void Pause()
{
if (!jump)
// Read the jump input in Update so button presses aren't missed.
jump = Input.GetButton("Fire1"); //&& CrossPlatformInputManager.GetButtonDown("Jump");
paused = !paused;
if (paused)
{
jump = !jump;
Time.timeScale = 0;
}
else if (!paused)
{
// jump = Input.GetButton("Fire1");
Time.timeScale = 1;
}
}
}
}
My Pause Button is WORKS well. But when I tap it , my character is jumping and game is pausing.
I want to make that , when I tapping the button game just pausing and character don't jump.
How I can make it. Thank's for help.
I would advise you not to use the same input for jumping and pausing. Also, separate your jump and pause functionalities into separate functions. For pausing, create a UI button on the screen and make it call a public function on a Pause script, that will toggle pause. Then, in the same function, check if you are paused or not and adjust Time.timescale accordingly
You will have to attach the script with pause functionality on to an object that will always be in a screen (Say, a panel in your canvas or your MainCamera). Under the button, add a new onClick() function after dragging the GO with the apt script to the box. Then, select the public function aforementioned.
private bool paused = false;
//The function called by the button OnClick()
public void TogglePause()
{
paused = !paused;
if(paused)
Time.timescale = 0f;
else
Time.timescale = 1f;
}
Hope this helped!
Well, your code is messed up, but just remove the jump script from the pause method. So it will just pause...
public void Pause()
{
paused = !paused;
if (paused)
{
Time.timeScale = 0;
}
else
{
Time.timeScale = 1;
}
}
Note that Input.GetButton should only be called in Update
EDIT
The problem that you have to tap your screen to press the button. And the code jump = Input.GetButton("Fire1"); basically means "Am I tapping the screen?" So both JUMP and PAUSE are triggered.
One solution would be to put a canvas filling the whole screen under your buttons. You will trigger a JUMP action only when this canvas is clicked. So when you click your pause button, it will stop the propagation and won't click the full screen canvas, which won't trigger the jump action.
EDIT2
Try changing the lines (in the Update function) :
if (!jump)
// Read the jump input in Update so button presses aren't missed.
jump = Input.GetButton("Fire1");
for :
if (!jump && !paused)
// Read the jump input in Update so button presses aren't missed.
jump = Input.GetButton("Fire1");
I think the button event is called before the Update, see reference
One solution would be possible make sure the raycast on of pause button.
I have always done it like this, essentially surround the entire fixed update (or wherever you have your game motion) with the paused-bool
private void FixedUpdate()
{
if (paused != true){
// Read the inputs.
bool crouch = Input.GetKey(KeyCode.LeftControl);
// float h = CrossPlatformInputManager.GetAxis("Horizontal");
// Pass all parameters to the character control script.
character.Move(1, false, jump);
jump = false;
}
}

Categories