(C++) How do I set a meshcomponent equal to that of a meshcomponent from another class?

Hi there,

I’m basing my script off of the default FirstPersonCharacter that appears when you start a new FPS project. I have a class called MasterWeapon that has a SkeletalMeshComponent “MasterWeapon_Skel”, a StaticMeshComponent “MasterWeapon_Static”, and a bunch of int/float values for firerate, spread, etc. These are all editable in the editor per object. In FPSDemoCharacter, I have declared an array of MasterWeapon*s called inventory. Whenever the Character hits an Actor of class MasterWeapon, it adds that object to the array w/ its values. That works fine. The trouble I have is when I call the EquipWeapon(inventory[slotnumberhere]) function, it crashes the editor immediately. Does anyone know why this is? I want to set FP_Gun to equal the MasterWeapon_Skel of the MasterWeapon stored in that particular slot. Code below:

MasterWeapon.h

#pragma once

#include "GameFramework/Actor.h"
#include "MasterWeapon.generated.h"

UCLASS()
class FPSDEMO_API AMasterWeapon : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AMasterWeapon();


	//NOT IN USE
	//AMasterWeapon(AMasterWeapon* myWeapon);

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	//virtual void Tick( float DeltaSeconds ) override;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Name)
		FName WeaponName;

	//UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = Mesh)
	//class USkeletalMesh* Gun_SkelMesh;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Mesh)
	class UStaticMeshComponent* Gun_StaticMeshComp;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Mesh)
	 class USkeletalMeshComponent* Gun_SkelMeshComp;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
		int spread;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
		float weaponFireRate;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
		int damage;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
		int currentAmmo;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
		int maxAmmo;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
		bool isAutoWeapon;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Sound)
	class USoundBase* FireSound;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Animation)
	class UAnimMontage* FireAnimation;
	
};

MasterWeapon.cpp
#include “FPSDemo.h”
#include “MasterWeapon.h”

// Sets default values
AMasterWeapon::AMasterWeapon()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;

	//FIGURE OUT HOW TO CREATE MESH AND CHOOSE IN EDITOR
	Gun_SkelMeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MasterWeapon_Skel"));

	Gun_SkelMeshComp->SetVisibility(false);

	Gun_StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MasterWeapon_Static"));

	Gun_StaticMeshComp->BodyInstance.SetCollisionProfileName("MasterWeapon_Collision");
}

//NOT IN USE
/*AMasterWeapon::AMasterWeapon(AMasterWeapon* myWeapon)
{
	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;

	//FIGURE OUT HOW TO CREATE MESH AND CHOOSE IN EDITOR
	Gun_SkelMeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MasterWeapon_Skel"));

	Gun_SkelMeshComp->SetVisibility(false);

	Gun_StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MasterWeapon_Static"));

	Gun_StaticMeshComp->BodyInstance.SetCollisionProfileName("MasterWeapon_Collision");

	int mySpread = myWeapon->spread;

	float myWeaponFireRate = myWeapon->weaponFireRate;

	int myDamage = myWeapon->damage;

	int myCurrentAmmo = myWeapon->currentAmmo;

	int myMaxAmmo = myWeapon->maxAmmo;

	bool myIsAutoWeapon = myWeapon->isAutoWeapon;
}
*/

// Called when the game starts or when spawned
void AMasterWeapon::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
/*void AMasterWeapon::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );

}*/

FPSDemoCharacter.h

#pragma once
#include "GameFramework/Character.h"
#include "FPSDemoCharacter.generated.h"

class UInputComponent;

UCLASS(config=Game)
class AFPSDemoCharacter : public ACharacter
{
	GENERATED_BODY()

		UPROPERTY(VisibleDefaultsOnly, Category = Collision)
	class UCapsuleComponent* CharCollisionComp;

		/** Pawn mesh: 1st person view (arms; seen only by self) */
		UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
	class USkeletalMeshComponent* Mesh1P;

	/** Gun mesh: 1st person view (seen only by self) */
	UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
	class USkeletalMeshComponent* FP_Gun;

	/** Location on gun mesh where projectiles should spawn. */
	UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
	class USceneComponent* FP_MuzzleLocation;

	/** First person camera */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class UCameraComponent* FirstPersonCameraComponent;

	UFUNCTION()
	void OnHit(UPrimitiveComponent* MyComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);

	void EquipWeapon(int weaponNum);

	virtual void Tick(float DeltaSeconds) override;

	//This ■■■■ is REALLY ■■■■■■■ ANNOYING EPIC!
	void Switch1();
	
	void Switch2();

	void Switch3();

	void Switch4();

	void Switch5();

	void Switch6();

	void Switch7();

