Quantcast
Viewing all articles
Browse latest Browse all 18

D&D BattleMap Using the UDK - Special Effects

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:

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;
DefaultProperties
{
 DrawScale=1.000000

 Begin Object Name=ParticleSystemComponent0
  Template=ParticleSystem'P_WP_ShockRifle_Explo'
 End Object
}
BattleMapEmitterEffectLightning.uc

class BattleMapEmitterEffectLightning extends BattleMapEmitterEffect;
DefaultProperties
{
 DrawScale=2.000000
 Rotation=(Pitch=16384,Yaw=0,Roll=0)

 Begin Object Name=ParticleSystemComponent0
  Template=ParticleSystem'PS_Scorpion_Gun_Impact'
 End Object
}
BattleMapEmitterEffectNuke.uc

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)
{
 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;
  }
 }
}
DefaultInput.ini

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":
    Spawn(class'BattleMapBlood',Outer,,MouseOrigin );
    break;
And bind a key to it in DefaultInput.ini:

-Bindings=(Name="B",Command="GBA_ToggleSpeaking")
.Bindings=(Name="B",Command="BMSpawn Blood")
BattleMapPlayerInput.uc

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()
{
 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;
  }
 }
}
Add bind a key to BMDeleteObject() in DefaultInput.ini:
.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

Viewing all articles
Browse latest Browse all 18

Trending Articles