Adding a screen resolution option

A ready-made "Graphic Options" UI template can be found on the Downloads page.

Adventure Creator has built-in support for basic options such as audio levels and subtitles. However, when building a game for PC and Mac, it's likely that you'll want to add further options - particularly graphical ones.

In this advanced tutorial, we'll add add the ability to both change the screen resolution, from within the game as a custom option. We'll be making use of Menus, Variables, as well as some scripting. The scripting will be quite basic, but it is still recommended that you have a basic knowledge of coding principles beforehand - though the complete script is still shown within.

What resolutions are possible depends on the user's monitor. Unity stores an array of the available choice in its Screen.resolutions array.

We'll use an Integer Variable to store the current index of the above array. This will be a Global Variable, so that it can be accessed at any time.

Begin by going to the Variables Manager, and adding these a new Global Variable.

Name the this ScreenResolution, and set its Type to Integer. Set its Initial value to -1. We can later write a script to set it to the correct value if it's found to be negative. Then set the Link to field to Options Data. This will cause its value to survive application restarts, and be separate from save game files.

Make a note of the Variable's ID number, as we'll need it when scripting. The ID number is listed to the left of it's name in the list.

Now we're ready to amend our Options Menu to include a resolution option. This tutorial assumes you already have an Options Menu to work with - if you don't, you can simply copy one from the Default_MenuManager asset file, which looks like this:

Open the Menu Manager and select your Options Menu. Under the list of elements, choose an Element type of Cycle and click Add new.

A Cycle element will let the player choose between multiple values - in this case, the various resolutions. Rename it ScreenResolution, and re-style it so that it fits in with the rest of the menu:

The Cycle's value will be linked to the Variable we made earlier, so set the Cycle type to Variable, and select the ScreenResolution variable.

The element's properties next gives us space to enter in a number of different choices that the player can cycle through. However, because the available resolutions will vary based on the player's monitor, we'll need to set these values through script at runtime.

We can get an API reference to any Manager field by right-clicking its label. Set the Number of choices to 1, and right-click the Choice #0 field label to reveal its API reference as:

(AC.PlayerMenus.GetElementWithName ("Options", "ScreenResolution") as AC.MenuCycle).optionsArray[0]

We can use this, along with Unity's Screen.resolutions array, to write a function that generates choice labels accordingly:

void GenerateResolutionCycleOptions ()
{
	AC.MenuCycle resolutionCycle = AC.PlayerMenus.GetElementWithName ("Options", "ScreenResolution") as AC.MenuCycle;

	resolutionCycle.optionsArray.Clear ();
	foreach (Resolution resolution in Screen.resolutions)
	{
		string optionLabel = resolution.width.ToString () + " x " + resolution.height.ToString () + " (" + resolution.refreshRate.ToString () + ")";
		resolutionCycle.optionsArray.Add (optionLabel);
	}
}

We'll also need a function that sets the correct value of our ScreenResolution integer variable, if it's found to be -1:

void InitResolutionVariable ()
{
	GVar variable = GlobalVariables.GetVariable (0); // Replace '0' with your own variable's ID number
	if (variable.IntegerValue == -1)
	{
		for (int i=0; i<Screen.resolutions.Length; i++)
		{
			if (Screen.resolutions[i].width == Screen.currentResolution.width &&
				Screen.resolutions[i].height == Screen.currentResolution.height &&
				Screen.resolutions[i].refreshRate == Screen.currentResolution.refreshRate)
			{
				variable.IntegerValue = i;
				return;
			}
		}
		variable.IntegerValue = 0;
	}
}

These two functions are best called at the start of the game, once AC has initialised. From the Project window, create a new C# script named SetupOptionsMenu.cs, and give it the following:

using UnityEngine;
using AC;

public class SetupOptionsMenu : MonoBehaviour
{

	void Start ()
	{
		GenerateResolutionCycleOptions ();
		InitResolutionVariable ();
	}

	void GenerateResolutionCycleOptions ()
	{
		MenuCycle resolutionCycle = PlayerMenus.GetElementWithName ("Options", "ScreenResolution") as AC.MenuCycle;

		resolutionCycle.optionsArray.Clear ();
		foreach (Resolution resolution in Screen.resolutions)
		{
			string optionLabel = resolution.width.ToString () + " x " + resolution.height.ToString () + " (" + resolution.refreshRate.ToString () + ")";
			resolutionCycle.optionsArray.Add (optionLabel);
		}
	}

	void InitResolutionVariable ()
	{
		GVar variable = GlobalVariables.GetVariable (0); // Replace '0' with your own variable's ID number
		if (variable.IntegerValue == -1)
		{
			for (int i=0; i<Screen.resolutions.Length; i++)
			{
				if (Screen.resolutions[i].width == Screen.currentResolution.width &&
					Screen.resolutions[i].height == Screen.currentResolution.height &&
					Screen.resolutions[i].refreshRate == Screen.currentResolution.refreshRate)
				{
					variable.IntegerValue = i;
					return;
				}
			}
			variable.IntegerValue = 0;
		}
	}

}

Place this on an empty GameObject in your game's first scene. If you test the game now and open the Options menu, you should find that the Cycle element is set to the game's current resolution, and you are able to click through each of the available resolutions for your monitor. And since the Variable is linked to Options Data, the change is remembered even after exiting and re-playing the game.

However, clicking the Cycle will have no effect on the actual resolution - to change that, we're going to have to create a custom Action.

A tutorial on writing custom Actions can be found here.

The easiest way to create a new Action is to duplicate ActionTemplate.cs. This file can be found within Assets / AdventureCreator / Scripts / ActionList in the Project window. Duplicate it, rename it to ActionApplyResolution, and move it to a new empty folder.

An error will appear in the Console, because the code inside the new script still uses the same "class" name as ActionTemplate, so we'll need to fix that. Open the script file and change the mention of ActionTemplate to ActionApplyResolution on line 22:

[System.Serializable]
public class ActionApplyResolution: Action
{

Next, we need to give it a new category and title. This determines where it appears in any list of available Actions. Change the Category property to ActionCategory.Engine, and the Title property string on line 27 to Apply resolution. The Description string can be deleted or changed to suit your liking:

public override ActionCategory Category { get { return ActionCategory.Engine; }}
public override string Title { get { return "Apply resolution"; }}

This Action is very simple, and won't involve any settings to change, or GUI elements in any Editor, so we only need to write code in the Run() function, which is called when the Action is run.

When this Action runs, we want to read the value of our ScreenResolution Global Variable, and set the game's resolution accordingly. So first, we'll define a new integer, chosenIndex and set it to the Global Variable's current value. We'll then need to recalculate our menus to reflect the update, and then return a float value of zero to indicate that the Action is complete.

Replace the Run() function with the following:

override public float Run ()
{
	int chosenIndex = GlobalVariables.GetIntegerValue (0); // Replace '0' with your own variable's ID number
	if (chosenIndex >= 0)
	{
		Resolution chosenResolution = Screen.resolutions [chosenIndex];

		Screen.SetResolution (chosenResolution.width, chosenResolution.height, Screen.fullScreen);
		KickStarter.playerMenus.RecalculateAll ();
	}
	return 0f;
}

Our Action is now finished - we now just need to plug it into our Actions Manager, so that we can use it in our ActionLists. Move the file to a new folder in your Assets directory, and go the Actions Manager. In the Custom Action scripts panel, click the folder icon and point the window to the directory where our new Action is stored. Be sure that the directory contains nothing but Action scripts. You'll then find the new Action listed with the others.

We're now ready to call this Action when the Cycle element is clicked on by the player. We'll do this by placing it in an ActionList asset, that can be called in any scene. Choose an appropriate folder in your Project window, and choose Create → Adventure Creator → ActionList asset.

Rename this asset to Set resolution and view it in the Inspector window. Click Add new Action once to create a new Action, and set the Action type to Engine: Apply resolution.

Now return to the Menu Manager, select the ScreenResolution Cycle element, and assign the Set resolution ActionList as the ActionList on click.

Now when the Cycle is clicked on, the screen will set itself to the player's chosen resolution. We now just need to ensure that the game keeps this resolution when the game re-starts. We can do this by setting the Set resolution asset as our game's ActionList on start game, as listed in the Settings Manager: