Download

Attaching a mesh to a socket spawns the mesh in the middle of the character

I’m having trouble attaching my sword mesh with the righthand socket. Inside of Persona, I have the socket positioned at the character’s right hand, with the sword attached to the socket:

a11f5877b2e3598e09b27a5a7ca2126e40375a8e.jpeg

Now since it’s a preview, I have to manually attach it in C++ inside of PostInitializeComponents. The problem is that the socket attaches itself to the middle of the character, rather than the right hand like it should. Here is my code inside of my Monster.cpp:


void AMonster::PostInitializeComponents(){

	Super::PostInitializeComponents();

	if (BPMeleeWeapon){
		MeleeWeapon = GetWorld()->SpawnActor<AMeleeWeapons>(BPMeleeWeapon, FVector(), FRotator()); //spawn actor of type AMeleeWeapons and assign it to MeleeWeapon variable
		if (MeleeWeapon){
			const USkeletalMeshSocket *socket = Mesh->GetSocketByName("RightHandSocket"); //get reference to the socket on the monster
			socket->AttachActor(MeleeWeapon, Mesh);  //attach the weapon to the socket
		}
	}
}

AMeleeWeapons is the C++ class contains the weapon’s hit methods and stuff, and the BPMeleeWeapon is a property inside of the character blueprint which is set to BP_MeleeWeapons (derived blueprint class of AMeleeWeapons)

Here is how the sword appears on the character:

Capture.PNG

The name of the socket is 100% correct. Also, I’m importing the AMeleeWeapons class inside of the Monster.cpp so it recognizes it.

One thing. you’re not checking you actually getting a valid socket * from GetSocketByName. You really should check the pointer is valid before using it.

Not that it fixes your issue, but I was cruising the forums and saw that :slight_smile: sorry :wink:

I added an if statement to check and a log to say it did and did in fact execute. So I guess that’s not the problem.

A C++ newbie here. Have you tried getting the socket location, and then set the melee weapon relative location to the socket location after you retrieve the const melee weapon pointer data?

Just tried it:


MeleeWeapon->SetActorLocation(socket->GetSocketLocation(GetMesh()));

Didn’t change a thing. Also, one other thing to notice, when I drag my Monster_BP into the viewport, the sword doesn’t even appear. It doesn’t appear when I actually go in-game. It only appears in the blueprint editor viewport and it appears in the wrong place. All the code is pretty much the same, idk if this is a UE4 problem or if I’m doing something wrong.

Have you replaced SpawnActor with a static ConstructorHelpers::FObjectFinder<FMeleeWeapon>(), since your FMeleeWeapon is technically a blueprint class?

Supposing MeleeWeapon is a MeshComponent and you have already set up correctly the sockets for the pawn mesh, you should use



MeleeWeapon->AttachTo(MyPawn->GetMesh, MYSocketName, EAttachLocation::SnapTarget)



Look at the EAttachLocation definition in case you need other kind of alignment.

Is that a sword in your pocket or are you just happy to see me?

I think it’s just a long, stabby thingy.

MeleeWeapon has no method called AttachTo that I can use. MeleeWeapon is defined in Monster.h as AActor* MeleeWeapon. When I assign MeleeWeapon a value, I’m assigning it from the class AMeleeWeapons who’s header file is:


UCLASS()
class TUTORIALPLACE_API AMeleeWeapons : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AMeleeWeapons();
	AMeleeWeapons(const FObjectInitializer& ObjectInitializer);

	// 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 = WeaponProperties)
		float AttackDamage;
}

Regardless, I tried using the following line:


MeleeWeapon->AttachRootComponentTo(GetMesh(), "RightHandSocket", EAttachLocation::SnapToTarget);

Still same result.

You mean the skeletal mesh component of AMeleeWeapon can’t be attached?

// StaticMeshComponent to represent the pickup in the level
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = Pickup)
	UStaticMeshComponent* PickupMesh;

// SkeletalMeshComponent to represent the pickup in the level
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = Pickup)
	USkeletalMeshComponent* PickupMeshSkeletal;

