Feeds:
Posts
Comments

In part 2 of this tutorial I will first show you how to create your own project that implements the vehicle HUD. The second step will consist of creating the necessary UnrealScript classes. The last step will be importing your new HUD, save the resulting package in the right place and cook the project.

Requirements here:

  • A text editor, I suggest Visual Studio 2010 Express with nFringe (you can get them both for free). The tutorial works without them but they’re a huge help.
  • About an hour of your time
Again, I will make all files available as download for you.

1. The Groundwork (again)

We will have to modify existing respectively add new files. If we just modified the stock UTGame UDK files, the result won’t be update proof and you’ll either lose your work or you’ll have to merge the new files with your modified ones when you move to the next UDK version. So the best way is to add our own code the “myMod” way.

INI Files

In order to let the FrontEnd know that it is supposed to compile and cook “myMod”, we will have to enable this in the config files. Look for your UDKGame/config folder and locate the file DefaultEngineUDK.ini.

UDK config files

Search for the entry: [UnrealEd.EditorEngine].The lines below will look like this.

EditPackagesOutPath=..\..\UDKGame\Script
FRScriptOutputPath=..\..\UDKGame\ScriptFinalRelease
+EditPackages=UDKBase
+EditPackages=UTEditor
;ModEditPackages=MyMod

Remove the ‘;’ in front of MyMod. That will enable the FrontEnd to cook every script file in the MyMod folder. We want to give your mod a better name than this, so rename the “MyMod” to whatever you want. the line I use looks like this:

ModEditPackages=RaceGame

Since we are in the configs folder already, look for the file DefaultEngine.ini, it should be right above the one you just edited. Search for the entry

[Engine.StartupPackages]
+Package=FX_HitEffects
+Package=UDKFonts
+Package=UTGame

And add the line below but rename RaceGame to whatever you just added instead of MyMod.

+Package=RaceGame

This line serves the sole purpose to make sure that your game’s package is always cooked. Without it, it may well happen that your new HUD does not display after cooking if this line is missing.

If you are using some versioning system, it’s a good idea to add the two modified files now, so you can quickly diff them with the next UDK version. I recommend SVN.

Last step in the config folder, locate all .ini files that start with UDK* and delete them. The UDK will recreate them when you start it the next time, but with your changes now. That’s just a precautionary step though, it should work without deleting them.

Class Folders

Now that we made all these changes, we should see to it that your project’s script folders actually exist. Locate the folder Development\Src\, it is in your UDK’s root folder. There you should spot the “MyMod” folder there. Rename it to whatever you chose in the .ini files.

UDK development src folder.

Once you renamed MyMod to your mod’s name (RaceGame in my case), open both this and the next folder called Classes. Inside the classes folder we will have to create the files listed below. My files have Race in their name, since the mod is called RaceGame.

  • RaceGame.uc
  • RaceGFxHudWrapper.uc
  • RaceGFxMinimapHud.uc
These files are text files, so if you don’t have a fancy IDE like Visual Studio, you can create new text files and rename their ending manually.

The required script files

2. Unreal Script

RaceGame.uc

Here we will override parts of the HUD initialization for UT’s Deathmatch. Now copy and paste the following code:

/**
* Copyright 1998-2011 Epic Games, Inc. All Rights Reserved.
*/
class RaceGame extends UTDeathmatch
config(game);

/** handles all player initialization that is shared between the travel methods
* (i.e. called from both PostLogin() and HandleSeamlessTravelPlayer())
*/
function GenericPlayerInitialization(Controller C)
{

local PlayerController PC;

super.GenericPlayerInitialization(C);

if ( !bUseClassicHUD )
{

HUDType = bTeamGame ? class’UTGFxTeamHUDWrapper’ : class’RaceGFxHudWrapper’;

}

PC = PlayerController(C);
if (PC != None)
{

// tell client what hud class to use

PC.ClientSetHUD(HudType);

}

}

defaultproperties
{
}

One thing though is, this way it will only work for Deathmatch, not for any of the team based modes. If you want to use it in all modes, change this line:

HUDType = bTeamGame ? class’UTGFxTeamHUDWrapper’ : class’RaceGFxHudWrapper’;

to this line:

HUDType = class’RaceGFxHudWrapper’;

