Custom Pawn crashes the editor

I just tried to make my own Pawn class by inheriting the default APawn class. Then I made a blueprint from that class and put it as my standard Pawn BP in my gamemode. When I press Play, the editor immediately crashes with this log:


Access violation - code c0000005 (first/second chance not available)

UE4Editor_BuildingEscape_1650!ABuildingEscapePawn::SetupInputComponent() [e:\ue4 projects\03_buildingescape\buildingescape\source\buildingescape\buildingescapepawn.cpp:38]
UE4Editor_Engine!APawn::PawnClientRestart() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\pawn.cpp:367]
UE4Editor_Engine!APlayerController::ClientRestart_Implementation() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\playercontroller.cpp:719]
UE4Editor_Engine!APlayerController::execClientRestart() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\classes\gameframework\playercontroller.h:155]
UE4Editor_CoreUObject!UFunction::Invoke() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\coreuobject\private\uobject\class.cpp:5077]
UE4Editor_CoreUObject!UObject::ProcessEvent() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:1245]
UE4Editor_Engine!AActor::ProcessEvent() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\actor.cpp:639]
UE4Editor_Engine!APlayerController::ClientRestart() [d:\build\++ue4+release-4.12+compile\sync\engine\intermediate\build\win64\ue4editor\inc\engine\engine.generated.1.cpp:4367]
UE4Editor_Engine!APlayerController::Possess() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\playercontroller.cpp:785]
UE4Editor_Engine!AGameMode::RestartPlayer() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\gamemode.cpp:501]
UE4Editor_Engine!AGameMode::HandleMatchHasStarted() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\gamemode.cpp:607]
UE4Editor_Engine!AGameMode::SetMatchState() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\gamemode.cpp:733]
UE4Editor_Engine!AGameMode::StartMatch() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\gamemode.cpp:600]
UE4Editor_Engine!UWorld::BeginPlay() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\world.cpp:3218]
UE4Editor_Engine!UGameInstance::StartPIEGameInstance() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\gameinstance.cpp:293]
UE4Editor_UnrealEd!UEditorEngine::CreatePIEGameInstance() [d:\build\++ue4+release-4.12+compile\sync\engine\source\editor\unrealed\private\playlevel.cpp:3250]
UE4Editor_UnrealEd!UEditorEngine::PlayInEditor() [d:\build\++ue4+release-4.12+compile\sync\engine\source\editor\unrealed\private\playlevel.cpp:2346]
UE4Editor_UnrealEd!UEditorEngine::StartQueuedPlayMapRequest() [d:\build\++ue4+release-4.12+compile\sync\engine\source\editor\unrealed\private\playlevel.cpp:1103]
UE4Editor_UnrealEd!UEditorEngine::Tick() [d:\build\++ue4+release-4.12+compile\sync\engine\source\editor\unrealed\private\editorengine.cpp:1246]
UE4Editor_UnrealEd!UUnrealEdEngine::Tick() [d:\build\++ue4+release-4.12+compile\sync\engine\source\editor\unrealed\private\unrealedengine.cpp:368]
UE4Editor!FEngineLoop::Tick() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\launch\private\launchengineloop.cpp:2775]
UE4Editor!GuardedMain() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\launch\private\launch.cpp:148]
UE4Editor!GuardedMainWrapper() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:126]
UE4Editor!WinMain() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:200]
UE4Editor!__scrt_common_main_seh() [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:264]
kernel32
ntdll

I need help figuring out why this happens. On line 38 in buildingescapepawn.cpp you find this:


InputComponent = GetOwner()->FindComponentByClass<UInputComponent>();

I’m still learning C++ so please bear with me :slight_smile:

And here is my code:

ABuildingEscapePawn.h


#pragma once

#include "GameFramework/Pawn.h"
#include "BuildingEscapePawn.generated.h"

UCLASS()
class BUILDINGESCAPE_API ABuildingEscapePawn : public APawn
{
	GENERATED_BODY()

public:
	// How far ahead of the player can we reach in cm
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float Reach = 100.f;