	void Switch8();

	//============================================

public:
	AFPSDemoCharacter();

	virtual void BeginPlay();

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Gameplay)
		int occupiedSlots = 1;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
		int maxSlots;

	/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera)
		float BaseTurnRate;

	/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera)
		float BaseLookUpRate;

	/** Gun muzzle's offset from the characters location */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
		FVector GunOffset;

	/** Projectile class to spawn */
	UPROPERTY(EditDefaultsOnly, Category = Projectile)
		TSubclassOf<class AFPSDemoProjectile> ProjectileClass;

	/** Sound to play each time we fire */
	//Moving to Weapon class
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
	class USoundBase* FireSound;

	/** AnimMontage to play each time we fire */
	//Moving to Weapon class
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
	class UAnimMontage* FireAnimation;

	//Moving to Weapon class
	UPROPERTY(EditAnywhere, Category = Gameplay)
		float fireRate = 0.125f;

	UFUNCTION()
		void PickupWeapon(class AMasterWeapon* pWeapon);

	UFUNCTION(Category = Gameplay)
		void PlayerTakeDamage(float damageTaken);

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		TArray<AMasterWeapon*> inventory;

protected:

	

	//Switches between full auto and semi-auto.
	void ToggleAuto();

	void RespawnPlayer();

	void ToggleHUD();

	//Initial function called when fire button is pressed, checks whether or not auto-fire is enabled and calls the appropriate function.
	void DecideFire();

	//Fires full auto assuming firing mode is set to auto and fire button is held.
	void AutoFire();

	//Ceases firing upon release.
	void StopFire();


	/** Fires a projectile. */
	void OnFire();

	void KillPlayer();

	/** Handles moving forward/backward */
	void MoveForward(float Val);

	/** Handles stafing movement, left and right */
	void MoveRight(float Val);

	/**
	 * Called via input to turn at a given rate.
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void TurnAtRate(float Rate);

	/**
	 * Called via input to turn look up/down at a given rate.
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void LookUpAtRate(float Rate);

	struct TouchData
	{
		TouchData() { bIsPressed = false; Location = FVector::ZeroVector; }
		bool bIsPressed;
		ETouchIndex::Type FingerIndex;
		FVector Location;
		bool bMoved;
	};
	void BeginTouch(const ETouchIndex::Type FingerIndex, const FVector Location);
	void EndTouch(const ETouchIndex::Type FingerIndex, const FVector Location);
	void TouchUpdate(const ETouchIndex::Type FingerIndex, const FVector Location);
	TouchData	TouchItem;

protected:
	// APawn interface
	virtual void SetupPlayerInputComponent(UInputComponent* InputComponent) override;
	// End of APawn interface

	/*
	 * Configures input for touchscreen devices if there is a valid touch interface for doing so
	 *
	 * @param	InputComponent	The input component pointer to bind controls to
	 * @returns true if touch controls were enabled.
	 */
	bool EnableTouchscreenMovement(UInputComponent* InputComponent);

public:
	/** Returns Mesh1P subobject **/
	FORCEINLINE class USkeletalMeshComponent* GetMesh1P() const { return Mesh1P; }
	/** Returns FirstPersonCameraComponent subobject **/
	FORCEINLINE class UCameraComponent* GetFirstPersonCameraComponent() const { return FirstPersonCameraComponent; }

};

FPSDemoCharacter.cpp

#include "FPSDemo.h"
#include "FPSDemoCharacter.h"
#include "FPSDemoProjectile.h"
#include "FPSDemoHUD.h"
#include "FPSDemoGameMode.h"
#include "Animation/AnimInstance.h"
#include "GameFramework/InputSettings.h"
#include "Engine.h"
#include "MasterWeapon.h"

DEFINE_LOG_CATEGORY_STATIC(LogFPChar, Warning, All);

//////////////////////////////////////////////////////////////////////////
// AFPSDemoCharacter

bool isAuto = false;

bool firing = false;

float delay = 0.0f;

float ticker = 1.0f;

bool isDead = false;

bool HUDOn = true;

bool isWeaponAuto = false;


int playerHealth = 100;