RaceGFxHudWrapper.uc

This class defines the MinimapHUD class to use. The actual work is done in RaceGFxMinimapHUD.

class RaceGFxHudWrapper extends UTGFxHudWrapper;

defaultproperties
{

MinimapHUDClass=class’RaceGFxMinimapHUD’

}

RaceGFxMinimapHUD.uc

This class will calculate the vehicle’s speed and then transform the value into a value that our speedometer can deal with. The first part of the magic is done in the tick function:

fVehicleSpeed = VSize(UTV.Velocity) * 0.09162; //KPH

Vehicle speed is calculated from the vehicle’s velocity (units per second) and then multiplied with 0.09162.

Why?  If we assume that one UU is 1 inch, we can multiply the result of VSize(UTV.Velocity) by 2,545, to convert it to centimeters per second. To get to km/h, we multiply the result again, by 0,036. In short 2,545 / 100 * 3,6 equals 0,09162. That’s why. If I am wrong here, feel free to point it out.

m_fDisplaySpeed = fVehicleSpeed / 1.11111; // 200 KPH ~ 180°

If you have taken a good look at my speedometer from tutorial 1, you will have noticed that between 0 kph and 200kph the needle has to rotate 180°, so this line “converts” the actual speed to a value that matches 200kph to a rotation of 180°.

The second part of the magic is the function:

simulated function GFxObject GetDisplaySpeed(string VarName)

It prepares the m_fDisplaySpeed variable, for Flash Action Script to read it. How this works exactly, is described here, so I won’t explain this much more.

The entire code for this file should now look like this:

class RaceGFxMinimapHud extends GFxMinimapHud;

var GFxObject root;
var GFxObject speedometerMC;

/** Var that holds the ‘display speed’ */
var float m_fDisplaySpeed;

/** Visibility of the dashboard */
var bool m_bDashboardVisible;

/** Is the player driving? */
var bool m_bDriving;

/** Initialize the Race HUD */

function Init(optional LocalPlayer player)
{

super.Init(player);

root = GetVariableObject(“_root”);
speedometerMC = root.GetObject(“speedometer”);

speedometerMC.SetVisible(false);

}

function TickHud(float DeltaTime)
{

local UTPawn UTP;
local UTVehicle UTV;
local PlayerController PC;
local float fVehicleSpeed;

PC = GetPC();
UTP = UTPawn(PC.Pawn);

/** Speedo */

// Only tick the speedometer, if the player is in a vehicle
if (UTP == None)
{

UTV = UTVehicle(PC.Pawn);

// Player is driving
if ( UTV != None )
{

// Show the speedometer, if it isn’t already visible
if( !m_bDashboardVisible )
ToggleVisible();

// Actionscript will read this variable and
fVehicleSpeed = VSize(UTV.Velocity) * 0.0681825; //KPH
m_fDisplaySpeed = fVehicleSpeed / 1.11111; // 200 KPH ~ 180°

}

}
else
{

if( m_bDashboardVisible )
ToggleVisible();

}

super.TickHud( DeltaTime );
}

/** This function passes the display speed on to flash action script */
simulated function GFxObject GetDisplaySpeed(string VarName)
{

local GFxObject TempObj;
local ASValue asval;
local array<ASValue> args;

TempObj = CreateObject(“Object”);

asval.Type = AS_Number;
asval.n = m_fDisplaySpeed;

args[0] = asval;
TempObj.Set(VarName, args[0]);

return TempObj;

}

/** Toggle visibility of the dashboard */
simulated function ToggleVisible()
{

if( !m_bDashboardVisible )
{

speedometerMC.SetVisible(true);
m_bDashboardVisible = true;

}

else
{

speedometerMC.SetVisible(false);
m_bDashboardVisible = false;

}

}

DefaultProperties
{

MovieInfo=SwfMovie’RaceHud.race_hud’
m_bDashboardVisible = false;

}

3. Importing your HUD

On the Script side we should be done now. Let’s start up the Editor. It should inform you that the Script Files are out of date, since we just added 3 new ones. If it does not, double check the config files and restart it. Confirm the rebuilt of the script files.

Confirm this prompts with yes.

If it all worked out, there will be two yellow warnings in the text window that popped up. They are telling you that the new HUD files we defined cannot be found. That’s because we haven’t added them yet.

