Our battlemap is working fairly well at this point. But unless our heroes happen upon one of our prescripted triggers, it's pretty static. Let's add some special effects that we can toss out during combat for fun.
We're going to expand on what we learned about creating torches (extending an existing game object) and extend our own objects.
BattleMapEmitterEffect.uc
Let's start with a basic fireball.
Our torch was based on the EmitterSpawnable object, and extended to include movement and interactivity. This is a similar object extended from EmitterSpawnable, but we're only adding two features: a self-destruct timer (we only want it alive for a few seconds) and a camera shake. However, we've also made many of the values parameters so that they can be extended:
When we spawn this with a keystroke, it will throw down a screen shaking fireball wherever we're pointing.
With this as a base, creating other effects is simple. We extend our own object and swap out the particle system template. Below are three more effects: a force ball, a lightning bolt, and for the ranger in our group who fires Tomahawk cruise missiles instead of arrows, an earth-shattering nuclear explosion.
BattleMapEmitterEffectForce.uc
BattleMapPlayerInput.uc
We already have a function for spawning objects (so far, just the torch) so we just need to add our new effects to BMSpawn():
Finally, bind a key to the spawn function just like we did the torch:
BattleMapBlood.uc
We also need a way to mark creatures that have been "bloodied" during battle. The UDK has the perfect system for this: Decals. We'll create our own Decal actor to "spray" blood on the map. But first, we need some blood.
For simplicity's sake, I made a copy of the Bio_Splat_Decal_001 DecalMaterial (I liked the "wet" effect) and saved it to my BattleMapAssets package. Then I inserted a "Multiply" at the end to make it red instead of green:
Our extended DecalActorMovable object below has two extra features: it ensures the decal is always sprayed straight "down", and it adds a collision component so that we can detect it with the mouse:
Since we're only using a single decal, the PostBeginPlay() function also randomly rotates the blood so that the same splat doesn't look mirrored all over the battle field. You could also randomly swap out the Material if you had several blood textures.
Don't forget to add the reference to our BattleMapPlayerInput.BMSpawn() function:
To wrap it up, we need a way to clean up our mess and delete torches and blood that we've spawned. We already know how to determine what object we're pointing at, so we just call that object's Destroy() function. Add the following function to BattleMapPlayerInput:
BattleMap mode source files
We're going to expand on what we learned about creating torches (extending an existing game object) and extend our own objects.
BattleMapEmitterEffect.uc
Let's start with a basic fireball.
Our torch was based on the EmitterSpawnable object, and extended to include movement and interactivity. This is a similar object extended from EmitterSpawnable, but we're only adding two features: a self-destruct timer (we only want it alive for a few seconds) and a camera shake. However, we've also made many of the values parameters so that they can be extended:
class BattleMapEmitterEffect extends EmitterSpawnable;
var float EffectLifespan;
var float EffectStarted;
var float ShakeScale;
var float OscillationDur;
var float PitchAmp;
var float PitchFreq;
var float YawAmp;
var float YawFreq;
var float RollAmp;
var float RollFreq;
simulated function PostBeginPlay()
{
EffectStarted = WorldInfo.TimeSeconds;
DoCameraEffects();
}
function Tick( float DeltaTime )
{
if ((WorldInfo.TimeSeconds - EffectStarted) > EffectLifespan)
self.Destroy();
}
function DoCameraEffects()
{
local CameraShake Shake;
local BattleMapPlayerController PC;
foreach WorldInfo.LocalPlayerControllers(class'BattleMapPlayerController', PC)
{
if (PC.PlayerCamera != None)
{
Shake = new class'CameraShake';
Shake.OscillationDuration = OscillationDur;
Shake.RotOscillation.Pitch.Amplitude = PitchAmp;
Shake.RotOscillation.Pitch.Frequency = PitchFreq;
Shake.RotOscillation.Yaw.Amplitude = YawAmp;
Shake.RotOscillation.Yaw.Frequency = YawFreq;
Shake.RotOscillation.Roll.Amplitude = RollAmp;
Shake.RotOscillation.Roll.Frequency = RollFreq;
PC.ClientPlayCameraShake(Shake, ShakeScale, false);
}
}
}
DefaultProperties
{
EffectLifespan=3.0
ShakeScale=1.0
OscillationDur=1.0
PitchAmp=20.0
PitchFreq=40.0
YawAmp=20.0
YawFreq=30.0
RollAmp=20.0
RollFreq=50.0
DrawScale=3.000000
Begin Object Name=ParticleSystemComponent0
Template=ParticleSystem'Envy_Effects.Particles.P_VH_Gib_Explosion'
ReplacementPrimitive=None
LightingChannels=(bInitialized=True,Dynamic=True)
LODLevel=1
End Object
ParticleSystemComponent=ParticleSystemComponent0
RemoteRole=ROLE_SimulatedProxy
bAlwaysRelevant=true
bReplicateMovement=true
bNetTemporary=true
bNoDelete=false
}
When we spawn this with a keystroke, it will throw down a screen shaking fireball wherever we're pointing.
With this as a base, creating other effects is simple. We extend our own object and swap out the particle system template. Below are three more effects: a force ball, a lightning bolt, and for the ranger in our group who fires Tomahawk cruise missiles instead of arrows, an earth-shattering nuclear explosion.
BattleMapEmitterEffectForce.uc
class BattleMapEmitterEffectForce extends BattleMapEmitterEffect;BattleMapEmitterEffectLightning.uc
DefaultProperties
{
DrawScale=1.000000
Begin Object Name=ParticleSystemComponent0
Template=ParticleSystem'P_WP_ShockRifle_Explo'
End Object
}
class BattleMapEmitterEffectLightning extends BattleMapEmitterEffect;BattleMapEmitterEffectNuke.uc
DefaultProperties
{
DrawScale=2.000000
Rotation=(Pitch=16384,Yaw=0,Roll=0)
Begin Object Name=ParticleSystemComponent0
Template=ParticleSystem'PS_Scorpion_Gun_Impact'
End Object
}
class BattleMapEmitterEffectNuke extends BattleMapEmitterEffect;
DefaultProperties
{
PitchAmp=150.0
PitchFreq=40.0
YawAmp=75.0
YawFreq=30.0
RollAmp=150.0
RollFreq=50.0
Begin Object Name=ParticleSystemComponent0
Template=ParticleSystem'P_VH_Death_SpecialCase_1_Base_Near'
End Object
}
BattleMapPlayerInput.uc
We already have a function for spawning objects (so far, just the torch) so we just need to add our new effects to BMSpawn():
exec function BMSpawn(string ObjectToSpawn)DefaultInput.ini
{
if (WorldInfo.NetMode == NM_Standalone || WorldInfo.NetMode == NM_ListenServer)
{
switch(ObjectToSpawn)
{
case "Torch":
Spawn(class'BattleMapTorch',Outer,,MouseOrigin,,,true );
break;
case "Fireball":
Spawn(class'BattleMapEmitterEffect',Outer,,MouseOrigin );
break;
case "Force":
Spawn(class'BattleMapEmitterEffectForce',Outer,,MouseOrigin );
break;
case "Lightning":
Spawn(class'BattleMapEmitterEffectLightning',Outer,,MouseOrigin );
break;
case "Nuke":
Spawn(class'BattleMapEmitterEffectNuke',Outer,,MouseOrigin );
break;
}
}
}
Finally, bind a key to the spawn function just like we did the torch:
-Bindings=(Name="F1",Command="GBA_ShowScores")
-Bindings=(Name="F2",Command="GBA_ShowMap")
-Bindings=(Name="F3",Command="GBA_ToggleMinimap")
.Bindings=(Name="F1",Command="BMSpawn Fireball")
.Bindings=(Name="F2",Command="BMSpawn Force")
.Bindings=(Name="F3",Command="BMSpawn Lightning")
.Bindings=(Name="F4",Command="BMSpawn Nuke")
BattleMapBlood.uc
We also need a way to mark creatures that have been "bloodied" during battle. The UDK has the perfect system for this: Decals. We'll create our own Decal actor to "spray" blood on the map. But first, we need some blood.
For simplicity's sake, I made a copy of the Bio_Splat_Decal_001 DecalMaterial (I liked the "wet" effect) and saved it to my BattleMapAssets package. Then I inserted a "Multiply" at the end to make it red instead of green:
Our extended DecalActorMovable object below has two extra features: it ensures the decal is always sprayed straight "down", and it adds a collision component so that we can detect it with the mouse:
class BattleMapBlood extends DecalActorMovable;
simulated function PostBeginPlay()
{
local Rotator newRot;
newRot.Pitch = -16384;
newRot.Yaw = Rand(65536);
newRot.Roll = -65536;
SetRotation(newRot);
}
DefaultProperties
{
Begin Object Name=NewDecalComponent
DecalMaterial=DecalMaterial'BattleMapAssets.Materials.Blood_Decal'
End Object
Begin Object Class=CylinderComponent Name=CollisionCylinder
CollisionRadius=+0064.000000
CollisionHeight=+0064.000000
BlockNonZeroExtent=true
BlockZeroExtent=true
BlockActors=true
CollideActors=true
End Object
CollisionComponent=CollisionCylinder
Components.Add(CollisionCylinder)
RemoteRole=ROLE_SimulatedProxy
bAlwaysRelevant=true
bReplicateMovement=true
bNetTemporary=false
bCanBeDamaged = false
bCollideActors = true
bBlockActors = true
bCollideWorld = false
bStatic=false
bNoDelete=false
bMovable=true
}
Since we're only using a single decal, the PostBeginPlay() function also randomly rotates the blood so that the same splat doesn't look mirrored all over the battle field. You could also randomly swap out the Material if you had several blood textures.
Don't forget to add the reference to our BattleMapPlayerInput.BMSpawn() function:
case "Blood":And bind a key to it in DefaultInput.ini:
Spawn(class'BattleMapBlood',Outer,,MouseOrigin );
break;
-Bindings=(Name="B",Command="GBA_ToggleSpeaking")BattleMapPlayerInput.uc
.Bindings=(Name="B",Command="BMSpawn Blood")
To wrap it up, we need a way to clean up our mess and delete torches and blood that we've spawned. We already know how to determine what object we're pointing at, so we just call that object's Destroy() function. Add the following function to BattleMapPlayerInput:
exec function BMDeleteObject()Add bind a key to BMDeleteObject() in DefaultInput.ini:
{
local BattleMapTorch To;
local BattleMapBlood Bl;
if (WorldInfo.NetMode == NM_Standalone || WorldInfo.NetMode == NM_ListenServer)
{
switch(ParseObjectName(ObjectUnderMouse))
{
case "Torch":
foreach DynamicActors(class'BattleMapTorch', To)
if (To.Name == ObjectUnderMouse)
{
To.Destroy();
}
break;
case "Blood":
foreach DynamicActors(class'BattleMapBlood', Bl)
if (Bl.Name == ObjectUnderMouse)
{
Bl.Destroy();
}
break;
}
}
}
.Bindings=(Name="Delete",Command="BMDeleteObject")Now, you can litter the battlefield with torches, blood and explosions while snuffing out your player's precious light sources.
BattleMap mode source files