softwaresailor
softwaresailor

Reputation: 11

Unreal Engine 4 C++: Unable to assign subclass instance to a TSubclassOf variable

As stated in the title, I'm currently working in C++ on a project of mine and Im unable to assign an instance of a class to a variable in another class that is expecting a subclass of the instances parent class.

In more detail I have 3 classes right now: USpell, UProjectilePrimarySpell, and UPreparedSpell.

UProjectilePrimarySpell inherits from USpell which is an abstract class.

UCLASS(Abstract)
class SPELLCRAFTER_API USpell : public UObject
{
    GENERATED_BODY()

public:

    USpell();

    USpell(FString element);

    UPROPERTY()
    FString element;

    UFUNCTION()
    virtual void castSpell(FVector targetPoint, FRotator targetRotation);

    UFUNCTION()
    virtual void weaveSpell();
};

UCLASS()
class SPELLCRAFTER_API UProjectilePrimarySpell : public USpell
{
    GENERATED_BODY()

    UPROPERTY()
    float projectileSpeed;

    UPROPERTY()
    float projectileScale;

    UPROPERTY()
    bool isBurst;

    UPROPERTY()
    int32 burstCount;

    UPROPERTY()
    float burstDelay;

    UPROPERTY()
    bool isShotgun;

    UPROPERTY()
    int32 shotgunPelletCount;

    UPROPERTY()
    float castDelay;

    UPROPERTY()
    float cooldown;

    UPROPERTY()
    float despawnTime;

    UPROPERTY()
    int32 damage;

    UPROPERTY()
    bool isAffectedByGravity;

public:

    UProjectilePrimarySpell();

    void castSpell(FVector targetLocation, FRotator targetRotation);
};

UPreparedSpell has a field called PrimarySpell which is of type TSubclassOf;

UCLASS()
class SPELLCRAFTER_API UPreparedSpell : public UObject
{
    GENERATED_BODY()

public:

    UPreparedSpell();

    UPreparedSpell(TSubclassOf<USpell> primarySpell);

    UPreparedSpell(TSubclassOf<USpell> primarySpell, TArray<TSubclassOf<USpell>> secondarySpells);

    UPROPERTY()
    TSubclassOf<USpell> PrimarySpell;

    UPROPERTY()
    TArray<TSubclassOf<USpell>> SecondarySpells;

    UFUNCTION()
    void CastPreparedSpell(FVector targetPoint, FRotator targetRotation);
};

In a separate class which I have some code running when the player performs some input. In there I am creating an instance of the UProjectilePrimarySpell class and an instance of the UPreparedSpell both using the NewObject function.

I then attempt to assign the UProjectilePrimarySpell instance to the field in the UPreparedSpell however I'm getting an error saying

no operator "=" matches these operands. Operand types are TSubclassOf = UProjectilePrimarySpell

Where I assign PrimarySpell to *baseSpell;

void ASpellcrafterCharacter::OnFire()
{

    const FRotator SpawnRotation = GetControlRotation();
    // MuzzleOffset is in camera space, so transform it to world space before offsetting from the character location to find the final muzzle position
    const FVector SpawnLocation = ((FP_MuzzleLocation != nullptr) ? FP_MuzzleLocation->GetComponentLocation() : GetActorLocation()) + SpawnRotation.RotateVector(GunOffset);

    UProjectilePrimarySpell *baseSpell = NewObject<UProjectilePrimarySpell>();

    UPreparedSpell* preparedSpell = NewObject<UPreparedSpell>();

    preparedSpell->PrimarySpell = *baseSpell;
    preparedSpells.Add(preparedSpell);

    preparedSpells[0]->CastPreparedSpell(SpawnLocation, SpawnRotation);

}

I'm fairly greenhorn when it comes to C++ and Unreal engine, I understand the basics of pointers and I've got years of experience in Java so I understand how inheritance should work. I'm confused as to why this isnt a valid setup.

Upvotes: 1

Views: 11078

Answers (1)

goose_lake
goose_lake

Reputation: 1438

TSubclassOf<> is a templated type that can be thought of as simply a UClass*.

Variables of this type are meant to be assigned an instance of a UClass, to denote different types of objects. For example, if you have child classes of USpell called UFireSpell and UHealSpell, and let’s say they can be equipped to a slot on a weapon, you can use a TSubclassOf<USpell> EquippedSpell variable, and assign the slot to use heal spells (not a specific heal spell, but in general the type of spell used for healing) by doing something like EquippedSpell = UHealSpell::Static_Class().

I hope this makes it clear that an instance of a UClass is different from an instance of a UObject, which is what you’re doing by creating a new object. If you create some objects of C++ class UPreparedSpell, they are UPreparedSpell* type. Their UClass (different from C++ class) can be found by using their GetClass() function, which returns a pointer to UClass.

preparedSpell->PrimarySpell = *baseSpell doesn’t make sense, as you should never dereference a UObject*, they are non copyable.

For most Unreal programming, it’s quite important to understand what a UClass is. It’s not really the same as a C++ class, but rather a prototype, similar to what JavaScript objects use, if you’re familiar with that. If you’re not familiar with the term, search for “prototype based object oriented programming” if you want to learn more.

Upvotes: 2

Related Questions