Tutorials‎ > ‎

Custom Menu in UDK using Flash

Programs Required:

  • Adobe Flash:  Professional CS6 is being used in this tutorial
  • Unreal Development Kit:  March 2012 is being used in this tutorial
  •           *  UDK Editor and UnrealFrontend will be needed
  • ConTEXT Editor:  You can download it for free here.
This tutorial will walk you through the process of creating a custom game menu, or a main menu, for your UDK map using UDK's scaleform and Flash that will take the place of UDK's Frontend map.  I don't expect you to have extensive knowledge of UDK, Flash, or scaleform, but I'm not going to teach you about every tool regarding any of the mentioned programs.

This tutorial does not extensively use UnrealScript, but instead uses ActionScript 3.0 for the programming of the menus and kismet for the interactivity of the menus.


Install Scaleform GFx Launcher for Flash

First, open your Flash program.  I don't need to reinvent the wheel here, since UDN already provides a wonderful tutorial on installing the Scaleform GFx Launcher for Flash.  However, we won't be needing access to the CLIK library in the final step in order to complete this tutorial.

This awesome extension allows you to test your SWF movies in the UDK environment without having to do all that file moving and importing.  It definitely helped me find out all the nuances that UDK doesn't like, such as audio files and TLF text.

Once you restart Flash as directed in their tutorial, you're ready for the next step.

Design Your Flash U.I. Menu

If you already have a menu created in flash, you can skip this step.  Otherwise, read on!

My example menu for this tutorial will have two buttons on the main menu page: one that points to a sub-menu and another one that exits the game.  The sub-menu has two more buttons: one that loads a UDK map and another one that takes you back to the main menu.

Whether you're a designer, a programmer, or somewhere in between, you can design a main menu with basic functionality like this one, and eventually a menu with more advanced features.  But I'm only showing you the basics for now.

Before we begin, let's keep our files in a folder hierarchy that's relative to each other; this is an important step because if you ever need to move these files, links won't be broken.  So create a folder on your desktop.  I'll call my folder 'TessaTutorial' for example.  In that folder, I commonly create another folder called 'assets' where I save all external pieces that get imported into my FLA file, including external AS files and classes/packages, background images, button images, sound files, etc.  I like being organized, and that single assets folder will keep all of those files together. If you anticipate a huge inventory of assets, you can divide that further into folders labeled audio, images, classes, and whatever else suits your fancy. For good programming practices, we're going to make a subfolder called "CustomClasses" inside our main folder.

So let's get started.  Create a new ActionScript 3.0 File:


Let's change the size of our menu to match that of the default UDK screen.  With nothing selected, take a look at the properties screen.  Change the size to 1280 by 720 pixels. In general, this is the default size of the UDK screen.


I'm a save-a-holic, so I frequently press CTRL+S while working on anything (which doesn't work in UDK because CTRL+S isn't the shortcut for saving in UDK. In fact, it makes matters worse by NOT saving, and it makes a subtractive brush instead, but continuing on anyway...).  So when you go to save your FLA, save it in that folder you created on your desktop as the same name.  So I would name my file 'TessaTutorial.fla,' for example, in my folder called "TessaTutorial."

Moving on, create three more layers in your main timeline, and name them like so:


The Buttons layer will hold all of the button movie clips or simple buttons that we'll be placing on our screens.  The Text layer will hold any static text (such as the menu headers) for each screen.  The Opac layer will be a simple, rectangular graphic drawing with no outline, and a white fill that has a 75% alpha.  The BG layer will hold the background image.  The penguins image that will be using comes from my sample images folder.  I copied that image into my assets folder. The purpose of the "Opac" layer is to tint the background image in order to make our buttons and text legible. As you become more experienced with flash, you'll be able to design much more interesting and engaging menus.

To get an external image into flash, go to File > Import > "Import To Library".  Navigate to your assets folder and select the items you want.  For me, it's just 'Penguins.jpg' and choose Open.  When it's loaded, you'll see it in your Library panel ("Window > Library" if it's not already open). The cheap way I do this is to navigate to the image on your computer, then drag and drop it into your Library column in flash. It takes a moment to do the transfer, so let it be. Otherwise, freezing is a possibility. I hope you saved.

With the keyframe of the BG layer selected, drag the penguins picture onto the stage.  Since this isn't really a finalized design, it doesn't particularly matter if this image is skewed.  I went ahead and aligned the image to 0,0 on the stage, unlinked their height-width proportion, and stretched it to match the dimensions of the whole stage (all of which can be done in the properties panel while the penguins image is selected).  Then, I clicked the second little dot of the BG layer to lock the image so I don't accidentally click it later.