	// Sets default values for this pawn's properties
	ABuildingEscapePawn();

	// 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;

private:
	UPhysicsHandleComponent* PhysicsHandle = nullptr;
	UInputComponent* InputComponent = nullptr;

	/*---------------*/
	/* Input Section */
	/*---------------*/

	// Ray-cast and use what's in reach
	void Use();

	// Ray-cast and grab what's in reach
	void Grab();

	// Called when grab key is released
	void ReleaseGrab();

	/*-----------------*/
	/* Helper Functions*/
	/*-----------------*/

	// Find attached physics handle
	void FindPhysicsHandleComponent();

	// Return hit for first physics body in reach
	const FHitResult GetFirstPhysicsBodyInReach();

	// Return hit for first use handle in reach
	const FHitResult GetFirstUseHandleInReach();

	// Setup (assumed) attached input component
	void SetupInputComponent();

	// Find the vector at the start of the players reach
	FVector GetReachLineStart();

	// Find the vector at the end of the players reach
	FVector GetReachLineEnd();
};


ABuildingEscapePawn.cpp


#include "BuildingEscape.h"
#include "BuildingEscapePawn.h"
#include "UseComponent.h"


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

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

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

}

// Called to bind functionality to input
void ABuildingEscapePawn::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
	Super::SetupPlayerInputComponent(InputComponent);
	SetupInputComponent();
}

void ABuildingEscapePawn::SetupInputComponent()
{
	InputComponent = GetOwner()->FindComponentByClass<UInputComponent>();
	if (InputComponent)
	{
		InputComponent->BindAction("Use", EInputEvent::IE_Pressed, this, &ABuildingEscapePawn::Use);
		InputComponent->BindAction("Grab", EInputEvent::IE_Pressed, this, &ABuildingEscapePawn::Grab);
		InputComponent->BindAction("Grab", EInputEvent::IE_Released, this, &ABuildingEscapePawn::ReleaseGrab);
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("%s missing input component"), *(GetOwner()->GetName()));
	}
}

void ABuildingEscapePawn::Use()
{
	if (!PhysicsHandle->GrabbedComponent)
	{
		FHitResult HitResult = GetFirstUseHandleInReach();
		AActor* ActorHit = HitResult.GetActor();
		if (ActorHit)
		{
			UUseComponent* UseComp = ActorHit->FindComponentByClass<UUseComponent>();
			if (UseComp)
			{
				UseComp->FireUseEvent();
			}
		}
	}
}

void ABuildingEscapePawn::Grab()
{
	/// Line trace and see if we reach any actors with physics body collision channel set
	FHitResult HitResult = GetFirstPhysicsBodyInReach();
	UPrimitiveComponent* ComponentToGrab = HitResult.GetComponent();
	AActor* ActorHit = HitResult.GetActor();

	/// If we hit something, then attach a physics handle
	if (ActorHit && PhysicsHandle)
	{
		PhysicsHandle->GrabComponent(ComponentToGrab, EName::NAME_None, ComponentToGrab->GetOwner()->GetActorLocation(), true); // true is to allow rotation
	}
}

void ABuildingEscapePawn::ReleaseGrab()
{
	PhysicsHandle->ReleaseComponent();
}

void ABuildingEscapePawn::FindPhysicsHandleComponent()
{
	PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
	if (PhysicsHandle == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("%s missing physics handle component"), *(GetOwner()->GetName()));
	}
}

const FHitResult ABuildingEscapePawn::GetFirstUseHandleInReach()
{
	/// Line-trace (AKA ray-cast) out to reach
	FHitResult HitResult;
	// Setup Query parameters
	FCollisionQueryParams TraceParameters(FName(TEXT("")), false, GetOwner());
	GetWorld()->LineTraceSingleByChannel(HitResult, GetReachLineStart(), GetReachLineEnd(), ECollisionChannel::ECC_Visibility, TraceParameters);

	return HitResult;
}

