Respawn an Actor?

Lets say I pick up a sword on the ground called ASword. To remove it from the world I could call Destroy on ASword but that would prevent me from being able to re-spawn it into the world. I tried to call RemoveActor from UWorld but that did nothing.

What is the proper way to “Re-Spawn” an actor?

Below is my current implementation:
This is how I add an item to my inventory, It gets called when NotifyActorBeginOverlap() is called by the item (a sword in this case). I first check to make sure it was successfully added to the inventory before destroying/removing the item.

bool SEtherItemGrid::AddItem(ABaseItem* itemToAdd)
{
	UWorld* theWorld = itemToAdd->();
	bool itemWasAdded = false;
	int32 firstEmptySlotIndex = -1;

	if (itemToAdd != NULL)
	{
		//Get the index of the first available slot.
		firstEmptySlotIndex = this->FindFirstAvailableSlot();

		if (firstEmptySlotIndex >= 0 && firstEmptySlotIndex < this->GetNumSlots())
		{
			//Add the item to the empty slot we just found.
			itemWasAdded = this->AddItem(firstEmptySlotIndex, itemToAdd);

			//Check to see if the item was added successfully.
			if (itemWasAdded == true)
			{
				//Remove item from the world since it was successfully picked up.
				itemToAdd->Destroy();
			}
		}
	}

	return itemWasAdded;
}

In my inventory, I have the option to right click an item and drop it. In other words this will remove the item from the inventory and then attempt to re-spawn it into the world. Here is what the code looks like for that:

void AStandardCharacter::DropItemFromInventory(ABaseItem* item)
{
	UWorld* theWorld = this->();
	ABaseItem* removedItem = NULL;
	FRotator spawnRotation;
	FVector spawnLocation;
	
	//Remove the item from the inventory.
	if (item != NULL && myInventory.IsValid() == true)
	{
		removedItem = myInventory->RemoveItem(item);

		//Take the removed item and re-spawn it into the world.
		if (removedItem != NULL)
		{
			if (theWorld != NULL && itemToDrop != NULL)
			{
				spawnRotation = this->GetActorRotation();
				spawnLocation = this->GetActorLocation();

				//Spawn the item at the spawnLocation.
				theWorld->SpawnActor<ABaseItem>(itemToDrop->GetClass(), 
												spawnLocation, 
												spawnRotation);
			}
		}
	}
}

When Attempting to drop the item, nothing happens and I get a warning saying “SpawnActor failed because the spawned actor IsPendingKill”.

So what Is the proper way to do this?

Make a Spawner that will spawn the object once it picked up and place it insted of placing ASword it self. you can make it universal by making UClass varable which you can set in details tab once you place it on the level.

Or keep ASword instance as inventory item in character, just deactivate the visual components make it spawn it self in spot it been picked up (so you need to keep that information).

Can you provide an example of this or some reference? I get the idea but those two sentences alone are not enough for me to go on.

Currently I’m Destroying the item on pickup and then attempting to use world->spawn actor but I’m getting an error that tells me “IsPendingKill”

Can you show me the that bad code? Tell me where it is located too

In a project I’m working on, I have my character pick up a sword and then pick up a second, but on a key press he can switch weapons from the currently equipped weapon to the secondary weapon. Since I want to bring the weapon back after I’ve switched it, I don’t want to destroy it, just make it invisible. So I use SetActorHiddenInGame(true) from within the weapon class to hide it, and SetActorHiddenInGame(false) to bring it back. Both weapons must be stored as separate variables and must exist in the world in some class (the character class is perfectly fine) just have in your character’s .h file something like AWeapon* weapon1; AWeapon* weapon2; etc. or make blueprints of them and store UClass pointers. You can call Destroy() and spawn new ones each time, but when you do this, you’re not actually brining the weapon back, but creating a new one altogether. So if you had any info stored in that weapon it would spawn with default values for everything, u less you stored those values somewhere like in the character and set them in the new weapon class upon spawning. If you wanna spawn new actors rather than toggle their visibility, use SpawnActor.

I’m working on what you suggested, If it works I will accept your answer.

Please provide a code example of this if you want me to accept this as an answer. I did what you suggested (along with disabling actor collision) and it works for actors(items) that are NOT simulating physics. If I try to “drop” the simulated physics actor, it is invisible.

I thought that perhaps it was re-appearing under the floor but it wasn’t, or it was re-appearing somewhere else on the map but that does not seem to be the case either.

Update: Above is the requested code, I kind of gave up on trying to do that after the Destroy work around worked perfectly for me.

Edited my original answer to include the code.

