Spell class actor

The Spell class will ultimately do damage to all the monsters. Towards that end, we need to contain both a particle system and a bounding box inside the Spell class actor. When a Spell class is cast by the avatar, the Spell object will be instantiated into the level and start Tick() functioning. On every Tick() of the Spell object, any monster contained inside the spell's bounding volume will be affected by that Spell.

The Spell class should look something like the following code:

UCLASS()
class GOLDENEGG_API ASpell : public AActor
{
  GENERATED_UCLASS_BODY()

  // box defining volume of damage
  UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category =  Spell)
  TSubobjectPtr<UBoxComponent> ProxBox;

  // the particle visualization of the spell
  UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category =  Spell)
  TSubobjectPtr<UParticleSystemComponent> Particles;

  // How much damage the spell does per second
  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Spell)
  float DamagePerSecond;

  // How long the spell lasts
  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Spell)
  float Duration;

  // Length of time the spell has been alive in the level
  float TimeAlive;

  // The original caster of the spell (so player doesn't
  // hit self)
  AActor* Caster;

  // Parents this spell to a caster actor
  void SetCaster( AActor* caster );

  // Runs each frame. override the Tick function to deal damage 
  // to anything in ProxBox each frame.
  virtual void Tick( float DeltaSeconds ) override;
};

There are only three functions we need to worry about implementing, namely the ASpell::ASpell() constructor, the ASpell::SetCaster() function, and the ASpell::Tick() function.

Open the Spell.cpp file. Add a line to include the Monster.h file, so we can access the definition of Monster objects inside the Spell.cpp file, as shown in the following line of code:

#include "Monster.h"

First, the constructor, which sets up the spell and initializes all components is shown in the following code:

ASpell::ASpell(const class FPostConstructInitializeProperties&  PCIP) : Super(PCIP)
{
  ProxBox = PCIP.CreateDefaultSubobject<UBoxComponent>(this,  TEXT("ProxBox"));
  Particles = PCIP.CreateDefaultSubobject<UParticleSystemComponent>(this,  TEXT("ParticleSystem"));

  // The Particles are the root component, and the ProxBox
  // is a child of the Particle system.
  // If it were the other way around, scaling the ProxBox
  // would also scale the Particles, which we don't want
  RootComponent = Particles;
  ProxBox->AttachTo( RootComponent );

  Duration = 3;
  DamagePerSecond = 1;
  TimeAlive = 0;

  PrimaryActorTick.bCanEverTick = true;//required for spells to 
  // tick!
}

Of particular importance is the last line here, PrimaryActorTick.bCanEverTick = true. If you don't set that, your Spell objects won't ever have Tick() called.

Next, we have the SetCaster() method. This is called so that the person who casts the spell is known to the Spell object. We can ensure that the caster can't hurt himself with his own spells by using the following code:

void ASpell::SetCaster( AActor *caster )
{
  Caster = caster;
  AttachRootComponentTo( caster->GetRootComponent() );
}

Finally, we have the ASpell::Tick() method, which actually deals damage to all contained actors, as shown in the following code:

void ASpell::Tick( float DeltaSeconds )
{
  Super::Tick( DeltaSeconds );

  // search the proxbox for all actors in the volume.
  TArray<AActor*> actors;
  ProxBox->GetOverlappingActors( actors );

  // damage each actor the box overlaps
  for( int c = 0; c < actors.Num(); c++ )
  {
    // don't damage the spell caster
    if( actors[ c ] != Caster )
    {
      // Only apply the damage if the box is overlapping
      // the actors ROOT component.
      // This way damage doesn't get applied for simply 
      // overlapping the SightSphere of a monster
      AMonster *monster = Cast<AMonster>( actors[c] );

      if( monster && ProxBox->IsOverlappingComponent( monster- >CapsuleComponent ) )
      {
        monster->TakeDamage( DamagePerSecond*DeltaSeconds,  FDamageEvent(), 0, this );
      }

      // to damage other class types, try a checked cast 
      // here..
    }
  }

  TimeAlive += DeltaSeconds;
  if( TimeAlive > Duration )
  {
    Destroy();
  }
}