const FHitResult ABuildingEscapePawn::GetFirstPhysicsBodyInReach()
{
	/// Line-trace (AKA ray-cast) out to reach 
	FHitResult HitResult;
	// Setup query parameters
	FCollisionQueryParams TraceParameters(FName(TEXT("")), false, GetOwner());

	GetWorld()->LineTraceSingleByObjectType(OUT HitResult, GetReachLineStart(), GetReachLineEnd(), FCollisionObjectQueryParams(ECollisionChannel::ECC_PhysicsBody), TraceParameters);

	return HitResult;
}

FVector ABuildingEscapePawn::GetReachLineStart()
{
	FVector PlayerViewPointLocation;
	FRotator PlayerViewPointRotation;
	GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(OUT PlayerViewPointLocation, OUT PlayerViewPointRotation);

	return PlayerViewPointLocation;
}

FVector ABuildingEscapePawn::GetReachLineEnd()
{
	FVector PlayerViewPointLocation;
	FRotator PlayerViewPointRotation;
	GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(OUT PlayerViewPointLocation, OUT PlayerViewPointRotation);

	return PlayerViewPointLocation + (PlayerViewPointRotation.Vector() * Reach);
}

You’re calling AActor::GetOwner(), it returns the AActor::Owner member, which is used for replication and is usually null or invalid. You probably want to replace GetOwner() with GetController(), and check for validity before accessing it. But you really should just pass in the InputComponent pointer given in SetupPlayerInputComponent rather than trying to find it yourself.

Oooh…yeah that makes sense then.

I did actually consider simply passing the InputComponent I get from SetupInputComponent() but I was tired and had to go sleep so I didn’t get around to trying it.
Thanks though, I’ll try it when I can :slight_smile:

So basically making this:


UInputComponent* InputComponent = nullptr;

Into this:


UInputComponent* InputComponent;

Then in my .cpp I’d do this:



if (InputComponent)
{
	InputComponent->BindAction("Use", EInputEvent::IE_Pressed, this, &ABuildingEscapePawn::Use);
	InputComponent->BindAction("Grab", EInputEvent::IE_Pressed, this, &ABuildingEscapePawn::Grab);
	InputComponent->BindAction("Grab", EInputEvent::IE_Released, this, &ABuildingEscapePawn::ReleaseGrab);
	SetupPlayerInputComponent(InputComponent);
}
else
{
	UE_LOG(LogTemp, Error, TEXT("%s missing input component"), *(GetController()->GetName()));
}

?

I just looked over your code more thoroughly, and theres a couple things wrong that will cause crashes later on. First off your pointers need to be declared as UPROPERTY() because the objects they point to can easily be deleted from under you, you should mark them as UPROPERTY so UE4 can properly use its memory management. Second, you don’t need to store a pointer to the InputComponent, the engine automatically calls SetupPlayerInputComponent and gives you the input component it wants you to bind stuff to as the argument to the function, if you change your code to what you just posted, it will go into an infinite loop and run out of stack space. Did this code used to be on a component? Because I’m seeing a lot of GetOwner() calls which don’t make sense. There’s a UActorComponent::GetOwner() which gets the outer actor of a component which would make sense if this code were on a component, but you’re doing AActor::GetOwner() which gets the actor that owns this actor with regards to network permissions, and it doesn’t make sense in this context. Also it almost looks like you’re coming from a Unity background, there’s far too much FindComponentByClass<> which doesn’t really work that well in UE4 since you often have multiple components of the same type on an actor. Also, doing GetWorld()->GetFirstPlayerController() isn’t really the right way to do it, you really should use GetController() which is a function of APawn. I don’t mean to be mean, but you should probably go through the gameplay framework documentation and follow along with some c++ tutorials (preferably made for version 4.10 or later), because what you’ve written so far isn’t really the right way to go about writing code in UE4.

Okay so lets take it one thing at a time. Sorry, I’m new to C++ in UE4 and I’ve never extended the Pawn before so, a lot of this is probably just beginner mistakes ._.