Now select the keyframe on your Opac layer.  Click the Rectangle Tool.  In the properties panel, click the box next to the pen image, and set it to none.  Click the box next to the fill bucket image, and change the color to white, and the alpha to 50%.


With these settings, create a box over the entire menu.  The size and position doesn't have to be perfect, as long as it covers the entire stage.

     

Before and After. Click image to view larger.

Go ahead and lock this layer too. We tinted our background as to contrast our text and buttons more.

Each circle on the timeline represents a Keyframe. Currently, the timeline has only one Keyframe. Since we want to have a main menu and a sub-menu, we will need to have two. Select frame 2 for the Opac and BG layers, left click this selection, and choose "Insert Frame".

You'll see a little box appear in their timelines, indicating the end of an animation. Now you can move your red timeline cursor between frames 1 and 2, but nothing changes. We'll be seeing our Penguin background on both menu screens.

Now select frame 2 for the Buttons and Text layers, left click this selection, and choose "Insert Keyframe". You'll see white circles in these ones instead of the boxes.

Your timeline should look something like this:



Now when you design your actual game menu, you'll probably be making your own buttons.  But for the sake of this tutorial, I'm just going to use some default flash buttons.  To do that, click on "Window > Common Libraries > Buttons".  In the window that shows up, expand the folder labeled "buttons rounded" and highlight "rounded blue 2" like so:


Drag the button to your library, and it will create a folder with the same name.  It should look like this:


Now create three new duplicates of this button (you can right click the button to make duplicates) so you have four buttons in total.  Name each one differently.  We need a button to go to our sub menu, an exit button, a play button, and a back button.  I named mine "submenu_button", "exit_button", "play_button", and "back_button", respectively.

Return to frame 1, and highlight the Buttons layer.  Drag the submenu_button and the exit_button to the stage.  You can proportionately re-size them so that they appear larger.  I set my width to 200, and the height automatically changes.

Double click on a button on the stage, and you'll be able to edit the text on the button.  For example, I double click on the sub menu button.  The rest of the stage goes whiter.  Now I double click on the text, and I can change it from 'Enter' to 'Sub Menu'.  You can return to the stage by clicking the Scene 1 button on the top of the program.

Take a look at this screenshot.  There is one particular thing you need to be aware of.  Make sure that all text in your FLA file is classic text.  You can see that the timeline changes to the button within your submenu_button when you double clicked it, and on the top left is the button you can click on to go back to the main stage.  Change the text for your exit button in the same manner.

On frame 5 of the Buttons layer, drag the play_button and back_button to the stage.  Re-size them and change their text to display the appropriate words as well.

This concludes creating the visuals for the tutorial main menu, the next part is all about coding it.

     

Screen shots of the final 'Main Menu' and 'Sub Menu' frames in the tutorial file.  Click to view larger.

Code Your Menu Using Action Script 3.0

Now that you have all of the visuals for a main menu ready, it's time to add some functionality to it.

The first thing we need to do is create a main class to do all of the major functions of your menu. To start, select "File > New..."  Highlight "ActionScript 3.0 Class" on the left, and type in "Main" in the class name. The case will be important, and I like to use capital letters for my class names because I'm weird like that.



After the word package, you need to type in the path to your class relative to your FLA file. So remember that sub-folder we made earlier called "CustomClasses"? That's what we type here.

This class needs to inherit all of which a movie clip is. So let's set that up next.

Finally, we need to know if it will work, so let's toss a few trace statements in there for good measure. I know I've done this a million times, but it's always good to make sure your scripts execute when you tell them too instead of assuming, and then wondering why nothing is working later after you've written all this awesome code.

Oh, and put a stop command in the constructor as well. We want to appeal to our epileptic users.



Be sure to save your script, "Main.as" in the CustomClasses folder.

Don't freak out just yet if your movie is still inducing seizures by flickering between the first and second frame. That's up next. We need to tell the main time line that there is a new main class. So let's do that.

In the Properties panel of your FLA file, you'll see an empty field for Class. Type in the full path to your Main class, using a period between the folder name and class name, like so:


Now test your movie and check out your Output. You should only be able to see the main menu screen (no flickering) and both trace statements should appear in your output.

Next, we need to make our buttons do something.  We want the submenu_button to take us to the next screen, and the exit_button to take us out of the game.  But first, we need to do two things before we write the code to do this; give our buttons instance names and give our screens frame labels.

Select a button on the stage.  In the properties panel, you'll see a blank field with the text <Instance Name> in it.  Click in the space, and type a name for it.  I've named all of my buttons "subMenu_btn", "exit_btn", "play_btn", and "back_btn" appropriately.


Now select the keyframe on frame 1 of the Buttons layer.  In the properties panel, you'll see something similar, but we're focusing on the field that follows "Name: ".  I've named this main menu "Main Menu".  Move to the keyframe on frame 2 of the actions layer, and label that one as well.  Mine is called "Sub Menu".


You'll also see these labels show up in your timeline with a little red flag on them.

Okay, here's the beginning of the juicy programming part. We need to make event handlers for the buttons to listen for mouse clicks each time that menu is displayed. So we'll start off with two private functions: "DisplayMainMenu" and "DisplaySubMenu," no parameters necessary.

The first thing that each function needs to do is go to their correct frame using the call "gotoAndStop()". The parameter is a string of the label we gave each menu earlier.

The next thing they ought to do is give the buttons their appropriate event listeners so that when they are clicked, they'll call a function, sending the data regarding the mouse click as the only parameter; there is only one for each button.



Now we need to make some event handlers of the functions they call. For example, the play and exit buttons will invoke fscommands to communicate with Unreal Kismet. The menu navigation buttons will display the menus that they're meant to.



Now like I mentioned in this tutorial's introduction, we won't be using a whole lot of UnrealScript.  In actuality, we'll be using kismet.  Those fscommands you see in our code will call fscommands we create in UDK's kismet, and those fscommands can then do anything we want them to do.  This is further discussed in The Kismet Part of the tutorial.

Finally, don't forget to call the "DisplayMainMenu" function from your constructor.

At this point, you're ready for the next part of the tutorial.

Main.as

package  CustomClasses
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.system.fscommand;
public class Main extends MovieClip
{
trace('Main Class is functional.');
public function Main()
{
trace('Main Constructor is functional.');
DisplayMainMenu();
}
private function DisplayMainMenu():void
{
gotoAndStop('Main Menu');
subMenu_btn.addEventListener(MouseEvent.CLICK, clickSubMenu);
exit_btn.addEventListener(MouseEvent.CLICK, clickExit);
}
private function DisplaySubMenu():void
{
gotoAndStop('Sub Menu');
play_btn.addEventListener(MouseEvent.CLICK, clickPlay);
back_btn.addEventListener(MouseEvent.CLICK, clickBack);
}
private function clickSubMenu(e:MouseEvent):void
{
trace('Clicked Sub Menu Button');
DisplaySubMenu();
}
private function clickBack(e:MouseEvent):void
{
trace('Clicked Back Button');
DisplayMainMenu();
}
private function clickExit(e:MouseEvent):void
{
trace('Clicked Exit Button');
fscommand('ExitGame');
}
private function clickPlay(e:MouseEvent):void
{
trace('Clicked Play Button');
fscommand('PlayMap');
}
}
}


What Main.as should look like before proceeding.

Menu Navigation: Mouse Cursor

UDK automatically hides your cursor, so if you plan on using a mouse cursor as part of your menu, then it is vital that you create your own cursor. From my experience, this is not the most optimal way due to the listeners being in the movie. With some research and trial and error, you can learn to do this with the CLIK library from UDK itself instead. Until then, here's the simplest method for the Flash Developer.

You can create your own or download one that looks like the default cursor.  Either way, it must be inside a movie clip.  To make one, go to Insert > New Symbol.

Give your symbol a name, I'll be naming mine "cursor_mc".  Make sure the type is "Movie Clip", and then check the box "Export for ActionScript."

This movie clip will be added to your library, and you will be taken inside it.  I'm lame, so I'll just draw an arrow pointing to the little plus sign.

Now return to Main.as, and edit the code to include this new function called "FixCursor". It takes a Boolean as a parameter that defaults to false if none is given.

Function FixCursor

private function FixCursor(newCursor:Boolean=false):void
{
    if(newCursor)
    {
        trace('Creating a new cursor...');
        cursor = new cursor_mc();
    }
    else
    {
        trace('Fixing existing cursor...');
        removeChild(cursor);
    }
    addChild(cursor);
    cursor.x = mouseX;
    cursor.y = mouseY;
    cursor.startDrag();
    trace('Cursor Fixed.');
}

The parameter is named "newCursor". If it is true, then we'll be creating a new cursor. We need this distinction for when we first run the code to create a brand new cursor compared to simply fixing the cursor by removing the existing one.

Once that difference is taken care of, the cursor is added, moved to the current mouse coordinates, and then calls the "startDrag" function.

Be sure to create the variable "cursor" and give it a variable type "cursor_mc" at the beginning and invoke this function in all of the appropriate locations: "Main" (with the parameter being true and before calling "DisplayMainMenu"), and then at the end of "DisplayMainMenu" and "DisplaySubMenu".

Main.as

package  CustomClasses
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.system.fscommand;
public class Main extends MovieClip
{
trace('Main Class is functional.');
                private var cursor:cursor_mc;
public function Main()
{
trace('Main Constructor is functional.');
                        FixCursor(true);
DisplayMainMenu();
}
private function DisplayMainMenu():void
{
gotoAndStop('Main Menu');
subMenu_btn.addEventListener(MouseEvent.CLICK, clickSubMenu);
exit_btn.addEventListener(MouseEvent.CLICK, clickExit);
                        FixCursor();
}
private function DisplaySubMenu():void
{
gotoAndStop('Sub Menu');
play_btn.addEventListener(MouseEvent.CLICK, clickPlay);
back_btn.addEventListener(MouseEvent.CLICK, clickBack);
                        FixCursor();
}
private function clickSubMenu(e:MouseEvent):void
{
trace('Clicked Sub Menu Button');
DisplaySubMenu();
}
private function clickBack(e:MouseEvent):void
{
trace('Clicked Back Button');
DisplayMainMenu();
}
private function clickExit(e:MouseEvent):void
{
trace('Clicked Exit Button');
fscommand('ExitGame');
}
private function clickPlay(e:MouseEvent):void
{
trace('Clicked Play Button');
fscommand('PlayMap');
}
                private function FixCursor(newCursor:Boolean=false):void
{
if(newCursor)
{
trace('Creating a new cursor...');
cursor = new cursor_mc();
}
else
{
trace('Fixing existing cursor...');
removeChild(cursor);
}
addChild(cursor);
cursor.x = mouseX;
cursor.y = mouseY;
cursor.startDrag();
trace('Cursor Fixed.');
}
}
}


This function is my fix in the event that the cursor goes underneath the buttons instead of on top. The cursor needs to be the last child added to the top most object. In our case, the object is Main (the class) that we're adding the cursor to.

Menu Navigation: UDK Controls


TBA. Check back soon ;)

Preparing For UDK

Make sure you publish your flash file before continuing on.  Simply pressing CTRL + ENTER to preview your movie will automatically create a published SWF file.

Now copy the entire folder on your desktop that holds everything related to your flash project.  Navigate to where you installed UDK and go to "UDKGame > Flash" and paste your folder here.

Now since our menu has a background image, it does not necessarily matter what our level looks like.  So create a blank map.  My map is only a hollow cube brush (512) with a player start and point light in it.  I built all and saved it as 'TessaTutorialMap.udk' in the Maps folder of UDKGame > Content.

If you plan on showing off models in your menu, simply leave the stage empty instead of a background image.  Any place where the stage is visible in flash will be completely transparent when imported into UDK.

Screen shot of my main menu's map in UDK.  Click to view larger.

In your Content Browser, click the import button.  Navigate to your swf file in the UDK hierarchy.

Import the swf file using the default settings.
Click to view larger.

If your swf imported correctly, you will see the external assets used in your file import alongside your swf.  This is very important because if you don't see them, it will not work.
Click to view larger.

Once the file is imported correctly, make sure to save all of your work, including all packages and map files (the 'TessaTutorial.upk' is also saved in my Maps folder.

The Kismet Part

Make sure your package and map are saved before continuing.  Highlight the SwfMovie object in your Content Browser, and then close out of it.  The pointer to your SwfMovie object will be saved.  Now open up kismet.

We need to do three things in kismet:  Tell it to play the SwfMovie, tell it to enter cinematic mode, and set up the fscommands.  Lets do those things in that order.

Add two new events: a player spawn and a level loaded.  We're going to link the player spawned event to a cinematic mode.  So in New Actions > Toggle > Toggle Cinematic Mode.  Link the player spawned to the Enable node like so:

Next, go to New Actions > GFx UI > Open GFx Movie.  Link the "Loaded and Visible" node of the Level Loaded to the "In" node of the Open GFx Movie.

Click on the Open Movie and lets take a look at it's properties.  Expand the first tab.  The first field, where it says None for Movie, press the green arrow button.  That button says 'Use Selected Object in Content Browser' which was the swf file before we closed it.  Check the boxes for "Take Focus" and "Capture Input".
Click to view larger.

If you save and play your level, you'll see your movie play.  You'll also be able to click the buttons.  However, pressing exit or play won't do anything yet.  We need to set those up next.

Fscommands are trigger events in kismet.  So click to add a new event > GFx UI > FsCommand.  Make two of them.  Now in flash, you'll remember that we sent string parameters: "ExitGame" and "PlayMap".  Click on one of the events and view it's properties.  Expand the first and last tab.  Click the green arrow for the Movie field to point to our swf file.  In FSCommand, type in "ExitGame" but without quotes.  Do the same for the Obj Comment so we can differentiate between the fs events.
Click to view larger.

Adjust the properties of the other FsCommand event for the "PlayMap" call.
Click to view larger.

Now these buttons still won't do anything just yet.  We have one more thing to do (two technically).  Create a New Action > Misc > Console Command.  Make two of these.

Open the first tab of the properties of one of the console commands and type in 'quit'.  For the other, type 'open DM-Deck.udk' or whatever custom map you've made that you want your menu to load.  Connect the out nodes of the FsCommands to the In nodes of the appropriate console command.

Almost done.  Create an all player variable, and connect all of your targets to it.
Click to view larger.

Now you're done.  Build All.  Save All.  Test your level.  Exit.  You're ready for the next step.

The UnrealScript Part

This is actually very easy, even if you don't know a thing about UnrealScript.  Open ConTEXT editor.  First, we want to be able to see the line numbers; click on "Options > Environment Options..."  Choose the 'Editor' tab, and check the box for 'Line Numbers'.  Now, navigate to where you installed UDK, and then go to "UDKGame > Config" and open the 'DefaultEngine.ini' file.

Lines 9 and 10 say "Map=UDKFrontEndMap.udk" and "LocalMap=UDKFrontEndMap.udk", respectively.  Edit those lines to point to the UDK map that you made with your scaleform U.I.  I would change it to "Map=TessaTutorialMap.udk" and "LocalMap=TessaTutorialMap.udk".


Now scroll down that file until you reach the section [Engine.PackagesToForceCookPerMap] on line 56.   After ".Map=UDKFrontEndMap", press enter to create a new line (line 58) and type in something similar, but replace the map with yours.  Mine would say ".Map=TessaTutorialMap" (make note that we aren't typing .udk after it like we did in the previous lines.  After the last .Package line, press enter to create a new line (line 61) and type in the same thing, but for your flash package (in other words, it's the name we gave the folder that holds your FLA and related files).  Mine would say ".Package=TessaTutorial".


Save the file.  The changes we just made makes it so that your map with all of your scaleform menu information is loaded instead of the UDKFrontEndMap.  The later changes made it so when you cook your game files using Frontend, we don't actually have to load our menu's map into Frontend.  It will be cooked automatically.

Once those four changes have been made, you're ready for the next step of the tutorial.  I told you the UnrealScript part was easy.

Compiling and Packaging

Now I'm assuming you already created a map in UDK that is essentially your game.  Otherwise, why would you be making a custom main menu?  Right?  Well, now it's time to compile all of your scripts and package your game into an executable for distribution.

If you've packaged your level for play-testing purposes before you created a main menu at all, you essentially don't have to do anything differently because of the additions we made to the DefaultEngine.ini file in the last section.

If you've never packaged a game before, open Frontend.  The interface looks like this.
Click to view larger.

Now click on the Add... button and select your custom game map, not your menu map.  For this tutorial, I don't particularly have one, so I'm using DM-Deck.udk anyway.  Otherwise, you can remove DM-Deck.udk.  Make sure all of the steps are enabled (though you don't necessarily have to have Launch enabled, that just lets you play your cooked game).

Just hit the big, green Start button, and wait.  Depending on the size of your level and how many custom scripts you have will make your wait lengthy.  In any event, when this process is almost done, it will prompt you to give your package a long name and a short name.  Go ahead and do so.

When it's all, absolutely done.  You'll find an executable file located in your UDK root folder (C:/UDK/UDK-2012-03/, for example) titled Install-<whatever short name you gave it>.exe.  You can give people this executable file and they can use it to install your udk map.  Your main menu will appear first and foremost.

Hope this was helpful!

Download Source Files

Below are source files available for download. Enjoy!
ċ
Flash Source Files.zip
(2291k)
Tessa Watkins,
Feb 27, 2014, 3:29 PM
Comments