The ASpell::Tick() function does a number of things, as follows:

  • Gets all actors overlapping ProxBox. Any actor that is not the caster gets damaged if the component overlapped is the root component of that object. The reason we have to check for overlapping with the root component is because if we don't, the spell might overlap the monster's SightSphere, which means we will get hits from very far away, which we don't want.
  • Notices that if we had another class of thing that should get damaged, we would have to attempt a cast to each object type specifically. Each class type might have a different type of bounding volume that should be collided with, other types might not even have CapsuleComponent (they might have ProxBox or ProxSphere).
  • Increases the amount of time the spell has been alive for. If the spell exceeds the duration it is allotted to be cast for, it is removed from the level.

Now, let's focus on how the player can acquire spells, by creating an individual PickupItem for each spell object that the player can pick up.

Blueprinting our spells

Compile and run your C++ project with the Spell class that we just added. We need to create blueprints for each of the spells we want to be able to cast. In the Class Viewer tab, start to type Spell, and you should see your Spell class appear. Right-click on Spell, and create a blueprint called BP_Spell_Blizzard, and then double-click to open it, as shown in the following screenshot:

Blueprinting our spells

Inside the spell's properties, choose the P_Blizzard spell for the particle emitter, as shown in the following screenshot:

Blueprinting our spells

Scroll down until you reach the Spell category, and update the Damage Per Second and Duration parameters to values you like. Here, the blizzard spell will last 3.0 seconds, and do 16.0 damage total per second. After three seconds, the blizzard will disappear.

Blueprinting our spells

After you have configured the Default properties, switch over to the Components tab to make some further modifications. Click on and change the shape of ProxBox so that its shape makes sense. The box should wrap the most intense part of the particle system, but don't get carried away in expanding its size. The ProxBox object shouldn't be too big, because then your blizzard spell would affect things that aren't even being touched by the blizzard. As shown in the following screenshot, a couple of outliers are ok.

Blueprinting our spells

Your blizzard spell is now blueprinted and ready to be used by the player.

Picking up spells

Recall that we previously programmed our inventory to display the number of pickup items the player has when the user presses I. We want to do more than that, however.

Picking up spells

Items displayed when the user presses I

To allow the player to pick up spells, we'll modify the PickupItem class to include a slot for a blueprint of the spell the player casts by using the following code:

// inside class APickupItem:
// If this item casts a spell when used, set it here
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Item)
UClass* Spell;

Once you've added the UClass* Spell property to the APickupItem class, recompile and rerun your C++ project. Now, you can proceed to make blueprints of PickupItem instances for your Spell objects.

Creating blueprints for PickupItems that cast spells

Create a PickupItem blueprint called BP_Pickup_Spell_Blizzard. Double-click on it to edit its properties, as shown in the following screenshot:

Creating blueprints for PickupItems that cast spells

I set the blizzard item's pickup properties as follows:

The name of the item is Blizzard Spell, and five are in each package. I took a screenshot of the blizzard particle system and imported it to the project, so the Icon is selected as that image. Under spell, I selected BP_Spell_Blizzard as the name of the spell to be cast (not BP_Pickup_Spell_Blizzard), as shown in the following screenshot:

Creating blueprints for PickupItems that cast spells

I selected a blue sphere for the Mesh class of the PickupItem class. For Icon, I took a screenshot of the blizzard spell in the particle viewer preview, saved it to disk, and imported that image to the project (see the images folder in the Content Browser tab of the sample project).

Creating blueprints for PickupItems that cast spells

Place a few of these PickupItem in your level. If we pick them up, we will have some blizzard spells in our inventory.

Creating blueprints for PickupItems that cast spells

Left: Blizzard spell pickup items in game world. Right: Blizzard spell pickup item in inventory.

Now we need to activate the blizzard. Since we already attached the left mouse click in Chapter 10, Inventory System and Pickup Items to dragging the icons around, let's attach the right mouse click to casting the spell.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.237.123