We’ll provide the option to choose a map with a flyout menu built in Flash. But to achieve our objective of keeping the maps independent of the BattleMap mod, we can’t hard code the map list into the menu. Therefore, we’ll store the list in a config file and pass it to the HUD on startup.
Flash
Once again, our friends at MonsterLayer.com produced some gorgeous assets for us in an astonishingly short amount of time. I’ll do my best to break down how they built our menu, but you can certainly create any style of menu that suits you. All that’s important is that the asset names match the code.
Below is a snapshot of an individual menu button. This will be duplicated multiple times: one for each map.
The “Scripts” layer simply contains:
stop();The second frame of the background later changes the color. That will become the “hover” when moused over. (Yes, Flash does include a Button type. However, we had multiple issues trying to get it to work correctly so we went with the programmer’s approach of just coding it ourselves.)
Make sure the Text object is named “ButtonText” and save the symbol as a MovieClip named “MapButton”.
Create another button the exact same way:
Name this MovieClip “CloseButton”.
Next, create a menu that contains your button objects:
Name the map button instances “MapButton0”, “MapButton1”, etc. Name the close button instance “CloseButton”. Save this MovieClip as “MapList”.
Create another MovieClip called “MapListMenu”. Add an instance of MapList named “MapListInst”. Create a motion tween of it moving onto the stage:
The scripts on the 1st and last frames both simply contain:
stop();Now, add an instance of MapListMenu to your root movie named “MapListMenuInst”. Position it so that it starts outside the scene, but ends inside at the end of its animation. (Edit In Place comes in real handy here.)
We need one more object. Transitioning between maps can take a few seconds to initiate. We should provide a visual clue that the transition has begun and the UDK isn’t hung. Create an object named “Overlay”. I drew a giant semi-transparent background with the ever-polite instructions “Please Wait…”:
Add an instance of your Overlay object to your root movie as “OverlayInst”.
ActionScript
Now, we need to wire it all up. Add the following to your root ActionScript. It initializes an array to store the map list, hides the Overlay and sets up mouse events for the buttons. The click event for the map buttons will show the Overlay on top, toggle off the menu and pass the chosen map back to UnrealScript:
var Maps:Array;Next, add the following InitMapList() function. This will be called by UnrealScript to pass in the map list and setup the map buttons:
// Hide overlay
OverlayInst._visible = false;
// Init map buttons
i=0;
while(MapListMenuInst.MapListInst["MapButton"+i])
{
MapListMenuInst.MapListInst["MapButton"+i]._visible = false;
MapListMenuInst.MapListInst["MapButton"+i].onRollOver = function(){
this.gotoAndStop(2);
}
MapListMenuInst.MapListInst["MapButton"+i].onRollOut = function(){
this.gotoAndStop(1);
}
MapListMenuInst.MapListInst["MapButton"+i].onRelease = function(){
OverlayInst.swapDepths(_root.getNextHighestDepth());
OverlayInst._visible = true;
ShowMapList();
ExternalInterface.call( "OpenMap", Maps[this._name.substr(9)]["File"] );
}
i++;
}
// Init close button
MapListMenuInst.MapListInst.CloseButton.onRollOver = function(){
this.gotoAndStop(2);
}
MapListMenuInst.MapListInst.CloseButton.onRollOut = function(){
this.gotoAndStop(1);
}
MapListMenuInst.MapListInst.CloseButton.onRelease = function(){
ExternalInterface.call( "CloseMap" );
}
function InitMapList(Param1:Array)Finally, add the ShowMapList() function to toggle the menu on/off:
{
Maps = Param1;
//Show only buttons with maps
for (i=0; i<Maps.length; i++)
{
MapListMenuInst.MapListInst["MapButton"+i].ButtonText.text = Maps[i]["Name"];
MapListMenuInst.MapListInst["MapButton"+i]._visible = true;
}
}
function ShowMapList()Republish the .swf file then open up the UDK, find the BattleMapHud package, and reimport BMHud.
{
if (MapListMenuInst._currentframe == 1)
{
MapListMenuInst.swapDepths(_root.getNextHighestDepth());
CursorInst.swapDepths(_root.getNextHighestDepth());
MapListMenuInst.gotoAndPlay(2);
}
else
MapListMenuInst.gotoAndStop(1);
}
BattleMapConfig.uc
Now, let’s setup a config file to store the map names. The UDK builds in configuration file functionality into the base Object class. That means that every class can implement its own config file. Mougli’s portfolio includes a very good tutorial on UDK configuration files. To sum up, any variable declared globally in a class becomes an entry in its config file.
Here’s the code for a simple object containing an array of MapItem structs:
class BattleMapConfig extends Object config(BattleMap);The “config(BattleMap)” directive tells the UDK that this object will read and write to a BattleMap.ini file.
struct MapItem
{
var config string Name;
var config string File;
};
var config array <MapItem> Maps;
DefaultBattleMap.ini
In your /UDKGame/Config directory, create a new .ini file called “DefaultBattleMap.ini” and enter the titles and file names of your maps. For example, mine looks like:
[BattleMap.BattleMapConfig]The format should look very familiar, it’s similar to DefaultInput.ini where we include new key bindings. Notice that the section heading is the name of our class.
Maps=(Name="Demon Queen's Enclave U1, L1",File="BM_DemonQueensEnclave.udk")
Maps=(Name="Demon Queen's Enclave L13-16",File="BM_DemonQueensEnclave1.udk")
Maps=(Name="Demon Queen's Enclave L2-6,11,V1",File="BM_DemonQueensEnclave2.udk")
Maps=(Name="Demon Queen's Enclave V2,V4-V10",File="BM_DemonQueensEnclave3.udk")
Maps=(Name="Demon Queen's Enclave V12",File="BM_DemonQueensEnclave4.udk")
DefaultInput.ini
Speaking of DefaultInput.ini, while we’re here go ahead and add a key binding to toggle our menu:
-Bindings=(Name="Escape",Command="GBA_ShowMenu")(In case you’re curious, the period in front of .Bindings means that duplicate entries are allowed.)
.Bindings=(Name="Escape",Command="BMShowMapList")
BattleMapPlayerController.uc
Here, we simply need to instantiate our new BattleMapConfig class, which will cause it to automatically initialize its variables from the config file:
var BattleMapConfig BMConfig;BattleMapHUD.uc
simulated function PostBeginPlay()
{
super.PostBeginPlay();
BMConfig = new class'BattleMapConfig';
}
Inside PostBeginPlay(), add a call to a CallInitMapList() function right after the CrosshairMovie.Initialize() statement and pass in the newly loaded Map array:
CrosshairMovie.CallInitMapList(BattleMapPlayerController(PlayerOwner).BMConfig.Maps);BattleMapPlayerInput.uc
Create a new command to tell the HUD to toggle the menu and another to tell the UDK to load a new map:
exec function BMShowMapList()BattleMapGfxHud.uc
{
if (WorldInfo.NetMode == NM_Standalone || WorldInfo.NetMode == NM_ListenServer)
{
BattleMapHUD(myHUD).CrossHairMovie.CallShowMapList();
}
}
exec function BMOpenMap(string MapFile)
{
WorldInfo.Game.ProcessServerTravel(MapFile);
}
First, create two new wrapper functions for calling the HUD’s InitMapList() and ShowMapList():
function CallInitMapList( array <MapItem> Param1 )Finally, create two receiver functions called by the HUD to execute our BMOpenMap() command and the Quit command:
{
ActionScriptVoid("InitMapList");
}
function CallShowMapList()
{
ActionScriptVoid("ShowMapList");
}
function OpenMap(string MapFile)That’s it! If everything went smoothly, hitting Esc will now pop up a menu of map choices. Clicking on a map name will transition to a new map. Clicking the close button will cleanly exit the UDK.
{
ConsoleCommand("BMOpenMap " @ MapFile);
}
function CloseMap()
{
ConsoleCommand("Quit");
}
BattleMap mode source files