UnifyCommunity PauseMenu

*** Updated to relocated links ***

Almost long time ago, I implemented this pause menu to learn UnityGUI and put it on the Unity wiki:

http://wiki.unity3d.com/index.php/PauseMenu

Recently, I’ve been getting more emails and individual PM’s with questions about this script. I’m pleased to discover the script is actually getting used, but I usually refer the questioners to this forum and http://answers.unity3d.com/ because I don’t want be in the business of free individual programming support (I try to charge for that), and most of the questions really are general programming issues. So I’m starting this thread so users of this script can help each other out (perhaps even add functionality), and questions and answers don’t have to be repeated (I’ve seen some people in the Unity forum and answers site help out, already -thanks!)

I’ll start off with some quick answers to some recent queries:

“What are the terms of use?” - Do anything you want with it.

“I’m getting an error with the SepiaToneFilter” - Image effects including the sepia tone filter are a Unity Pro feature - just comment out the that line in the script.

“When the game is paused, keyboard input still comes through.” - Look at the definition of PauseGame, it pauses time and the audio listener. If all input was disabled, you couldn’t operate the menu! Add the appropriate code to your input-handling scripts, e.g. check if the timescale is zero.

“How do I use this on an iPhone” - this script was only used for Unity webplayers, so if you want to use it on an iPhone, you’ll have to change the OnGUI function, at the very least replace the Input.GetKeyDown check with something appropriate for how you want to invoke the menu.

Before asking any questions, please acquaint yourself with the UnityGUI functions (there’s a walkthrough in the Unity manual) and try to understand how the pause menu script works. I wrote a general breakdown of the script here (moved to Medium):

https://medium.com/technicat-on-software/don-t-use-this-pause-menu-572ea107c383

I should mention the C# version of the PauseMenu on the wiki was contributed by someone else.

I’m currently creating a FPS game. I need to create a pause button for my pause menu. I’ve found an excellent pause script here: http://www.unifycommunity.com/wiki/index.php?title=PauseMenu
I’m currently using the free version of Unity3D. I was able to get the pause script working within the game when I first start the game.
On the PC, press ESC key reloads the pause menu.
My questions is, how do I create a button or text link which reloads the Pause menu on screen for an iPhone device?
Any help is appreciated, Thank you

Look in the OnGUI function, replace the check for the ESC key with something appropriate, e.g. you can place another UnityGUI button for “Pause”. That should be straightforward if you’ve gone through the UnityGUI walkthrough in the Unity manual.

I encourage users of this pause menu to also consider GUIKit and EZGUI from http://gameassets.net/ and http://anbsoft.com/ respectively. I haven’t used either of them, but from what I’ve seen in their discussion threads on this forum, they provide a lot of support for the price.

I’m currently working on using the GameHUD script’s code to get the script to scale correctly: (from Lerpz tutorial)

// Our GUI is laid out for a 1920 x 1200 pixel display (16:10 aspect). The next line makes sure it rescales nicely to other resolutions.
	GUI.matrix = Matrix4x4.TRS (Vector3(0, 0, 0), Quaternion.identity, Vector3 (Screen.height / nativeVerticalResolution, Screen.height / nativeVerticalResolution, 1));

My font scales nicely whenever I use this, and also scales my images very nicely, but when I use the pause script in the nude (no changes) everything changes sizes when I alter the screen size. In other words the buttons don’t scale, the positioning doesn’t scale, and my font especially doesn’t scale. I need the GUI to scale depending on monitor/window size in order to incorporate a wider audience.

Small screen, BIG PAUSE MENU

BIG SCREEN, small pause menu

Notice how my HUD items scale nicely with the screen, but the pause menu does not. I don’t know how to work the script correctly (or well enough) to get the code shown above to work correctly (If I add it, the buttons and words scale right, but it’s lop-sided and no longer centered)