Should I do that to all my pointers in general…?

But this code here:


void SetupPlayerInputComponent(class UInputComponent* InputComponent)

Doesn’t return anything, so how would I get the InputComponent? Something like GetController()->GetInputComponent()?

Yes, this code used to be part of a “DefaultPlayerController” component that I stuck on a DefaultPawn_BP (Blueprint) so that it got some custom controls as you see in the code (Grab, Use). But I felt that was dumb and wanted to move it into the Pawn instead but this resulted in the mess I’m in now haha

I followed a Udemy class that was backed by Kickstarter (basically the one with Learn C++ with UE4, pretty good) and he used the method seen above. I haven’t moved on to the next part yet where you make a much more complex game with AI and such so perhaps this is further discussed in that part. I have used Unity before and I was surprised too that the teacher (who also got a Unity background) just used that in UE4. I didn’t pay it much mind because he is a teacher.

The same reason as above. My understanding of UE4 C++ is still very limited. I learn by doing :')

I understand that. That’s why I’m here so I can learn a bit from my mistakes. I understand C++ but I haven’t used C++ before. Learning to use it here is what I want to do so…I’m trying. I have a bachelor’s degree in computer science so programming is not alien to me, but I was taught in Java and C#. Had to teach myself C++ so, it’s going to be rocky in the beginning I’m sure. Thanks for taking the time to teach me by pointing out my mistakes :slight_smile:

Yes you should make UPROPERTY on every pointer that you store as a member variable of a UObject, AActor or UStruct, because then UE4 can take care of whether it still points to a valid object.

The only place you need the input component is within SetupPlayerInputComponent itself, and UE4 gives it to you inside that function (the argument named InputComponent). Your entire input code should look like this:



//header
	virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) override;
//cpp
void ABuildingEscapePawn::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
	Super::SetupPlayerInputComponent(InputComponent);
	InputComponent->BindAction("Use", EInputEvent::IE_Pressed, this, &ABuildingEscapePawn::Use);
	InputComponent->BindAction("Grab", EInputEvent::IE_Pressed, this, &ABuildingEscapePawn::Grab);
	InputComponent->BindAction("Grab", EInputEvent::IE_Released, this, &ABuildingEscapePawn::ReleaseGrab);
}

You don’t need to store any UInputComponent* or manually find the input component unless you’re doing some advanced input stuff.

C++ doesn’t work at all like Java or C#, there’s a bunch of gotchas and behaviours that are different especially with regard to objects, references, and memory management, and you won’t go far without learning them. Basically everyone will tell you the way to learn UE4 C++ is to get a solid understanding of C++ by itself first, then learn how to use UE4’s custom version of C++. You should use recent official tutorials from Epic instead of this Udemy class because it looks like it’s teaching you bad design.

I thank you for your advise to go and look at C++ more in-depth but I just can’t keep going back to zero all the time. I need to see that I can actually use C++ at all and I feel like I am making baby steps here. I won’t make perfect C++ code from the get-go just like how I didn’t learn how to make perfect Java or C# code. It’s okay to fail, as long as I learn from it :slight_smile:

Now my code is a bit different, but still not working 100 %.
I can now get into the game but no WASD or Mouse Movement registers. I assume this is because the Basic Movement Input variable is not checked? If that’s the case, would I have to write my own code to make basic movement?


#include "BuildingEscape.h"
#include "BuildingEscapePawn.h"
#include "UseComponent.h"


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

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

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

}

// Called to bind functionality to input
void ABuildingEscapePawn::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
	Super::SetupPlayerInputComponent(InputComponent);
	if (InputComponent)
	{
		InputComponent->BindAction("Use", EInputEvent::IE_Pressed, this, &ABuildingEscapePawn::Use);
		InputComponent->BindAction("Grab", EInputEvent::IE_Pressed, this, &ABuildingEscapePawn::Grab);
		InputComponent->BindAction("Grab", EInputEvent::IE_Released, this, &ABuildingEscapePawn::ReleaseGrab);
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("%s missing input component"), *(GetController()->GetPawn()->GetName()));
	}
}