Literally this is all I do:
PrimaryWeapon->SetActorHiddenInGame(true);
SecondaryWeapon->SetActorHiddenInGame(false);
and if you want it to appear somewhere, you can use SetActorLocation(LocationVector).

But I need to know what you mean by “drop.” Do you mean spawn a new item, with physics enabled? Because if you just make it invisible without physics or collision, it will be lying around somewhere in your world (which I guess is ok), but if you want to spawn a new one, you can do that too. But your “PendingKill” problem comes from trying to spawn an actor you’ve already called Destroy() on.

I don’t know if SetActorHiddenInGame() has anything to do with the physics being on or off.

What I mean by “drop” is to take the item and make it appear in-front of the character. Since I don’t want to create a new item, I just want to “re-spawn” it so yea just SetActorHiddenInGame would work but you also need to disable collision. If you don’t disable collision you will be able to keep picking up the weapon even though its invisible.

The issue I’m having now is after re-enabling collision, the sword keeps falling though the floor. I try to spawn it above the floor but it insists on falling though the floor when I un-hide it and re-enable collision.

Could you make a temporary weapon variable? Like this:

ABaseItem* TemporaryItem;
TemporaryItem = ItemToDrop;
ItemToDrop->Destroy();

And then when you need to spawn it again, spawn the temporary item?
You shouldn’t get the pendingKill problem that way.

That might solve the pendingKill problem but that’s not necessarily what I want. If I destroy an item, lets say in the future that item has enchantments put on it. The enchantments would be lost because you would be creating a new item entirely.

My initial understanding of Destroy was slightly incorrect, now that I understand that destroy literally means destroy the item and remove it from memory, that’s not exactly what “dropping” an item is.

That’s right, calling Destroy() will make pointers to that object null. But why don’t you just create a function that creates a temporary and then populates any variables based on the item you’re about to destroy? Like if you have a magical damage buff for instance, create a temporary and make its damage buff equal to the damage buff of the item you’re about to destroy, then destroy it. Now you have an exact copy of that item stored in your character (or wherever you store it) class and then when you want to bring it back, simply spawn that temporary.

Edit: Actually, as soon as you copy all the variables from the item into the temporary, then destroy, simply set the pointer to the destroyed item equal to the temporary. Then you have an exact copy stored as your item variable. Like this:

ABaseItem* Temporary;
Temporary = ItemToDestroy;
Temporary->DamageBuff = ItemToDestroy->DamageBuff;
ItemToDestroy->Destroy();
ItemToDestroy = Temporary;

You can do it this way. I do this in my project. Now your item will no longer be in the world, but you can re spawn it any time, with all the parameters and enchantments stored on it.

That doesn’t sound like the proper way to do it. I thought the proper way was to hide it and then un-hide it like you suggested previously, that’s what I’ve been trying to get working. Doing it this way might work but it seems like we’re going around logic we should be enforcing.

One way in’t more proper than another. I just said you could do that because I understood what you meant by drop, meaning you wanted to re spawn. But as far as the actor falling through the floor, have you tried the following (after setting visible to true and setting the actor location):

TheWeaponRootComponent->SetCollisionProfileName(TEXT("BlockAll"));

Or whatever component you have set up for collision. Be it a box or a capsule etc.

Nah I tried that, I create the bounding capsule sub-object in the constructor for the item but I don’t think I should have to re-construct (call the constructor on) the actor just to un-hide the actor. I tried doing what you wrote but all that’s happening now is it re-appears in the same spot I originally picked it up at so its not setting the location, and in addition to that its not detecting collisions after I do that.

Do you have a particular root component selected? I know there can be issues if you don’t. Try these specific settings (I’m assuming your root component is something called capsule)

Capsule->SetSimulatePhysics(true);
Capsule->SetCollisionObjectType(ECC_WorldStatic);
Capsule->SetCollisionProfileName(TEXT("BlockAll"));

These are literally the settings I have on weapon items that I drop in the world.
They fall and tumble around on the ground. Sometimes they bounce and fall through the floor, so I have a special code to take care of it. Here’s the header and the source file for a weapon called AProjectile, which spawns with AddForce and AddTorque so it flies and spins, and notice my timer triggered function that detects if it falls through the floor and stops it if it does so. You must select the mesh in the blueprint (I chose not to hardcode the mesh into the code).

Header:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

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

UCLASS()
class MELEE_API AProjectile : public AActor
{
	GENERATED_BODY()
	
public:	

	FTimerHandle TimerHandle;

	void TurnOffCollision();

	bool bHasTimerTicked;
	
	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = Projectile)
	USkeletalMeshComponent* Mesh;

	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = MeleeWeapon)
	UBoxComponent* Capsule;

	
	// Sets default values for this actor's properties
	AProjectile(const FObjectInitializer& ObjectInitializer);

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

	
	
};

and source:

// Fill out your copyright notice in the Description page of Project Settings.

#include "Melee.h"
#include "Projectile.h"


// Sets default values
AProjectile::AProjectile(const FObjectInitializer& ObjectInitializer) :
Super(ObjectInitializer.SetDefaultSubobjectClass<UMovementComponent>(TEXT("Movement")))
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mesh"));
	

	Capsule = CreateDefaultSubobject<UBoxComponent>(TEXT("Capsule"));
	RootComponent = Capsule;
	Mesh->AttachTo(RootComponent);
	Capsule->SetSimulatePhysics(true);
	Capsule->SetCollisionEnabled(ECollisionEnabled::PhysicsOnly);
	Capsule->SetCollisionObjectType(ECC_WorldStatic);
	SetActorEnableCollision(true);
	Capsule->SetCollisionProfileName(TEXT("BlockAll"));

	bHasTimerTicked = false;

}

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

	
	Capsule->AddForce(FVector(2000, -200, 20000), NAME_None, true);
	Capsule->AddTorque(FVector(20000, 20000, 0), NAME_None, true);
}

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

	if (GetActorLocation().Z <= 3500.f)
	{
		if (Capsule->GetComponentLocation().Z <= -12.0f)
		{
			SetActorEnableCollision(false);
			Capsule->SetSimulatePhysics(false);
			Capsule->SetCollisionProfileName(TEXT("OverlapAll"));

			FRotator NewRotation = GetActorRotation();

			NewRotation.Yaw = 0.f;
			SetActorRotation(NewRotation);
			FVector NewActorLocation = GetActorLocation();
			NewActorLocation.Z = 0.f;
			SetActorLocation(NewActorLocation);
			return;
		}
		if (!bHasTimerTicked)
		{
			GetWorldTimerManager().SetTimer(TimerHandle, this, &AProjectile::TurnOffCollision, 3.5f, false);
		}
		bHasTimerTicked = true;
	}

}

void AProjectile::TurnOffCollision()
{
	SetActorEnableCollision(false);
	Capsule->SetSimulatePhysics(false);
	Capsule->SetCollisionProfileName(TEXT("OverlapAll"));
	
}

I hope this helps.

Correction: The tick function detects if it falls through the floor by seeing if its Z location ever goes past -12.f and if so it turns off physics. The timer function is what allows it to tumble realistically before turning off physics. This is so the character doesn’t bump into its collision mesh when it’s on the ground. Also, ignore that first if statement. Originally I was using it to test something but for our purposes here it doesn’t do anything.

Another thing to note: I’m using a box component for the collision, and I’m calling it Capsule. Hope that doesn’t confuse you. Before it was a capsule component and I changed it but kept the name.

Hope that helps.

I said screw it and tried what you suggested and it worked exactly as I want it to! My only concern is this; why does this work? Having juggler = itemToAdd takes the contents of itemToAdd and copies them into juggler, making juggler point to the same location. My line of thought was that since juggler is pointing to the same location, it would get destroyed anyway because we simply have two pointers pointing to the same memory location. But as we see below, my assumption is apparently wrong.

So what exactly is happening when we do “temporary = itemToAdd”? Below is my full code for when I remove an item from the world.

bool SEtherItemGrid::AddItem(ABaseItem* itemToAdd)
{
	bool itemWasAdded = false;
	int32 firstEmptySlotIndex = -1;
	ABaseItem* juggler;

	if (itemToAdd != NULL)
	{
		//Get the index of the first available slot.
		firstEmptySlotIndex = this->FindFirstAvailableSlot();

		if (firstEmptySlotIndex >= 0 && firstEmptySlotIndex < this->GetNumSlots())
		{
			//Add the item to the empty slot we just found.
			itemWasAdded = this->AddItem(firstEmptySlotIndex, itemToAdd);

			//Check to see if the item was added successfully.
			if (itemWasAdded == true)
			{
				juggler = itemToAdd;
				itemToAdd->Destroy();
				itemToAdd = juggler;

				//Clean up temporary variable copy.
				juggler->Destroy();
			}
		}
	}

	return itemWasAdded;
}

Yea it did make it un-green, that was weird, I’ll make sure you get credit for it. Add me on Skype (Katianie9).

That’s fine I just wanted to make sure I still understand pointers correctly, Because I printed out the memory addresses of the temporary and the itemToAdd and they were the same. I guess in the case of unreal engine, it makes a copy and has the pointer point to that…but then why would the addresses be the same? Perhaps unreal is doing some behind the scenes logic to accomplish this.