float respawnTimer = 3.0f;



 AFPSDemoCharacter::AFPSDemoCharacter()
{

	inventory.SetNum(maxSlots);

	PrimaryActorTick.bCanEverTick = true;

	//CharCollisionComp = CreateDefaultSubobject<UCapsuleComponent>(TEXT("CapsuleComp"));

	// Set size for collision capsule
	GetCapsuleComponent()->InitCapsuleSize(55.f, 96.0f);

	GetCapsuleComponent()->OnComponentHit.AddDynamic(this, &AFPSDemoCharacter::OnHit);


	// set our turn rates for input
	BaseTurnRate = 45.f;
	BaseLookUpRate = 45.f;

	// Create a CameraComponent	
	FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
	FirstPersonCameraComponent->SetupAttachment(GetCapsuleComponent());
	FirstPersonCameraComponent->RelativeLocation = FVector(-39.56f, 1.75f, 64.f); // Position the camera
	FirstPersonCameraComponent->bUsePawnControlRotation = true;

	// Create a mesh component that will be used when being viewed from a '1st person' view (when controlling this pawn)
	Mesh1P = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("CharacterMesh1P"));

	Mesh1P->SetOwnerNoSee(false);

	Mesh1P->SetOnlyOwnerSee(true);
	Mesh1P->SetupAttachment(FirstPersonCameraComponent);
	Mesh1P->bCastDynamicShadow = false;
	Mesh1P->CastShadow = false;
	Mesh1P->RelativeRotation = FRotator(1.9f, -19.19f, 5.2f);
	Mesh1P->RelativeLocation = FVector(-0.5f, -4.4f, -155.7f);

	// Create a gun mesh component
	//CALL VIA EquipWeapon LATER
	FP_Gun = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FP_Gun"));

	FP_Gun->SetOwnerNoSee(false);

	FP_Gun->SetOnlyOwnerSee(true);			// only the owning player will see this mesh
	FP_Gun->bCastDynamicShadow = false;
	FP_Gun->CastShadow = false;
	//
	FP_Gun->SetVisibility(false);
	// FP_Gun->SetupAttachment(Mesh1P, TEXT("GripPoint"));

	FP_MuzzleLocation = CreateDefaultSubobject<USceneComponent>(TEXT("MuzzleLocation"));
	FP_MuzzleLocation->SetupAttachment(FP_Gun);
	FP_MuzzleLocation->SetRelativeLocation(FVector(0.2f, 48.4f, -10.6f));

	// Default offset from the character location for projectiles to spawn
	GunOffset = FVector(100.0f, 30.0f, 10.0f);

	if (HUDOn == false)
		ToggleHUD();



	// Note: The ProjectileClass and the skeletal mesh/anim blueprints for Mesh1P are set in the
	// derived blueprint asset named MyCharacter (to avoid direct content references in C++)
}


void AFPSDemoCharacter::BeginPlay()
{
	// Call the base class  
	Super::BeginPlay();
	FP_Gun->AttachToComponent(Mesh1P, FAttachmentTransformRules(EAttachmentRule::SnapToTarget, true), TEXT("GripPoint")); //Attach gun mesh component to Skeleton, doing it here because the skelton is not yet created in the constructor
	
}

//////////////////////////////////////////////////////////////////////////
// Input

void AFPSDemoCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
	// set up gameplay key bindings
	check(InputComponent);

	InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
	InputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

	InputComponent->BindAction("Toggle", IE_Pressed, this, &AFPSDemoCharacter::ToggleAuto);

	//THIS IS SUCH ■■■■■■■■
	InputComponent->BindAction("Switch1", IE_Pressed, this, &AFPSDemoCharacter::Switch1);

	InputComponent->BindAction("Switch2", IE_Pressed, this, &AFPSDemoCharacter::Switch2);

	InputComponent->BindAction("Switch3", IE_Pressed, this, &AFPSDemoCharacter::Switch3);

	InputComponent->BindAction("Switch4", IE_Pressed, this, &AFPSDemoCharacter::Switch4);

	InputComponent->BindAction("Switch5", IE_Pressed, this, &AFPSDemoCharacter::Switch5);

	InputComponent->BindAction("Switch6", IE_Pressed, this, &AFPSDemoCharacter::Switch6);

	InputComponent->BindAction("Switch7", IE_Pressed, this, &AFPSDemoCharacter::Switch7);

	InputComponent->BindAction("Switch8", IE_Pressed, this, &AFPSDemoCharacter::Switch8);

	//=========================================================================================

	//InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &AFPSDemoCharacter::TouchStarted);
	if (EnableTouchscreenMovement(InputComponent) == false)
	{
		InputComponent->BindAction("Fire", IE_Pressed, this, &AFPSDemoCharacter::DecideFire);
		InputComponent->BindAction("Fire", IE_Released, this, &AFPSDemoCharacter::StopFire);
	}

	InputComponent->BindAxis("MoveForward", this, &AFPSDemoCharacter::MoveForward);
	InputComponent->BindAxis("MoveRight", this, &AFPSDemoCharacter::MoveRight);

	// We have 2 versions of the rotation bindings to handle different kinds of devices differently
	// "turn" handles devices that provide an absolute delta, such as a mouse.
	// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
	InputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
	InputComponent->BindAxis("TurnRate", this, &AFPSDemoCharacter::TurnAtRate);
	InputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
	InputComponent->BindAxis("LookUpRate", this, &AFPSDemoCharacter::LookUpAtRate);
}