void ABuildingEscapePawn::Use()
{
	if (PhysicsHandle)
	{
		if (!PhysicsHandle->GrabbedComponent)
		{
			FHitResult HitResult = GetFirstUseHandleInReach();
			AActor* ActorHit = HitResult.GetActor();
			if (ActorHit)
			{
				UUseComponent* UseComp = ActorHit->FindComponentByClass<UUseComponent>();
				if (UseComp)
				{
					UseComp->FireUseEvent();
				}
			}
		}
	}
}

void ABuildingEscapePawn::Grab()
{
	/// Line trace and see if we reach any actors with physics body collision channel set
	FHitResult HitResult = GetFirstPhysicsBodyInReach();
	UPrimitiveComponent* ComponentToGrab = HitResult.GetComponent();
	AActor* ActorHit = HitResult.GetActor();

	/// If we hit something, then attach a physics handle
	if (ActorHit && PhysicsHandle)
	{
		PhysicsHandle->GrabComponent(ComponentToGrab, EName::NAME_None, ComponentToGrab->GetOwner()->GetActorLocation(), true); // true is to allow rotation
	}
}

void ABuildingEscapePawn::ReleaseGrab()
{
	PhysicsHandle->ReleaseComponent();
}

void ABuildingEscapePawn::FindPhysicsHandleComponent()
{

	PhysicsHandle = GetController()->GetPawn()->FindComponentByClass<UPhysicsHandleComponent>();
	if (PhysicsHandle == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("%s missing physics handle component"), *(GetController()->GetPawn()->GetName()));
	}
}

const FHitResult ABuildingEscapePawn::GetFirstUseHandleInReach()
{
	/// Line-trace (AKA ray-cast) out to reach
	FHitResult HitResult;
	// Setup Query parameters
	FCollisionQueryParams TraceParameters(FName(TEXT("")), false, GetController()->GetOwner());
	GetWorld()->LineTraceSingleByChannel(HitResult, GetReachLineStart(), GetReachLineEnd(), ECollisionChannel::ECC_Visibility, TraceParameters);

	return HitResult;
}

const FHitResult ABuildingEscapePawn::GetFirstPhysicsBodyInReach()
{
	/// Line-trace (AKA ray-cast) out to reach 
	FHitResult HitResult;
	// Setup query parameters
	FCollisionQueryParams TraceParameters(FName(TEXT("")), false, GetController()->GetOwner());

	GetWorld()->LineTraceSingleByObjectType(OUT HitResult, GetReachLineStart(), GetReachLineEnd(), FCollisionObjectQueryParams(ECollisionChannel::ECC_PhysicsBody), TraceParameters);

	return HitResult;
}

FVector ABuildingEscapePawn::GetReachLineStart()
{
	FVector PlayerViewPointLocation;
	FRotator PlayerViewPointRotation;
	GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(OUT PlayerViewPointLocation, OUT PlayerViewPointRotation);

	return PlayerViewPointLocation;
}

FVector ABuildingEscapePawn::GetReachLineEnd()
{
	FVector PlayerViewPointLocation;
	FRotator PlayerViewPointRotation;
	GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(OUT PlayerViewPointLocation, OUT PlayerViewPointRotation);

	return PlayerViewPointLocation + (PlayerViewPointRotation.Vector() * Reach);
}

To get the basic movement (move & mouse look) working , you have to derive from “ADefaultPawn” instead of “APawn”

Oh darn.
Well I’ll have to start over then haha. Thanks though.

How would I override the standard bindings of ADefaultPawn? Last time I tried to press “E” it made me float upwards like when I pressed space.

@Vipar
“E” is already registered with “InitializeDaufaultPawnBinding” , to have more control the best way is to drive from “APawn” and copy the defautpawn movement inputs setup from “ADefaultPawn” and remove the axis definition like (E,C)…

Oh okay.
I’ll have to look at that.