With the editor now open, open the content browser and hit the “import” button and import your race_hud.swf file.

Import your new HUD using the context browser

Leave the default settings and click ok.

Settings for importing your HUD

If you are getting spammed by error messages now, then you forgot to copy the contents of the udk_hud folder into your race_hud folder, as mentioned in the first part of this tutorial.

Locate your newly created race_hud package in the “new packages” list of the content browser and right click it and select Save.

click save

As location for your new HUD package choose UDKGame/Content/RaceGame/GFx. This path probably does not exist yet, so create the necessary folders, make sure the name is racehud.upk and click Save.

the save location

4. Getting it to work

Now close the editor and rebuild your scripts in the Frontend by clicking the large green arrow. Make sure you have UDKGame selected, as shown in the picture. and the Launch and Package Game option both disabled. We don’t need them right now.

Note: Ignore the Maps to cook setting I defined here. That’s irrelevant for now.

Unreal Frontend

Once the FrontEnd is done compiling and cooking, reopen the editor.When the default map is loaded, locate the View/Worldproperties settings window and in there set Default Game Type and Game Type for PIE to RaceGame. That is necessary for this map (or any of your maps for that matter) to use your new HUD.

required game type settings

Now, as a last step, add a UT vehicle of your choice and start the map in PIE. If all worked out, it will look like this:

final result

Enjoy.

You can find the files I used here.

Uh, my first tutorial for the UDK. But hopefully not my last. This time I will show you how to add a speedometer to your vehicle-based UDK game, using some Unreal Script (not that much really) and Scaleform. All necessary files can be found at the bottom of this tutorial.

Ideally, when you’re through this tutorial, the result should look like this: (minus the Audi maybe…)

speedometer in action

The requirements:

  • UDK February 2012, this should work with older versions though
  • Your game is using the UDK SVehicle code
  • Adobe Flash, or any other Flash builder that outputs UDK compatible .swf files and some basic flash skills.
  • A text editor
  • Some very basic Unreal Script and Frontend knowledge, I’ll try to walk you through the worst pitfalls though.
  • Action Script knowledge is beneficial, I will not explain it’s syntax or offer deeper explanation beyond what’s necessary for this tutorial.
  • Capability to read and actually gather information from posted screenshots. I will not create videos tutorials here, as I am not particularly a fan of these.

1. The Groundwork

The first step is to create the speedometer HUD in Flash. I assume you want to keep using the standard UDK HUD, so we will edit this one. You can find it in your UDK/UDKGame/Flash/UDKHud/ folder. It’s the file called udk_hud.fla

To keep your project’s file structure clear and update proof, copy this file and move back one folder. Create your own folder in the Flash folder and name it whatever you want. Now paste the file into that folder and open it. If you are lazy, you can edit the original udk_hud.fla directly, but don’t complain when your modifications vanish with the next UDK update. When you’re done it should look like this:

UDK HUD folder structure

Note: The race_hud folder contains all images from the original udk_hud folder. If you don’t copy it over, you will get many warnings when importing the hud.

2. The visuals

Now open the .fla file, lock all existing layers in the timeline and add your own layer. In this layer, add your speedometer graphics. When you’re happy with it, select it all (minus the indicator needle!) right click and choose: “Convert to Symbol”. There you can call it anything you want, this name is just for identification in the library. As type, use “Movie Clip”.

Convert to Symbol

Select your speedometer on the stage and open the properties window. It’s important to give it an instance name, otherwise it won’t work later. Name it speedometer and stick to this! Unreal and Action Script will look up the instance names on your stage, it will ignore the same names if they’re only found in the library.

Speedometer movie clip

Next step: Double click your speedometer, to get into isolation mode. There you create (or copy) your speedometer needle. Make sure that it’s pivot point is in the middle of the speedometer (you can move the image independently from the pivot, if you double click the needle). Back in the speedometer isolation view, select the needle and turn it into a movie clip as well. Give it it’s own instance name: IndicatorNeedle, that again is important, if you want Unreal Script and Action Script to recognize your stage graphics.

Speedometer needle setup in Flash

That should be it on the visual side of things. Next thing is to script your speedo to life in ActionScript.

3. Action Script