//VVV EDITOR CRASHES HERE VVV

void AFPSDemoCharacter::EquipWeapon(int weaponNum)
{

	if (inventory[weaponNum] != NULL)
	{
		//inventory[weaponNum];
		UE_LOG(LogTemp, Error, TEXT("BREAK?"));
		// Create a gun mesh component
		//FP_Gun->SetSkeletalMesh(inventory[weaponNum].Gun_SkelMesh);

		AMasterWeapon* activeWeapon = inventory[weaponNum];


		FP_Gun = activeWeapon->Gun_SkelMeshComp;

		FP_Gun->SetOwnerNoSee(false);

		FP_Gun->SetOnlyOwnerSee(true);			// only the owning player will see this mesh
		FP_Gun->bCastDynamicShadow = false;
		FP_Gun->CastShadow = false;
		FP_Gun->SetVisibility(true);
		// FP_Gun->SetupAttachment(Mesh1P, TEXT("GripPoint"));

		FP_MuzzleLocation = CreateDefaultSubobject<USceneComponent>(TEXT("MuzzleLocation"));
		FP_MuzzleLocation->SetupAttachment(FP_Gun);
		FP_MuzzleLocation->SetRelativeLocation(FVector(0.2f, 48.4f, -10.6f));

		FP_Gun->AttachToComponent(Mesh1P, FAttachmentTransformRules(EAttachmentRule::SnapToTarget, true), TEXT("GripPoint"));

		UE_LOG(LogTemp, Warning, TEXT("Weapon %i equipped."), weaponNum);
	}

}

void AFPSDemoCharacter::Switch1()
{
	EquipWeapon(1);
}

void AFPSDemoCharacter::Switch2()
{
	EquipWeapon(2);
}

void AFPSDemoCharacter::Switch3()
{
	EquipWeapon(3);
}

void AFPSDemoCharacter::Switch4()
{
	EquipWeapon(4);
}

void AFPSDemoCharacter::Switch5()
{
	EquipWeapon(5);
}

void AFPSDemoCharacter::Switch6()
{
	EquipWeapon(6);
}

void AFPSDemoCharacter::Switch7()
{
	EquipWeapon(7);
}

void AFPSDemoCharacter::Switch8()
{
	EquipWeapon(8);
}

void AFPSDemoCharacter::OnHit(UPrimitiveComponent* MyComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
	AMasterWeapon* MyWeapon = Cast<AMasterWeapon>(OtherActor);
	
	UE_LOG(LogTemp, Warning, TEXT("Hit"));
	// Only add impulse and destroy projectile if we hit a physics
	if ((OtherActor != NULL) && (OtherActor != this) && (OtherComp != NULL) && (!MyWeapon) && OtherComp->IsSimulatingPhysics())
	{
		OtherComp->AddImpulseAtLocation(GetVelocity() * 0.0f, GetActorLocation());
	}

	if (MyWeapon)
	{
		UE_LOG(LogTemp, Warning, TEXT("WeaponHit"));
		PickupWeapon(MyWeapon);
	}
}

void AFPSDemoCharacter::PickupWeapon(class AMasterWeapon* pWeapon)
{
	if (occupiedSlots < maxSlots)
	{
		UE_LOG(LogTemp, Warning, TEXT("Weapon picked up."));
		inventory.Add(pWeapon);
		occupiedSlots++;
	}
}

Isn’t the problem, that array index is zero based and you are reffering to it out of bounds? I mean Switch(1) should call EquipWeapon(0), right?

Did it work? :slight_smile:

Was a good catch, but unfortunately no. Even when I have an array of multiple objects and select one that isn’t zero it still crashes.

I would suggest you to debug the code and check the array, whether you are referencing to objects in bounds of the array. What is error message during crash? Usually the crashes are caused by invalid pointer. Are you able to point out the part of the code being executed before the crash?

I mean you should be able to pinpoint the exact place where code crashes. If it is immediatelly after entering the function, then the problem will be in the condition and really will be index referencing out of bounds value.

Fixed a few days ago. Thanks a bunch for the help though. There were several issues with the code, but this issue seems to have stemmed from the fact that I had tried to set the Subobject equal to a component of the weapon class. Fixed it by using SetSkeletalMesh() instead. Also created a USTRUCT to hold all of the weapon data rather than having it in the class itself.

Fixed it. Wasn’t the problem, but thanks anyways.