Download

Add additional component after instantiation of actor

I have a gun.
It model have a flashlight on it.
I want to “turn it on” (create and attach new USpotLightComponent to weapon, at specific position relative to weapon origin point and with specific rotation) if player select this weapon and press F.
How do so? Part “create and attach new USpotLightComponent to weapon” cause the main problem.

Do you have your code set up to load gun parts and install them when the weapons made? If not start there.

Here is flashlight code for a weapon and it will work on dedicated.

in YourCharacter.h file



#include "Components/SpotLightComponent.h"

public:
void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
USoundBase* WeaponlightSwitchSnd;

//weapon light
USpotLightComponent* WeaponsFlashlight;

UFUNCTION()
void ToggleWeaponlight();

UFUNCTION(Reliable, Server, WithValidation)
void Server_SetWeaponlight();
void Server_SetWeaponlight_Implementation();
bool Server_SetWeaponlight_Validate();

UFUNCTION()
void SetTheWeaponlight();

UPROPERTY(Replicated, ReplicatedUsing = OnRep_Weaponlight)
bool bShowWeaponlight;//pawns weapon flashlight

UFUNCTION()
void OnRep_Weaponlight();


In YourCharacter.cpp file



#include "Kismet/GameplayStatics.h"
#include "Net/UnrealNetwork.h"


AYourCharacter::AYourCharacter()
{
   bShowWeaponlight = false;//pawns weapon flashlight, set off

   WeaponsFlashlight = CreateDefaultSubobject<USpotLightComponent>(TEXT("WeaponsFlashlight"));
   WeaponsFlashlight->Mobility = EComponentMobility::Movable;
   WeaponsFlashlight->SetupAttachment(FP_Gun);
   WeaponsFlashlight->SetRelativeRotation(FRotator(0.0f, 90.0f, 0.0f));
   WeaponsFlashlight->SetVisibility(bShowWeaponlight);
   WeaponsFlashlight->UpdateColorAndBrightness();
}

void AYourCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
     Super::GetLifetimeReplicatedProps(OutLifetimeProps);

     //SKIP OWNER SEND TO EVERYONE ELSE
     DOREPLIFETIME_CONDITION(AYourCharacter, bShowWeaponlight, COND_SkipOwner);
}

//you will need to edit your DefaultInput.ini file from config folder to trigger the weapon light
//example > +ActionMappings=(ActionName="Wlight",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=F)
void AYourCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
     //Bind Flashlight events
     PlayerInputComponent->BindAction("Wlight", IE_Pressed, this, &AYourCharacter::ToggleWeaponlight);
}

/*ToggleWeaponlight()
toggles the Weapons flashlight on and off
*/
void AYourCharacter::ToggleWeaponlight()
{
     ENetMode NetMode = GetNetMode();

    SetTheWeaponlight();

    if (NetMode == NM_Client)
    {
        Server_SetWeaponlight();
    }
}

//set server to run this so info gets set on the client from the server
void AYourCharacter::Server_SetWeaponlight_Implementation()
{
      SetTheWeaponlight();
}

//validate sprint from client request so he can activate light
bool AYourCharacter::Server_SetWeaponlight_Validate()
{
    return true;
}

//seems that this runs the clients version now
void AYourCharacter::OnRep_Weaponlight()
{
    UE_LOG(LogCharacter, Log, TEXT("clients version run on Weapons Flashlight?"));
    this->WeaponsFlashlight->SetVisibility(bShowWeaponlight);
}

//runs on both client and server
void AYourCharacter::SetTheWeaponlight()
{
     UE_LOG(LogCharacter, Log, TEXT("AYourCharacter::SetTheWeaponlight();before = bShowWeaponlight = %s"), bShowWeaponlight ? TEXT("TRUE") : TEXT("FALSE"));
     bShowWeaponlight = !bShowWeaponlight;
     UE_LOG(LogCharacter, Log, TEXT("AYourCharacter::SetTheWeaponlight();after = bShowWeaponlight = %s"), bShowWeaponlight ? TEXT("TRUE") : TEXT("FALSE"));
     UE_LOG(LogCharacter, Log, TEXT(""));

     MakeNoise(1.0, this, this->GetActorLocation(), 200.0);
     UGameplayStatics::PlaySoundAtLocation(this, WeaponlightSwitchSnd, GetActorLocation());
     WeaponsFlashlight->SetVisibility(bShowWeaponlight);
}


This will get you a working weapon flashlight on any server you try.

You don’t have to spawn it at runtime. Just create the spotlight component in the constructor, and set it’s light intensity to 0.

Hmmm, this will create new spot light component, which would behave in same way as attached by default ways, using blueprint/hard code C++, right?!

Two more questions.
Is it possible, and if yes how to, destroy this component? So it wouldnt laying in memory as a dead weight when player switches from “gun with lighting” to another gun.
What if I created component, but after some time lost pointer to it (say, I use generic pointer type UActorComponent, or something bugged somewhere and function create two light components instead of one, etc.) is it possible to find it using some “find all attached components to actor by id/class/type/name/etc.”?

I know I can do it like this, but its…hacky.

You should write an inventory manager to manage the weapons when your switching between them. So you have a place to store them when not in use. Every time you switch a weapon you will need to reassemble its parts to a complete gun. You have a lot of work ahead of you to get what you are after fully working. I was writing something very similar to what you are after. I was at 8 to 10k lines of code and still not done…