Take a closer look at your timeline layers again. At the top there is a layer called “Actions”. Unlock it and hit “F9”, that’s the scripts hotkey. You should now see this:

import flash.external.ExternalInterface;

_global.gfxExtensions = true;

var minimapContainer:MovieClip = this.createEmptyMovieClip(“minimapContainer”, this.getNextHighestDepth());
minimapContainer._x = 970;
minimapContainer._y = 8;
minimapContainer.loadMovie(“udk_minimap.swf”);

Key.addListener(this);
ExternalInterface.call(“registerHUDView”, this);

////////////////////////////////////////////////////////////

function resetLayout(mc:MovieClip, xshift:Number, yshift:Number):Void {
if (mc[“_ox”] == undefined) {
mc[“_ox”] = mc._x;
mc[“_oy”] = mc._y;
}
mc._x = mc[“_ox”] + xshift;
mc._y = mc[“_oy”] + yshift;
}

Stage.scaleMode = “noBorder”;
function onResize(visibleRect:flash.geom.Rectangle)
{
var originalRect:flash.geom.Rectangle = Stage[“originalRect”];
var owidth:Number = (originalRect.right – originalRect.left);

var vheight:Number = (visibleRect.bottom – visibleRect.top);
var vwidth:Number = (visibleRect.right – visibleRect.left);

var noyshift:Boolean = (vwidth == owidth);

var vwidthSWF:Number = (vheight * 16 / 9);
var vheightSWF:Number = (vwidth * 9 / 16);
var xshift:Number = noyshift ? 0 : (vwidthSWF – vwidth) / 2;
var yshift:Number = noyshift ? (vheightSWF – vheight) / 2 : 0;

var leftShift:Number = (xshift);
var rightShift:Number = (-xshift);
var topShift:Number = (yshift);
var bottomShift:Number = (-yshift);

// Reposition elements
resetLayout(title, leftShift, topShift);
resetLayout(stats, leftShift, topShift);
resetLayout(minimapContainer, rightShift, topShift);
resetLayout(log, leftShift, bottomShift);
resetLayout(teamStats, leftShift, bottomShift);
resetLayout(rank, leftShift, bottomShift);
resetLayout(expBar, leftShift, bottomShift); // Special case below
resetLayout(playerStats, rightShift, bottomShift);
resetLayout(vehicleDashboard, rightShift, bottomShift);
resetLayout(flagRed, rightShift, bottomShift);
resetLayout(flagBlue, rightShift, bottomShift);
resetLayout(centerTextMC, 0, topShift);
resetLayout(popup, 0, topShift);

// Special case for expBar
if (expBar[“_owidth”] == undefined) { expBar[“_owidth”] = expBar._width; }
expBar._width = expBar[“_owidth”] – (2 * leftShift);

}
Stage.addListener(this);
onResize(Stage.visibleRect);

We will have to add a few lines of our own code, the “onEnterFrame” function to be precise. It doesn’t matter where, I put it above the “ResetLayout” function. The basic idea for this comes from the UDK Scaleform docu.

onEnterFrame = function()
{
var retVal:Object = {};

// Parameter 0 = the function to call in Unreal Script.

// Parameter 1 = the variable name in UnrealScript.

retVal = ExternalInterface.call(“GetDisplaySpeed”, “m_fDisplaySpeed”);

_root.speedometer.IndicatorNeedle._rotation = retVal.m_fDisplaySpeed;
}

What is happening here is, that every tick (onEnterFrame) an external call grabs a value called m_fDisplaySpeed from inside the UnrealScript vehicles. We will have to make these vehicles actually have and write this variable later. It is then written into the variable retval. RetVal is used to calculate the rotation of the speedometer needle.

In order to do this, it looks up _root, which is the stage and it’s containing parts speedometer and the one level deeper IndicatorNeedle. If it can find these Movie Clips, it will set the indicator needle _rotation value to whatever it got from m_fDisplaySpeed i.e. retVal.

Last but not least, publish this file as .swf, using AS 2.0 and Flashplayer 8.0 (I haven’t tried newer versions yet).

SWF publish settings

That’s it on the Flash side. In the second part I will show you how to implement your speedometer in UnrealScript. If you want to take a closer look at this setup, I have uploaded my .fla file containing the speedometer and the AS code only, here.