Using a blueprint callable c++ function from another class

Hello folks!

I feel like I’ve got a pretty simple problem, in a relatively complicated situation. Please don’t run away because of all the code down there! It’s just to be sure whoever can help me has all the info he needs. Here goes.

I am using three different actors here, one for the player, one for the enemy, and one for the weapon used by the enemy.

The weapon is placed in the hand of the enemy at the start of the game, and when the player is within range, he swings. I placed a notify at the moment of the animation when I want the weapon to be able to damage the player. As far as my tests go, the notify works.

I want to use the notify to change a bool variable in the weapon’s class. However, I am having trouble “getting” to the weapon from the “enemy” animation blueprint. Here are the relevant bits of code.

from enemy.h

UCLASS()
class GOLDENEGGREDUX_API AEnemy : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AEnemy(const FObjectInitializer& ObjectInitializer);

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MonsterProperties)
		UClass* BPMonsterWeapon;

	//The melee weapon instance
	AActor* MonsterWeapon;
};

from enemy.cpp

AEnemy::AEnemy(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
}

void AEnemy::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	//instantiate the weapon if the bp is selected
	if (BPMonsterWeapon)
	{
		MonsterWeapon = GetWorld()->SpawnActor<AAMeleeWeapon>(BPMonsterWeapon, FVector(), FRotator());

		if (MonsterWeapon)
		{
			const USkeletalMeshSocket *socket = Mesh->GetSocketByName("RightHandWeapon");
			socket->AttachActor(MonsterWeapon, Mesh);
		}
	}
}

from MeleeWeapon.h

UCLASS()
class GOLDENEGGREDUX_API AMeleeWeapon : public AActor
{
	GENERATED_BODY()
	
public:	
	AMeleeWeapon(const FObjectInitializer& ObjectInitializer);
	
	//We need a list of the things hit by the weapon during a swing, so we don't hit anything twice
	TArray<AActor*> ThingsHit;

	//Prevents damage from happening while we're not swinging
	bool isSwinging;

	AEnemy *WeaponHolder;

	//Box that's the collision box for hitting stuff
	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = MeleeWeapon)
		UBoxComponent* ProxBox;

	UFUNCTION(BlueprintNativeEvent, Category = "Collision")
		void Prox(AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);
		void Prox_Implementation(AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);

	UFUNCTION(BlueprintCallable, Category = Collision)
		void Swing();

};

from MeleeWeapon.cpp

AMeleeWeapon::AMeleeWeapon(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
	isSwinging = false;
	WeaponHolder = NULL;

	ProxBox = ObjectInitializer.CreateDefaultSubobject<UBoxComponent>(this, TEXT("ProxBox"));
	ProxBox->OnComponentBeginOverlap.AddDynamic(this, &AMeleeWeapon::Prox);

	ProxBox->AttachTo(RootComponent);
}

//Implementation of the hit
void AMeleeWeapon::Prox_Implementation(AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
{
	//Don't hit non root components on stuff
	if (OtherComp != OtherActor->GetRootComponent())
	{
		return;
	}

	AAvatar *player = Cast<AAvatar>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));

	//Don't hit things when not swinging, hit only the player, and don't hit the same thing twice
	if (isSwinging && OtherActor == player && !ThingsHit.Contains(OtherActor))
	{
		GEngine->AddOnScreenDebugMessage(0, 1.f, FColor::Green, "You got hit");

		ThingsHit.Add(OtherActor);
	}
}

//Function for swinging
void AMeleeWeapon::Swing()
{
	ThingsHit.Empty();
	isSwinging = true;
}

I tried to remove everything irrelevant to my problem, for clarity’s sake. BP_MonsterWeapon is a blueprint derived from the MeleeWeapon class. It can be chosen from the blueprint derived from the enemy.cpp class. Now, here is the blueprint for the enemy’s animation.

You can see down there my SwordSwung notify. I tested it by printing debug text, and it worked since everytime the enemy swung, text was print to the screen. I also know the collision between the sword and the player works well, since if I set the bool isSwinging to be always true, the debug text “You got hit” prints to the screen.

All I want now, is to be able to use the “Swing()” function from the relevant weapon class at every SwordSwung notify. I haven’t had to use a function so many “levels” from the one I’m using until now, so I’m not sure how I should go about this.

I don’t really want a walkthrough, I’d quite appreciate pointers as to what I should do.
Thank you! If you need to know anything else, fire away.

You need to replicate your variable status.

Since you don’t a walkthrough, to completely understand what’s going on, there’s some information here:

You might want to be careful on what you want to do. If you’re willing for the client to notify the server the isSwinging changed, you want a RPC function with these properties:

UFUNCTION(Server, Reliable, WithValidation)

If the server is aware and you want every single player out there to know this changed, use a Multicast:

UFUNCTION(NetMulticast, Reliable)

If you want that that just a specific client get information about this update, you probably want a:

UFUNCTION(Server, Reliable, WithValidation)

With the provided documentation, you probably will have the necessary information. If you’re stuck, ask again and I’ll try my best to help :slight_smile:
Oh, please, report back if you were successful - I’d love to hear back from you :slight_smile:

Cheers!

To be totally honest, I haven’t done anything with the Networking side of UE4 yet, I’m quite new to all this. I’ve only been working with a singleplayer game of sorts, with one actor used by the player, and the rest of the game being either NPCs or props.

I do plan on working on Networking, but I find a little surprising this specific situation couldn’t be solved without using a server-client system. Are servers and clients used even in singleplayer games in UE4 games? Or is variable replication a principle used outside of of multiplayer applications?

Change your weapon variable to the following:

UPROPERTY(BlueprintReadOnly, Transient)
class AMeleeWeapon* MonsterWeapon;

Transient isn’t required but I’m guessing it’s not something that you’d want saving.
Then in the blueprint you should be able to cast to your Enemy and do ‘Get Monster Weapon’, from which you can call the Swing function.

That did it! Thanks a lot!