I have no idea what you just posted lol. What I meant was that the sword ends up in the same position, regardless of the last couple of lines I have tried earlier.

Also, here is the Monster.h header file:


UCLASS()
class TUTORIALPLACE_API AMonster : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AMonster();
	AMonster(const FObjectInitializer& ObjectInitializer);
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) override;

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

	AActor* MeleeWeapon;

	virtual void PostInitializeComponents() override;
	
	
};

I would try to rule out the AMeleeWeapon actor by creating a static mesh component directly on the character and trying to attach that to the socket. If the same behaviour occurs, then the issue is likely to be on the character class, otherwise look at the weapon class.

Also, since the preview is using the reference pose, does the attachment preview also work when animated? It could be a bone issue.

-Camille

I added a StaticMesh component to the character’s blueprint, and set the Mesh to the sword mesh (I can’t set it to the MeleeWeapons_BP). The problem is that ParentSocket is disabled, I can’t type anything inside of it:

Capture.PNG

About the preview, I did try it while it was animated, here is how it appears:

Capture.PNG

Yeah sorry I was just affirming what isaacvega was saying when he mentioned MeshComponent, and saw that you didn’t have one in your class so I wrote down the code in case you need it. You’re doing a direct attach with the actor object. I’m pretty sure cmartel is better with words than I am.

You can always do it in blueprint like this
aae294f9fd06238f8462e07e56609149c02c6807.png

MeleeWeapons is a AActor object. The class AMeleeWeapons extends from AActor.

Ok, I tried that and it works, this is how I did it:

It attaches the Sword mesh to the correct socket. Now how can I attach the MeleeWeapons_BP using the same way?

This is what I have so far, which is the reference to the object. How can I get the mesh component?

Capture.PNG

Yeah this is true. Although your Sword component is a Static Mesh Component that you created in blueprint. If you want to access the sockets on that mesh in code then move the creation of that static mesh component into code and access it there, or use the blueprint diagram I just posted to attach the sword to the base mesh of the character. If you grab a reference to your weapon actor object and get it’s static mesh you should be able to attach it to the character.

Here is a pic of spawning a weapon from the character itself from blueprint in case you want to add multiple weapons.

074362ff75a819b49f7a5d9992c66db349f08e40.png

That’s strange. If your meleeweapon’s root component is properly set to the mesh, it should behave the exact same way as attaching a component. This is what we’re doing for equipping items and it’s not that different.



void AGlimpseCharacter::AttachPickupToHand( class AGlimpsePickup* Pickup )
{
	if( EquipSocketName != NAME_None )
	{
		if( GetMesh()->DoesSocketExist(EquipSocketName) )
		{
			Pickup->AttachRootComponentTo(GetMesh(), EquipSocketName);

			FRotator HoldRotation = Pickup->GetHoldRotation();
			FVector HoldLocation = Pickup->GetHoldLocation();
			Pickup->GetRootComponent()->SetRelativeLocationAndRotation( HoldLocation, HoldRotation );
			Pickup->GetRootComponent()->SetVisibility( true );
		}
		else
		{
			UE_LOG(LogGlimpse, Warning, TEXT("AttachPickupToHand: Cannot find socket %s on mesh %s"), *EquipSocketName.ToString(), *GetMesh()->SkeletalMesh->GetName());
		}
	}
}


The only extra thing is the GetHoldRotation/GetHoldLocation methods, which specify an optional static mesh socket that can be used to change the location at which the item is held. By default, they return zero, which would be the equivalent of doing an attach with SnapTo attach type.

Perhaps try stepping through the AttachRootComponentTo method with the debugger, see if there’s anything failing?

-Camille

THAT was the problem. I hadn’t set the Mesh to be the root component. I thought that it was automatically set as the root component and that I didn’t have to manually say “RootComponent = Mesh” inside of the AMeleeWeapons.cpp constructor. It’s working now that the line is in there.

Thanks a lot, I really appreciate it. And the line that I’m currently using is:


MeleeWeapon->AttachRootComponentTo(GetMesh(), "RightHandSocket", EAttachLocation::SnapToTarget);