Exposing multi-cast delegates to Blueprint

Multi-cast delegates are a great way to broadcast an event to multiple objects who listen or subscribe to the event in question. They are particularly invaluable if you have a C++ module that generates events that potentially arbitrary Actors might want to be notified about. This recipe shows you how to create a multi-cast delegate in C++ that can notify a group of other Actors during runtime.

How to do it…

  1. Create a new StaticMeshActor class called King. Add the following to the class header:
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnKingDeathSignature, AKing*, DeadKing);
  2. Add a new UFUNCTION to the class:
    UFUNCTION(BlueprintCallable, Category = King)
    void Die();
  3. Add an instance of our multicast delegate to the class:
    UPROPERTY(BlueprintAssignable)
    FOnKingDeathSignature OnKingDeath;
  4. Add our mesh initialization to the constructor:
    auto MeshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("StaticMesh'/Engine/BasicShapes/Cone.Cone'"));
    if (MeshAsset.Object != nullptr)
    {
      GetStaticMeshComponent()->SetStaticMesh(MeshAsset.Object);
      GetStaticMeshComponent()->bGenerateOverlapEvents = true;
    }
    GetStaticMeshComponent()->SetMobility(EComponentMobility::Movable);
  5. Implement the Die function:
    void AKing::Die()
    {
      OnKingDeath.Broadcast(this);
    }
  6. Create a new class called Peasant, also based on StaticMeshActor.
  7. Declare a default constructor in the class:
    APeasant();
  8. Declare the following function:
    UFUNCTION(BlueprintCallable, category = Peasant)
    void Flee(AKing* DeadKing);
  9. Implement the constructor:
    auto MeshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("StaticMesh'/Engine/BasicShapes/Cube.Cube'"));
    if (MeshAsset.Object != nullptr)
    {
      GetStaticMeshComponent()->SetStaticMesh(MeshAsset.Object);
      GetStaticMeshComponent()->bGenerateOverlapEvents = true;
    }
    GetStaticMeshComponent()->SetMobility(EComponentMobility::Movable);
  10. Implement the function in the .cpp file:
    void APeasant::Flee(AKing* DeadKing)
    {
      GEngine->AddOnScreenDebugMessage(-1, 2, FColor::Red, TEXT("Waily Waily!"));
      FVector FleeVector = GetActorLocation() – DeadKing->GetActorLocation();
      FleeVector.Normalize();
      FleeVector *= 500;
      SetActorLocation(GetActorLocation() + FleeVector);
    }
  11. Open Blueprint and create a Blueprint class based on APeasant called BPPeasant.
  12. Within the blueprint, click and drag away from the white (execution) pin of your BeginPlay node. Type get all, and you should see Get All Actors Of Class. Select the node to place it in your graph.
    How to do it…
  13. Set the value of the purple (class) node to King. You can type king in the search bar to make locating the class in the list easier.
    How to do it…
  14. Drag from the blue grid (object array) node out into empty space and place a get node.
    How to do it…
  15. Drag away from the blue output pin of the get node, and place a Not Equal (object) node.
    How to do it…
  16. Connect the red (bool) pin of the Not Equal node to a Branch node, and wire the execution pin of Branch to our Get All Actors Of Class node.
    How to do it…
  17. Connect the True pin of the branch to the Bind Event to OnKing Death node.
    How to do it…

    Note

    Note that you will probably have to untick Context Sensitive in the context menu for the Bind Event node to be visible.

  18. Drag out the red pin on the Bind Event node, and select Add Custom Event… in the context menu which appears after you release your left mouse button.
    How to do it…
  19. Give your event a name, then connect the white execution pin to a new node named Flee.
    How to do it…
  20. Verify that your Blueprint looks like the following figure:
    How to do it…
  21. Drag a copy of your King class into the level, then add a few BPPeasant instances around it in a circle.
  22. Open the level Blueprint. Inside it, drag away from BeginPlay, and add a Delay node. Set the delay to 5 seconds.
    How to do it…
  23. With your King instance selected in the level, right-click in the graph editor for the Level Blueprint.
  24. Select Call function on King 1, and look in the King category for a function called Die.
    How to do it…
  25. Select Die, then connect its execution pin to the output execution pin from the delay.
    How to do it…
  26. When you play your level, you should see that the king dies after 5 seconds, and the peasants all wail and flee directly away from the king.
    How to do it…
    How to do it…

How it works…

  1. We create a new actor (based on StaticMeshActor for convenience, as it saves us having to declare or create a Static Mesh component for the Actor visual representation).
  2. We declare a dynamic multicast delegate using the DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam macro. Dynamic multicast delegates allow an arbitrary number of objects to subscribe (listen) and unsubscribe (stop listening) so that they will be notified when the delegate is broadcast.
  3. The macro takes a number of arguments—the type name of the new delegate signature being created, the type of the signature's parameter, then the name of the signature's parameter.
  4. We also add a function to King that will allow us to tell it to die. Because we want to expose the function to Blueprints for prototyping, we mark it as BlueprintCallable.
  5. The DECLARE_DYNAMIC_MULTICAST_DELEGATE macro that we used earlier only declared a type; it didn't declare an instance of the delegate, so we do that now, referencing the type name that we provided earlier when invoking the macro.
  6. Dynamic multicast delegates can be marked BlueprintAssignable in their UPROPERTY declaration. This indicates to Unreal that the Blueprint system can dynamically assign events to the delegate that will be called when the delegate's Broadcast function is called.
  7. As always, we assign a simple mesh to our King so that it has a visual representation in the game scene.
  8. Within the Die function, we call Broadcast on our own delegate. We specified that the delegate would have a parameter that is a pointer to the king which died, so we pass this pointer as a parameter to the broadcast function.

    Note

    If you want the king to be destroyed, rather than play an animation or other effect when it dies, you would need to change the delegate's declaration and pass in a different type. For example, you could use FVector, and simply pass in the location of the dead king directly so that the peasants could still flee appropriately.

    Without this, you potentially could have a situation where the King pointer is valid when Broadcast is called, but the call to Actor::Destroy() invalidates it before your bound functions are executed.

  9. Within our next StaticMeshActor subclass, called Peasant, we initialize the static mesh component as usual using, a different shape to the one that we used for the King.
  10. Inside the implementation of the peasant's Flee function, we simulate the peasants playing sound by printing a message on the screen.
  11. We then calculate a vector to make the peasants flee by first finding a vector from the dead king to this peasant's location.
  12. We normalize the vector to retrieve a unit vector (with a length of 1) pointing in the same direction.
  13. Scaling the normalized vector and adding it to our current location calculates a position at a fixed distance, in the exact direction for the peasant to be fleeing directly away from the dead king.
  14. SetActorLocation is then used to actually teleport the peasants to that location.

    Note

    If you used a Character with an AI controller, you could have the Peasant pathfind to the target location rather than teleporting. Alternatively, you could use a Lerp function invoked during the peasant's Tick to make them slide smoothly rather than jump directly to the location.

See also

  • Look at Chapter 4, Actors and Components, for more extended discussions about Actors and Components. Chapter 5, Handling Events and Delegates, discusses events such as NotifyActorOverlap.
..................Content has been hidden....................

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