In this chapter, we will cover several key topics for your gaming environment. These include sound, moving elements like platforms and gates, and information displays. These constitute the last pieces before we move to an actual gameplay example in the next chapter.
Sounds in the UDK are generated through Sound Cues that can combine sound data with functions that alter or process sound effects like looping and attenuation. In a hands-on example we show you how to add sounds to a weapon through the weapon's projectile class. This is followed by a brief discussion of Kismet and Matinee with respect to moving objects including platforms and locked gates. Finally, the Unreal Heads Up Display, or HUD, is covered and a hands-on example is given that displays important items like the player's score, lives left, and current health.
In this section we will cover Sound Cues. First we will give you an overview of the Sound Cue Editor and its major features such as attenuation and sound looping. Next, we will show you how to place Sound Cues in a level using the Unreal Editor. We then show you how to use UnrealScript to play a Sound Cue dynamically from within a program. In the next chapter, we present a hands-on example that uses the information and code presented here.
The Sound Cue Editor is where you can create new Sound Cues as well as modify existing Sound Cues. Sound Cues consist of one or more SoundNodeWave items (which hold the actual sound data) and sound operators which alter the final sound that is output. We won't describe every aspect of the Sound Cue Editor but touch on the key points that are needed to give you a basic working knowledge of Sound Cues.
NOTE: Since Sound Cues are based on sound files of .wav format, any program that can capture and save or convert sounds to .wav format can be used to create audio data for Sound Cues. You can import .wav files by pressing the Import button located in the Content Browser. One program to record and save sound files in .wav format is Audacity which is a free, public-domain program.
Search for the Sound Cue called A_Powerup_UDamage_SpawnCue
in the Content Browser by typing its name into the asset search box. Also check the Sound Cues checkbox under Object Types Favorites to make sure only Sound Cues are shown in the Preview Pane. Right-click on the item and select Edit Using Sound Cue Editor. This should bring up the Sound Cue Editor. See Figure 6–1.
This Sound Cue uses attenuation. Attenuation allows your sound to fade away according to the distance from the sound's source in the game world. For example, when a car is on fire, the sound of the fire naturally fades away with a greater distance from the fire. In the UDK the sound cue Vehicle_Damage_FireLoop_Cue uses attenuation to simulate this real-world situation.
Click the Attenuation node to bring up the attenuation properties. See Figure 6–2.
The most important properties are the Distance Algorithm, Radius Min, and Radius Max.
Looping is the repetition of the same sound. This is appropriate for sounds that must be played continuously forever or for a short period of time. For example, the sound of the ocean hitting the shore can be played continuously if you are near a beach. Another example would be to play the sound of an alarm four times to indicate that an intruder has breached an area in your game world.
Now, search for Vehicle_Damage_FireLoop_Cue by typing that asset name into the search box. Right-click on the item in the preview pane and select Edit Using Sound Cue Editor to bring up the Sound Cue Editor. The set up of the Sound Cue is shown in Figure 6–3.
This Sound Cue uses both attenuation and looping to modify the behavior of the output sound. Click on the Looping node. The looping properties should be displayed as in Figure 6–4.
There are three values in the Looping node:
The random node's purpose is to play different variations of the same general sound so that the listener does not find the sound repetitive. A good example is background noises like insects and other environmental noises.
An example of a Sound Cue that uses a Random Node to select random sounds to play back is the S_BulletImpact_01_Cue. Type this into the search box and right-click on the asset in the preview pane and bring it up into the Sound Cue Editor. The Sound Cue layout should look like Figure 6–5.
This Sound Cue uses attenuation and randomness to produce the final sound from three possible sound effects. The final sound output will be affected by both attenuation and random selection. What this means is that final sound will be played from a random selection of sounds and will decrease in volume as the listener moves farther away from it.
The random properties are shown in Figure 6–6.
The Weights property allows you to set the probability that each sound would be selected. Here each is set to 1.0 which means that each sound effect has an equal chance of being selected for output.
The purpose of the Modulator node is to change the volume and/or pitch of the sound data being played. This can be a quick and easy way to tweak a sound once it has been sampled.
Search for the Sound Cue A_Effort_EnigmaMean_Death_Cue by typing that term in the search box. Right-click the asset in the preview pane and bring it up in the Sound Cue Editor. The Sound Cue structure should look like Figure 6–7.
This Sound Cue uses a combination of attenuation, modulation, and randomness in order to produce the final sound. The modulation properties are shown in Figure 6–8.
The Modulation node is used to pick a random pitch and volume within a range. The range values are:
For example, you could set the Pitch Min and Pitch Max values to 5.0 and the Volume Min and Volume Max values to 2.0 to increase the pitch of the sound sample 5 times normal value and increase the volume of the sound sample to twice the normal value.
You can add Sound Cues directly to levels using the Unreal Editor. For example to put a fire sound that loops, select the Vehicle_Damage_FireLoop_Cue that was mentioned earlier. Right-click on an empty space just in front of the cube in the default level and select Add Ambient Sound to add this Sound Cue to the level. Run the level in the Mobile Previewer and walk toward and away from the cube to hear the sound increase in volume as you get closer to the sound source and decrease in volume as you walk away. To add this Sound Cue to the level see Figure 6–9. Adding Sound Cues via this method is good for stationary environmental sounds such as insects, and the sound of an ocean near the beach.
If a sound is not stationary and/or needs to be generated when an action in the game occurs then it should be created dynamically using UnrealScript.
In order for an UnrealScript class to play a Sound Cue it must be derived from the Actor
class which contains the PlaySound()
function. The PlaySound()
function is defined in the Actor
class as follows:
PlaySound(SoundCue InSoundCue,
optional bool bNotReplicated,
optional bool bNoRepToOwner,
optional bool bStopWhenOwnerDestroyed,
optional vector SoundLocation,
optional bool bNoRepToRelevant);
The important parameters that are relevant to our needs are the parameters InSoundCue
and bStopWhenOwnerDestroyed.
InSoundCue
is the reference to the Sound Cue to play and bStopWhenOwnerDestroyed
allows you to stop playing the Sound Cue when the owner playing it is destroyed.
If the sound needs to be attached to a Kismet related action such as the opening of a door or a gate then an easy way to provide sound effects is through Kismet.
Bring up the Kismet panel by clicking on the K icon in the top row of icons on the Unreal Editor. Right-click on an empty area of the Kismet panel and select New Action Sound Play Sound to create a new Play Sound node. See Figure 6–10.
To set a sound cue to be played when this node is activated click on the node to bring up its properties and enter the name of the Sound Cue in the Play Sound field. An easy way to do this is to select a Sound Cue in the Content Browser and then click the arrow to the right of the Play Sound field to have the name of the selected Sound Cue put into the field.
In this example, we will begin a larger project for the next chapter. We will create a new weapon class and projectile class that incorporate Sound Cues. Remember all classes that are derived from the Actor class, which is most classes, are able to produce sounds via the PlaySound()
function defined in the Actor
class and is accessible to derived or extended classes. Both the Weapon
and Projectile
classes are derived from the Actor
class. We choose the Projectile
class to add the sounds into because this is where the projectiles are actually initialized and explosions of the projectiles are handled. This is designed to illustrate how to incorporate Sound Cues into a real world UnrealScript example and demonstrate how to use Sound Cues dynamically.
First you need to create a new directory for this project. Create a new directory called ExampleCh6 under your default UDK installation directory at C:UDKUDK-2011-06DevelopmentSrc. The exact base directory will depend on which version of the UDK you are using. The above base directory is set for the June 2011 UDK version.
Create another directory called Classes under the directory you just created. You should store all the UnrealScript files for this project under the Classes directory.
Next, you need to create a new class called JazzWeaponSound
and save it to the Classes directory under the filename JazzWeaponSound.uc. See Listing 6–1.
NOTE: Remember that all UnrealScript files must be named after the class in them with a .uc extension and placed in a Classes directory under a main project directory.
class JazzWeaponSound extends Weapon;
defaultproperties
{
Begin Object Class=SkeletalMeshComponent Name=FirstPersonMesh
SkeletalMesh=SkeletalMesh'KismetGame_Assets.Anims.SK_JazzGun'
End Object
Mesh=FirstPersonMesh
Components.Add(FirstPersonMesh);
Begin Object Class=SkeletalMeshComponent Name=PickupMesh
SkeletalMesh=SkeletalMesh'KismetGame_Assets.Anims.SK_JazzGun'
End Object
DroppedPickupMesh=PickupMesh
PickupFactoryMesh=PickupMesh
WeaponFireTypes(0)=EWFT_Projectile
WeaponFireTypes(1)=EWFT_NONE
WeaponProjectiles(0)=class'JazzBulletSound'
WeaponProjectiles(1)=class'JazzBulletSound'
FiringStatesArray(0)=WeaponFiring
FireInterval(0)=0.25
Spread(0)=0
}
The important code is highlighted in bold print. The rest of code should look familiar from our coverage of weapons in Chapter 3.
We specify a new JazzBulletSound
class for our projectile. It is in this class that we will add sounds associated with our bullets.
Next, we need to create the JazzBulletSound
class that is derived from the Projectile
class. See Listing 6–2.
class JazzBulletSound extends Projectile;
var SoundCue FireSound;
var bool ImpactSoundPlayed;
simulated singular event Touch(Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal)
{
Other.TakeDamage(33, InstigatorController, HitLocation, -HitNormal, None);
}
simulated function Explode(vector HitLocation, vector HitNormal)
{
if (!ImpactSOundPlayed)
{
PlaySound(ImpactSound);
ImpactSoundPlayed = true;
}
}
function Init( Vector Direction )
{
local vector NewDir;
NewDir = Normal(Vector(InstigatorController.Pawn.Rotation));
Velocity = Speed * NewDir;
PlaySound(SpawnSound);
PlaySound(FireSound, , , true,,);
}
defaultproperties
{
Begin Object Class=StaticMeshComponent Name=Bullet
StaticMesh=StaticMesh'EngineMeshes.Sphere'
Scale3D=(X=0.050000,Y=0.050000,Z=0.05000)
End Object
Components.Add(Bullet)
Begin Object Class=ParticleSystemComponent Name=BulletTrail
Template=ParticleSystem'Castle_Assets.FX.P_FX_Fire_SubUV_01'
End Object
Components.Add(BulletTrail)
MaxSpeed=+05000.000000
Speed=+05000.000000
FireSound = SoundCue'A_Vehicle_Generic.Vehicle.Vehicle_Damage_FireLoop_Cue'
ImpactSound = SoundCue'KismetGame_Assets.Sounds.S_BulletImpact_01_Cue'
SpawnSound = SoundCue'A_Pickups_Powerups.PowerUps.A_Powerup_UDamage_SpawnCue'
ImpactSoundPlayed = false
}
In this class we add sound effects for the impact of the projectile (ImpactSound
), the firing of the weapon (SpawnSound
) and the sound of the flames (FireSound
) that are attached to the projectile via particle emitter.
The Sound Cues are set in the defaultproperties
block and played back through the PlaySound()
function.
This code will be incorporated in a hands-on example in the next chapter. In the mean time you can preview the sound effects by searching for these Sound Cues in the Content Browser in the Unreal Editor and double-clicking on them to play them.
Kismet is the graphical version of UnrealScript. Kismet in combination with Unreal Matinee does an excellent job in controlling the movement of objects like platforms and the opening and closing of gates. Moving platforms that can move characters in the game world are created with InterpActors. Objects called triggers can be used to initiate the movement of closed gates or doors so that they become open.
Kismet is used to trigger the movement of platforms and gates and Unreal Matinee defines the exact movement that the platform, gate, or door should follow. Matinee uses a keyframe method of animation where you set certain frames that indicate the object's position in the world at certain times and then the Matinee will generate all the positions for the frames in between the keyframes. In this section we show you:
NOTE: There is also more information concerning Kismet and Matinee discussed back in Chapter 2.
In this hands-on example we will create a moving platform that can move the player's pawn from the ground level to the top of the cube of the default level.
Figure 6–11. Gate Mesh platform
Figure 6–13. Matinee node for our gate platform
Figure 6–14. Red marker that denotes the end of the Matinee sequence
Figure 6–16. Starting the first key frame with the gate at the default ground level.
Figure 6–18. Changing the position of the gate for the final keyframe
Figure 6–19. Initializing the new moving gate platform
Everything should now be set up so that you can have your pawn walk on the gate and have it move up. Select a game type from a previous chapter (such as Chapter 3) that allows you to see your pawn in the third person. A good choice would be the ExampleCh31Game game type.
Run the game on the mobile previewer. You should now be able to walk your pawn over the gate and the gate will automatically move up to the top of the cube. See Figure 6–20.
In this example we will create a gate that can be opened by the player touching a trigger.
Sm_Barrel_01
or RemadePhysBarrel
. Type one of these names into the search box to bring it up in the preview panel. You can select one of these and drag and drop it into your level. See Figure 6–21.
Figure 6–21. Gate with trigger
Figure 6–23. Creating the keyframe for the gate's initial position.
Figure 6–24. Creating the keyframe for the gate's final position
Figure 6–26. Opening the gate by touching the trigger
The last topic we cover in this chapter is the HUD in preparation for the topic that comes in the next chapter, which is gameplay. In term of the player's environment the HUD is probably the most apparent since it is right in the player's face literally. A HUD can be a basic one that displays the player's statistics or much more complex such as in a vehicle simulation that includes graphics that represent the vehicle's controls and the interior of the vehicle itself.
The Heads Up Display or HUD contains information that may be of interest to the player such as the number of lives left, current health, or score. The HUD can be drawn using Scaleform or the Canvas class. Scaleform refers to the Scaleform Gfx system that enables Adobe Flash based HUDs to run on the UDK.
Creating code that is compatible with Scaleform requires tools outside the UDK and requires the extra work of setting up scenes in Adobe Flash and graphics in programs like Adobe Photoshop. For these reasons only the Canvas method of HUD creation will be used in this book.
For developing iOS games for the mobile platform you should create a custom HUD class that derives from UDKHud as follows:
class ExtendedHUD extends UDKHud;
The main function that you need to override in your custom HUD class to draw your own items is the DrawHUD()
function. An example structure of a DrawHUD()
function in a derived class that adds to the HUD is as follows:
function DrawHUD()
{
super.DrawHUD();
// Put your custom code here that draws to the HUD
}
In the class where you define the type of game to be played you need to set your HUDType
in the defaultproperties
to your new custom HUD class.
defaultproperties
{
PlayerControllerClass=class'ExampleCh6.ExampleCh6PC'
DefaultPawnClass=class'ExampleCh6.Jazz3Pawn'
HUDType=class'ExampleCh6.ExtendedHUD'
bRestartLevel=false
bWaitingToStartMatch=true
bDelayedStart=false
}
In order to draw text as well as do such things as set the color of the text, and the position of the cursor that draws the text on the HUD you use the Canvas
object.
The Canvas object is created from the Canvas
class which is a built-in class in the UDK that contains functions that allow the user to draw on the screen.
In the HUD
class which is the base class for the HUD there is a variable called Canvas
that can be used to draw text and graphics on our HUD.
Var Canvas Canvas;
The following is a list of key functions in the Canvas
class. The examples show you how to use these functions from within the HUD
class.
DrawText()
—To draw text on the screen use the DrawText()
function.
Canvas.DrawText("Hello World");
SetDrawColor()
—You can set the color of the text by calling the SetDrawColor()
function. The input parameters R, G, B refer to the colors Red, Green, and Blue. These three values are used to define the color of the text that will be drawn. The values range from 0-255.
Canvas.SetDrawColor(R, G, B);
SetPos()
—You can set the position of the cursor that draws the text on the HUD by calling the SetPos()
function
Canvas.SetPos(X, Y);
TextSize()
—Gets the horizontal and vertical size of the input text as it would appear on the screen in screen pixels and returns it in the last two parameters. The TextLabel
variable holds the text in string format. The last two variables hold the numerical values of the size of the text in TextLabel
in the X (horizontal) and Y (vertical) directions.
Canvas.TextSize(TextLabel, TextSizeX, TextSizeY);
You can draw textures to the HUD by using the DrawTextureBlended()
function.
Canvas.DrawTextureBlended(DefaultTexture1, 1, BLEND_Masked);
The first parameter is a reference to the actual texture. The second parameter is the scale factor that will be applied to the horizontal and vertical lengths of the texture. The third parameter is the blend mode, with several options.
BLEND_Opaque
to put the texture on the HUD without any alterations of the colors.BLEND_Additive
to add the colors of the texture and the background color already on the HUD to create a final color that will be placed on the HUD.BLEND_Masked
to put the texture on the HUD without the black pixels.In this example we will create the basic custom HUD that we will use in the larger example that we will create later in the next chapter. Create a new file for this class in your Classes directory under the project directory called ExtendedHUD.uc and put in the following code. See Listing 6–3.
class ExtendedHUD extends UDKHud;
var Texture DefaultTexture1;
var Texture DefaultTexture2;
var Texture DefaultTexture3;
var Texture DefaultTexture4;
var Texture DefaultTexture5;
struct HUDInfo
{
var string Label;
var Vector2D TextLocation;
var Color TextColor;
var Vector2D Scale;
};
// HUD
var HUDInfo HUDHealth;
var HUDInfo HUDLives;
var HUDInfo HUDGameOver;
var HUDInfo HUDScore;
simulated function PostBeginPlay()
{
Super.PostBeginPlay();
HUDHealth.Label = "Health:";
HUDHealth.TextLocation.x = 1100;
HUDHealth.TextLocation.y = 50;
HUDHealth.TextColor.R = 0;
HUDHealth.TextColor.G = 0;
HUDHealth.TextColor.B = 255;
HUDHealth.Scale.X = 2;
HUDHealth.Scale.Y = 4;
HUDLives.Label = "Lives:";
HUDLives.TextLocation.x = 600;
HUDLives.TextLocation.y = 50;
HUDLives.TextColor.R = 0;
HUDLives.TextColor.G = 255;
HUDLives.TextColor.B = 0;
HUDLives.Scale.X = 2;
HUDLives.Scale.Y = 4;
HUDGameOver.Label = "GAME OVER";
HUDGameOver.TextLocation.x = 400;
HUDGameOver.TextLocation.y = 300;
HUDGameOver.TextColor.R = 255;
HUDGameOver.TextColor.G = 0;
HUDGameOver.TextColor.B = 255;
HUDGameOver.Scale.X = 7;
HUDGameOver.Scale.Y = 7;
HUDScore.Label = "Score:";
HUDScore.TextLocation.x = 0;
HUDScore.TextLocation.y = 50;
HUDScore.TextColor.R = 255;
HUDScore.TextColor.G = 0;
HUDScore.TextColor.B = 0;
HUDScore.Scale.X = 2;
HUDScore.Scale.Y = 4;
}
function DrawHUDItem(HUDInfo Info, coerce string Value)
{
local Vector2D TextSize;
Canvas.SetDrawColor(Info.TextColor.R, Info.TextColor.G, Info.TextColor.B);
Canvas.SetPos(Info.TextLocation.X, Info.TextLocation.Y);
Canvas.DrawText(Info.Label, ,Info.Scale.X, Info.Scale.Y);
Canvas.TextSize(Info.Label, TextSize.X, TextSize.Y);
Canvas.SetPos(Info.TextLocation.X + (TextSize.X * Info.Scale.X), Info.TextLocation.Y);
Canvas.DrawText(Value, , Info.Scale.X, Info.Scale.Y);
}
function DrawHUD()
{
local int Lives;
super.DrawHUD();
/*
// Blend Modes = BLEND_Opaque, BLEND_Additive, and BLEND_Modulate modes
Canvas.SetPos(0,0);
Canvas.DrawTextureBlended(DefaultTexture1, 1, BLEND_Opaque);
Canvas.SetPos(150,0);
Canvas.DrawTextureBlended(DefaultTexture2, 1, BLEND_Additive);
Canvas.SetPos(300,0);
Canvas.DrawTextureBlended(DefaultTexture3, 1, BLEND_Masked);
Canvas.SetPos(450,0);
Canvas.DrawTextureBlended(DefaultTexture4, 1, BLEND_Masked);
Canvas.SetPos(600,0);
Canvas.DrawTextureBlended(DefaultTexture5, 1, BLEND_Masked);
*/
Canvas.Font = class'Engine'.static.GetLargeFont();
// Score
DrawHUDItem(HUDScore,ExampleCh6PC(PlayerOwner).Score);
// Lives
Lives = Jazz3Pawn(PlayerOwner.Pawn).Lives;
DrawHUDItem(HUDLives, Lives);
// Health
DrawHUDItem(HUDHealth, PlayerOwner.Pawn.Health);
// Game Over
if (ExampleCh6PC(PlayerOwner).GameOVer)
{
DrawHUDItem(HUDGameOver, "");
}
}
defaultProperties
{
DefaultTexture1= Texture2D'EditorResources.Ambientcreatures' // Yellow Chick 32 by 32
DefaultTexture2= Texture2D'EditorResources.Ammo' // Ammo Icon 32 by 32
DefaultTexture3= Texture2D'EditorResources.LookTarget' // Target 32 by 32
DefaultTexture4= Texture2D'EditorMaterials.Tick' // Green Check 32 by 32
DefaultTexture5= Texture2D'EditorMaterials.GreyCheck' // Grey Check 32 by 32
}
The key function in this class is the DrawHUDItem()
function that draws the actual text on the HUD based on a HUDInfo
entry along with the input value for that entry.
The HUD displays the player's score, lives left, and health. This custom HUD class also provides examples of how to draw various textures to the HUD in the commented out section. The preview of the HUD as part of the larger game play example that is created later in the next chapter is shown in Figure 6–28.
In this chapter we covered Sound Cues, the Sound Cue Editor that is used to create Sound Cues from sound data, how to use Sound Cues from within the Unreal Editor, from within UnrealScript in real-time during gameplay, and from within Kismet. Next, we discussed how to use Kismet and Matinee to control the movement of platforms and locked gates, as well as how to add sounds to the opening of a gate. We then covered the Unreal Heads Up Display and showed you how to create a custom HUD in UnrealScript.
3.145.112.217