I’m not that familiar with the Lerpz code or with GUI.matrix for that matter (although there’s a discussion here - http://forum.unity3d.com/threads/68285-Unity-3-causes-GUI.Button-to-be-much-smaller ) but I’m guessing the problem is that the PauseMenu is trying to take the screen size into account for positioning and so using GUI.matrix to apply another adjustment for screen size will mess up that positioning. Try changing the BeginPage function to just use the same hardcoded screensize that you’re supplying to GUI.matrix (instead of Screen.width and height)

I’ve currently gotten it to scale correctly with the default Lerpz tutorial size. The only thing I can’t get to scale at the moment is the positions (like the offsets). Though surprisingly, just by switching a few values I’ve gotten it to scale and to position vertically correctly. I’ll actually give you the altered script with the scaling ability once I figure it all out. Right now I’ve only got about half of it figured out and will need some time to figure out the rest.

EDIT:

I have figured it out and scaled all of the buttons and components to fit… ANY SCREEN

Here you go Technicat ^^

BTW, I had my own legal information in the code, so I stripped it out and replaced it with dummy information, you can put your information back in. Also the “Begin Paused” code stuff was taken out for my own purposes, but the concept remains the same.

var skin:GUISkin;


private var gldepth = -0.5;
private var startTime = 0.1;

var nativeVerticalResolution = 1200.0;
var scaledResolutionWidth = nativeVerticalResolution / Screen.height * Screen.width;

var mat:Material;

private var tris = 0;
private var verts = 0;
private var savedTimeScale:float;
private var pauseFilter;

private var showfps:boolean;
private var showtris:boolean;
private var showvtx:boolean;
private var showfpsgraph:boolean;

var lowFPSColor = Color.red;
var highFPSColor = Color.green;

var lowFPS = 30;
var highFPS = 50;

var start:GameObject;

var url = "unity.html";

var statColor:Color = Color.yellow;
var GuiColor:Color = Color.white;

var credits:String[]=[
    "Credits This stuff",
	"I put a Catchphrase here haha",
    "Programming by Me!",
    "Copyright (c) 100BC-2011"] ;
var crediticons:Texture[];

enum Page {
    None,Main,Options,Credits
}

private var currentPage:Page;

private var fpsarray:int[];
private var fps:float;

function Start() {
    fpsarray = new int[scaledResolutionWidth];
    Time.timeScale = 1.0;
    //pauseFilter = Camera.main.GetComponent(SepiaToneEffect);
    //PauseGame();
}

function OnPostRender() {
    if (showfpsgraph  mat != null) {
        GL.PushMatrix ();
        GL.LoadPixelMatrix();
        for (var i = 0; i < mat.passCount; ++i)
        {
            mat.SetPass(i);
            GL.Begin( GL.LINES );
            for (var x=0; x<fpsarray.length; ++x) {
                GL.Vertex3(x,fpsarray[x],gldepth);
            }
        GL.End();
        }
        GL.PopMatrix();
        ScrollFPS();
    }
}

function ScrollFPS() {
    for (var x=1; x<fpsarray.length; ++x) {
        fpsarray[x-1]=fpsarray[x];
    }
    if (fps < 1000) {
        fpsarray[fpsarray.length-1]=fps;
    }
}

static function IsDashboard() {
    return Application.platform == RuntimePlatform.OSXDashboardPlayer;
}

static function IsBrowser() {
    return (Application.platform == RuntimePlatform.WindowsWebPlayer ||
        Application.platform == RuntimePlatform.OSXWebPlayer);
}

function LateUpdate () {
    if (showfps || showfpsgraph) {
        FPSUpdate();
    }
    if (Input.GetKeyDown("escape")) {
        switch (currentPage) {
            case Page.None: PauseGame(); break;
            case Page.Main: UnPauseGame(); break;
            default: currentPage = Page.Main;
        }
    }
}

function OnGUI () {
    if (skin != null) {
        GUI.skin = skin;
    }
	//Our GUI is laid out for a 1920 x 1200 pixel display (16:10 aspect). The next line makes sure it rescales nicely to other resolutions.
	GUI.matrix = Matrix4x4.TRS (Vector3(0, 0, 0), Quaternion.identity, Vector3 (Screen.height / nativeVerticalResolution, Screen.height / nativeVerticalResolution, 1)); 
	
    ShowStatNums();
    ShowLegal();
    if (IsGamePaused()) {
        GUI.color = GuiColor;
        switch (currentPage) {
            case Page.Main: PauseMenu(); break;
            case Page.Options: ShowToolbar(); break;
            case Page.Credits: ShowCredits(); break;
        }
    }   
}

function ShowLegal() {
    if (!IsLegal()) {
        GUI.Label(Rect(scaledResolutionWidth-100,nativeVerticalResolution-20,scaledResolutionWidth/4,nativeVerticalResolution/4),
        "MyWebsite.com");
    }
}

function IsLegal() {
    return !IsBrowser() ||
    Application.absoluteURL.StartsWith("http://MyWebsite.com/") ||
    Application.absoluteURL.StartsWith("http://MyWebsite.com/");
}

private var toolbarInt:int=0;
private var toolbarStrings: String[]= ["Audio","Graphics","Stats","System"];

function ShowToolbar() {
    BeginPage(1000,600);
    toolbarInt = GUILayout.Toolbar (toolbarInt, toolbarStrings);
    switch (toolbarInt) {
        case 0: VolumeControl(); break;
        case 3: ShowDevice(); break;
        case 1: Qualities(); QualityControl(); break;
        case 2: StatControl(); break;
    }
    EndPage();
}

function ShowCredits() {
    BeginPage(600,600);
    for (var credit in credits) {
        GUILayout.Label(credit);
    }
    for (var credit in crediticons) {
        GUILayout.Label(credit);
    }
    EndPage();
}

function ShowBackButton() {
    if (GUI.Button(Rect(40,nativeVerticalResolution-100,200,80),"Back")) {
        currentPage = Page.Main;
    }
}


function ShowDevice() {
    GUILayout.Label ("Unity player version "+Application.unityVersion);
    GUILayout.Label("Graphics: "+SystemInfo.graphicsDeviceName+" "+
    SystemInfo.graphicsMemorySize+"MB\n"+
    SystemInfo.graphicsDeviceVersion+"\n"+
    SystemInfo.graphicsDeviceVendor);
    GUILayout.Label("Shadows: "+SystemInfo.supportsShadows);
    GUILayout.Label("Image Effects: "+SystemInfo.supportsImageEffects);
    GUILayout.Label("Render Textures: "+SystemInfo.supportsRenderTextures);
}

function Qualities() {
    switch (QualitySettings.currentLevel) {
        case QualityLevel.Fastest:
        GUILayout.Label("Fastest");
        break;
        case QualityLevel.Fast:
        GUILayout.Label("Fast");
        break;
        case QualityLevel.Simple:
        GUILayout.Label("Simple");
        break;
        case QualityLevel.Good:
        GUILayout.Label("Good");
        break;
        case QualityLevel.Beautiful:
        GUILayout.Label("Beautiful");
        break;
        case QualityLevel.Fantastic:
        GUILayout.Label("Fantastic");
        break;
    }
}

function QualityControl() {
    GUILayout.BeginHorizontal();
    if (GUILayout.Button("Decrease")) {
        QualitySettings.DecreaseLevel();
    }
    if (GUILayout.Button("Increase")) {
        QualitySettings.IncreaseLevel();
    }
    GUILayout.EndHorizontal();
}

function VolumeControl() {
    GUILayout.Label("Volume");
    AudioListener.volume = GUILayout.HorizontalSlider(AudioListener.volume,0.0,1.0);
}

function StatControl() {
    GUILayout.BeginHorizontal();
    showfps = GUILayout.Toggle(showfps,"FPS");
    showtris = GUILayout.Toggle(showtris,"Triangles");
    showvtx = GUILayout.Toggle(showvtx,"Vertices");
    showfpsgraph = GUILayout.Toggle(showfpsgraph,"FPS Graph");
    GUILayout.EndHorizontal();
}

function FPSUpdate() {
    var delta = Time.smoothDeltaTime;
        if (!IsGamePaused()  delta !=0.0) {
            fps = 1 / delta;
        }
}

function ShowStatNums() {
    GUILayout.BeginArea(Rect(scaledResolutionWidth-200,20,scaledResolutionWidth/4,nativeVerticalResolution/4));
    if (showfps) {
        var fpsString= fps.ToString ("#,##0 fps");
        GUI.color = Color.Lerp(lowFPSColor, highFPSColor,(fps-lowFPS)/(highFPS-lowFPS));
        GUILayout.Label (fpsString);
    }
    if (showtris || showvtx) {
        GetObjectStats();
        GUI.color = statColor;
    }
    if (showtris) {
        GUILayout.Label (tris+"tri");
    }
    if (showvtx) {
        GUILayout.Label (verts+"vtx");
    }
    GUILayout.EndArea();
}

function BeginPage(width,height) {
	scaledResolutionWidth = nativeVerticalResolution / Screen.height * Screen.width;
    GUILayout.BeginArea(Rect(scaledResolutionWidth/2 - (width/2), nativeVerticalResolution/2 - (height/2),width,height));
}

function EndPage() {
    GUILayout.EndArea();
    if (currentPage != Page.Main) {
        ShowBackButton();
    }
}

/*function IsBeginning() {
    return Time.time < startTime;
}*/


function PauseMenu() {
    BeginPage(800,300);
    if (GUILayout.Button ("Continue")) {
        UnPauseGame();

    }
    if (GUILayout.Button ("Options")) {
        currentPage = Page.Options;
    }
    if (GUILayout.Button ("Credits")) {
        currentPage = Page.Credits;
    }
    if (IsBrowser()  GUILayout.Button ("Restart")) {
        Application.OpenURL(url);
    }
    EndPage();
}

function GetObjectStats() {
    verts = 0;
    tris = 0;
    var ob = FindObjectsOfType(GameObject);
    for (var obj in ob) {
        GetObjectStats(obj);
    }
}

function GetObjectStats(object) {
    var filters : Component[];
    filters = object.GetComponentsInChildren(MeshFilter);
    for( var f : MeshFilter in filters )
    {
        tris += f.sharedMesh.triangles.Length/3;
      verts += f.sharedMesh.vertexCount;
    }
}

function PauseGame() {
    savedTimeScale = Time.timeScale;
    Time.timeScale = 0;
    AudioListener.pause = true;
    if (pauseFilter) pauseFilter.enabled = true;
    currentPage = Page.Main;
	TurnCharCamera.gameIsPaused = true;
}

function UnPauseGame() {
    Time.timeScale = savedTimeScale;
    AudioListener.pause = false;
    if (pauseFilter) pauseFilter.enabled = false;
    currentPage = Page.None;
    if (start != null) {
        start.active = true;
    }
	TurnCharCamera.gameIsPaused = false;
}

function IsGamePaused() {
    return Time.timeScale==0;
}

function OnApplicationPause(pause:boolean) {
    if (IsGamePaused()) {
        AudioListener.pause = true;
    }
}

Nice! FYI, here’s a bug report I submitted about UnityGUI not being resolution-independent (which only occurred to me after I started supporting Retina displays) - http://intra.unity3d.com/fogbugz/default.asp?374624_ika6

In my more recent (and messier) versions of the pause menu, I have a boolean to toggle the start-paused behavior, something like this:

public var startPaused=true;

and later

if (startPaused) {
 PauseGame()
}

It would also be nice to have an #if UNITY_PRO wrapped around the pauseFilter use, if there was such a define.

Just thought of this, this morning. What if you used one of the Unity Pro variables from the Stats screen?

To determine if the Unity Player is a Pro version or not? If the Unity player doesn’t support shadows then it’s not Unity Pro, correct? That could be a good way around determining if it’s UnityPro or not.

Checking for image effects sounds like a good idea, maybe

if (SystemInfo.supportsImageEffects) {
  pauseFilter = Camera.main.GetComponent(SepiaToneEffect);
}

but it’s a runtime check so that doesn’t help people who are running Unity Indie and don’t understand why they’re getting a compile error on SepiaToneEffect.

Hi technicat,

I been using your pause menu for my game. I noticed that even my game had paused with the script but eventually I cannot stop my player from shooting while paused… So may I know how should I make a complete paused with your script please?

Thanks and regards,

The script pauses the game by setting Time.timeScale to zero:

This will pause any code that depends on the passage of time, including Unity physics, animation, but it doesn’t stop all code from executing at all, of course, including input functions, otherwise you wouldn’t be able to operate the pause menu. This all depends on your code, but I think the easiest thing to do is probably find where you’re detecting the input for shooting, then wrap an “if (Time.timeScale>0)” around either the fire input detection or fire input execution so that it only happens if the game is not paused.

There are many other approaches - if you search for “pause menu” in the forums, you’ll see some advocating setting up a game controller where you can query an IsPaused function and there is are a couple of other pause menus on the Unity Asset Store, one of which actively goes through and disables other scripts. But checking Time.timeScale is what I do.

Thanks for these advised I found the clue yeah! You’re cheerful thanks again.

I just remembered, the pause menu script has an IsGamePaused function, which just checks if Time.timeScale is zero. So if you want to make the code look a little bit cleaner, instead of checking Time.timeScale directly, you could make IsGamePaused static so, for example if the pausemenu script is name PauseMenu, you can call PauseMenu.IsGamePaused()

I really found the cure for this particular coding myth please be peace I really have to thanks for your advised cuz this took me 1 week to figured out and ask many too.

Thanks technicat. Sweet for you^_^

Hi Technicat, I notice that when you go to the options page using this, the Audio button seems to be stuck on? Like for eg go to options, then click(touch) the other buttons and observe the visual state of the audio button.

Using a custom style I am pressing the other buttons and the audio button is behaving visually as though it were pressed. Any ideas?

Thanks
AaronC

This is only with a custom style? (I don’t see it with the default skin) Are you assigning a skin to the Skin property in the script or supplying the style by passing additional arguments to the GUI.toolbar call in the script? Either way, I would try to narrow down which style property is the one that’s showing up and if it appears to be behaving incorrectly, submit it to Unity as a bug report.

Thanks !

I’ve been trying to use this but it’s not pausing the camera view. How do I get the FPS motion to be paused by this?