SimpleShooter press key to open/close the door

Hello I am trying to implement when player press E to the door, the door will open/close. But it keeps crashing whenever I try to call the function from ShooterCharacter. Any hints or suggestions?
Below is part of my code.

ShooterCharacter.h
class UOpenDoor;
public:
void Interact();
private:
	UPROPERTY(EditDefaultsOnly)
	TSubclassOf<UOpenDoor> DoorClasss;

	UPROPERTY()
	UOpenDoor *OpenDoor;
ShooterCharacter.cpp
void AShooterCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
       
	PlayerInputComponent->BindAction(TEXT("Interact"), IE_Pressed, this, &AShooterCharacter::Interact);
}
void AShooterCharacter::Interact() 
{	
	OpenDoor->OpenDoor();
}
OpenDoor.h
public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
	void OpenDoor();

private:

	float InitialYaw;
	float CurrentYaw;
	UPROPERTY(EditAnywhere)
	float OpenAngle{90.f};

	UPROPERTY(EditAnywhere)
	float DoorOpenSpeed{0.8f};
	UPROPERTY(EditAnywhere)
	float DoorCloseSpeed{2.f};

	// UPROPERTY(EditAnywhere)
	// AActor *ActorThatTrigger;
		
};
OpenDoor.cpp
void UOpenDoor::BeginPlay()
{
	Super::BeginPlay();

	InitialYaw = GetOwner()->GetActorRotation().Yaw;	
	CurrentYaw = InitialYaw;
	OpenAngle += InitialYaw;

	UE_LOG(LogTemp, Warning, TEXT("Current Yaw is %f"), CurrentYaw);
	// 
	// ...
	
}
}
void UOpenDoor::OpenDoor() 
{
	UE_LOG(LogTemp, Warning, TEXT("Current Yaw is %f"), CurrentYaw);
	CurrentYaw = FMath::FInterpConstantTo(CurrentYaw, OpenAngle, GetWorld()->GetDeltaSeconds(),45);	
	FRotator DoorRotation = GetOwner()->GetActorRotation();
	DoorRotation.Yaw = CurrentYaw;
	GetOwner()->SetActorRotation(DoorRotation);
}

It crashes every time I press E. The crash reporter says “Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x000000bc”

Beside this crash, my idea is to call OpenDoor() from OpenDoor.cpp everytime player press E, and check if the player is within the reach to the door in that function too. Is this a good way to do so?

Thanks in advance!

Where are you assigning OpenDoor?

Maybe null pointers are casuing the crash. In the interact function, check for nullptr before accessing the opendoor function. Try debugging by putting in breakpoints.

Under the StaticMeshComponent of the door in blueprint. It works fine without binding to the key if i put the code

	CurrentYaw = FMath::FInterpConstantTo(CurrentYaw, OpenAngle, GetWorld()->GetDeltaSeconds(),45);	
	FRotator DoorRotation = GetOwner()->GetActorRotation();
	DoorRotation.Yaw = CurrentYaw;
	GetOwner()->SetActorRotation(DoorRotation);

Under TickComponent. The door will just open automatically

Hmmmm yeah seems like a nullptr problem. But then why and how should I approach to this. Why Gun->PullTrigger() will not have this problem?

I think your approach of assigning opendoor* from the door bp is not good. This method won’t scale for multiple doors and stuff. The way I would do it is that inside the interact function, I would do a line trace from camera to a limited range. If it hits something, then cast the hit actor to UOpenDoor. If the cast succeeds, the just call the opendoor() on the actor. You won’t have to use the UOpenDoor* defined in the header file and you wont have to assign it in the door’s bp.

Where are you assigning that in the shooter character?

The place under blueprint.bp

okk thanks imma try that too :slight_smile:

That’s not the door. That’s the door class. This is the same issue as your other post.

The door exists in the world but your blueprint doesn’t, it’s not an instance. Only instances can be assigned something that exists in the world.

Sorry I dont really get that :frowning: Did you mean I should assign the instance of doorclass to BP_Character?

You’re assigning DoorClasss in the blueprint which is a TSubclassOf<UOpenDoor>. OpenDoor remains uninitialised so you’re dereferencing a null pointer.


TSubclass stores a type. It would be doing something like this (though this is not valid syntax)

// With the following types
// class A;
// class B : public A;

TSubclassOf<A> Example = B;

Not an instance of B, but B itself.

You can’t do that, the blueprint is not an instance. It’s not a physical thing that exists anywhere, it’s a blueprint (using the English definition of blueprint). Both need to be an instance.

In code you can find a specific object using FindObject (not in the constructor).

OpenDoor = FindObject<AOpenDoor>(GetWorld()->GetLevel(0), TEXT("ExactNameOfObject"));

But like @Harsh_Jalutharia has said, this aproach does not scale well. This only lets you open a single door.

I suggest you look into tutorials for interactable objects.

1 Like

Thank you so much!

Hi so I am trying to do a LineTraceSingleByObjectType in the interact function, but im not sure how should I cast it to the UOpenDoor? OpenDoor.h is a component of the door in the map and the actual type of that door seems to be an Actor.
What I tried

	FCollisionQueryParams TraceParams(FName(TEXT("")), false, this);
	GetWorld()->LineTraceSingleByObjectType(
		Hit,
		PlayerLocation,
		LineTraceEnd,
		FCollisionObjectQueryParams(ECollisionChannel::ECC_PhysicsBody),
		TraceParams
	);
	UOpenDoor* DoorThatHit = Cast<UOpenDoor>(Hit.GetActor());
	
	if (DoorThatHit) {
		// Call OpenDoor->Opendoor();
		UE_LOG(LogTemp, Warning, TEXT("Has hit %s"), *(DoorThatHit->GetName()));
		DoorThatHit->OpenDoor();
	}

But it does not work :frowning:

Oh. I don’t know how I assumed UOpenDoor was an Actor and not a component. Maybe try doing a getcomponentbyclass on the hitactor and using UOpenDoor as the ActorComponent to find.

1 Like

Thank you so much i followed your advice and now its working!

Glad I could help! :smile: