Getting an error trying to EnableInput on PlayerController

I am getting this error. Exception thrown at 0x00007FF9B2566758 (UE4Editor-FPSGame.dll) in UE4Editor.exe: 0xC0000005: Access violation reading location 0x0000000000000000.

Here is my GameCharacter.cpp file,

AFPSCharacter::AFPSCharacter()
{
       PlayerC = Cast<APlayerController>(GetController());
    	PlayerC->EnableInput(PlayerC);
    	bIsEPressed = PlayerC->IsInputKeyDown(EKeys::E);
    		if (bIsEPressed)
    		{
    			GetWorld()->SpawnActor<AFPSBlackHole>(GetClass(), FVector(0.f, 0.f, 0.f),FRotator::ZeroRotator);
    		}
}

	//_____________________________________________________
   //This is the .h file

    UPROPERTY()
	APlayerController* PlayerC;

	UPROPERTY()
	bool bIsEPressed;

What I am trying to do is monitor the keypress of letter E, if it occurs then I want to spawn a new actor. I am new to unreal so I am not sure what I am doing wrong.

I think I have seen that I can set up an InputController, but I was hoping this would be an easier way of monitoring for keypresses. If I set up an InputController and BindAction to each key I would have to make tons of functions and keys to bind them to.

Probably the crash is being caused by you trying to call GetWorld()->SpawnActor(...) in the constructor of your character class. It’s easy to forget, but note that class constructors long before you get a chance to hit the Play button — they’re even executed while the editor is loading. In other words, you can’t trust that the ‘game world’ exists when an object’s constructor is executed.

My advice: don’t try to spawn actors in any constructor; consider using BeginPlay() instead — but even then, remember to check that the world exists before trying to do something with it (like spawning actors). Anytime you see an “access violation” error, odds are you’ve tried to use a pointer before that pointer is ready — that is, before it points to a valid memory address. If pointers feel new to you, there are innumerable resources on the web for learning about the topic, but an obvious example is on the UE4 wiki: Entry Level Guide to UE4 C++


But now to the subject of input events.

You wrote,

If I set up an InputController [sic] and BindAction to each key I would have to make tons of functions and keys to bind them to.

… and I think you might have it backwards. Using the InputComponent properly, you would set up functions to handle only as many actions as you need. You don’t have to create a function per key — you can assign multiple keys to the same action in your project settings from within the editor.

For example, you could have one jump action, but assign two, or three, or five, or thirty different keys to this jump action in your project settings. All using just one jump function. This way, things stay really tidy.

But, if you prefer to use the IsInputKeyDown(...) approach, you can, but — like what I wrote above — you shouldn’t want to use the class constructor for this. You could try putting that function within Tick(), but you might want to ask yourself — is this the most organized and efficient way to program the desired behavior? In my opinion, the events-driven approach of the InputComponent is much more elegant.

I agree that using Tick() for input isn’t the best approach — I just wanted to mention it for comparison, to help illustrate what makes the events-driven approach so much tidier.

Now that I have a better understanding of your goal — kind of like typing in a cheat code — I have a different solution to suggest, which I’ll post in a new answer.

Since your goal is to capture keyboard input and trigger something if the player types in a specific sequence of letters, I suggest trying to use the InputKey function in the APlayerController class.

This function is virtual, meaning you can override it in your custom player controller, and it will be called up (presumably) every time the player presses a keyboard key. (I say ‘presumably’ because I’ve never used this function myself, and I won’t get a chance to test it within the next few hours, so I’m just crossing my fingers for now.)

The function’s signature provides an FKey parameter that you can use to identify which key was pressed. The basic idea is to log which keys the player presses, storing the results in a string, and checking the string to see if it matches the desired sequence (e.g. “ezgame”). After a couple seconds of no keyboard input, the string will be cleared, giving the player another chance to try to type the sequence correctly.

One possible implementation might look like this:

(This goes in your player controller .cpp file. Assume you have an FString variable called ‘CodeSequence’ which you’ll use to keep track of what the player has ‘typed in’ so far.)

bool InputKey(FKey Key, EInputEvent EventType, float AmountDepressed, bool bGamepad)
{
    // Only bother with presses (not releases) and don't worry about mouse button events
    if (InputType == EInputEvent::IE_Pressed && Key.IsMouseButton() == false)
    {
        // Clear the CodeSequence string if the last key press was more than 2 seconds ago
        ResetExpiredCodeSequence();  // in case it's not clear, this is another custom function

        // float TimeOfLastKeyPress is a float variable that you'll also set up in your Player Controller class
        TimeOfLastKeyPress = GetGameTimeSinceCreation();  // set the time (now) for the current key press; this is used by ResetExpiredCodeSequence(), above

        // Add the pressed key's "character" to the CodeSequence (by getting the key's string representation)
        CodeSequence += Key.ToString();
    
        // Call a custom function that compares the sequence to a list of your matching 'codes'
        CheckCodeSequence();
    }
    
    // Return a bool by calling the Super version of this function
    return Super::InputKey(Key, EventType, AmountDepressed, bGamepad);
}

As shown above, you’ll also need a couple additional functions to get things working. Such as:

void ResetExpiredCodeSequence()
{
    // Find out how many seconds has passed since the last key press
    float TimeSinceLastKeyPress = GetGameTimeSinceCreation() - TimeOfLastKeyPress;

    bool bSequenceExpired = TimeSinceLastKeyPress > 2.0f;  // arbitrarily choosing 2 seconds for this example
    if (bSequenceExpired)
    {
        // If more than 2 seconds has passed since the last key press, reset the string; otherwise, don't do anything
        CodeSequence = "";    // reset the string back to a blank, empty string
    }
}

And finally, something to compare to your ‘matching’ sequence strings:

void CheckCodeSequence()
{
    if (CodeSequence == "EZGAME")
    {
        // Do something to handle this match, e.g. spawn your actor(s)
    }
    else if (CodeSequence == "EXAMPLE2")
    {
        // Just another example to show that you can handle more than one match possibility
    }
    // etc.
}

Note that I’m using exclusively all caps in the above example. You don’t have to do that — you could use all lowercase — but the important thing is that you remain consistent.

As I said above, I don’t think I’ve used the InputKey function yet myself, and I’ve certainly not yet attempted to get a ‘cheat code’ input system like this working before myself. So maybe this won’t work exactly as I’ve written it. But hopefully it moves you (and anyone else who may find it) further in the right direction.

I think I understand what you mean, but the access violation is occuring here PlayerC->EnableInput(PlayerC), I believe it is also because of being in the constructor, I will try to move it to BeginPlay.

I don’t know if the Tick would be the best place for that because i don’t want to be constantly polling to see if a key is pressed i just wanted an event to trigger when it is. Does IsInputKeyDown() only works if it is in Tick?

The purpose of this logic is to spawn a blackhole when a user inputs “ezgame” on the keyboard in that sequence. I just wanted to get a simple way to do that.

I tried moving what I had to the begin play and I no longer had an error, but the code doesn’t seem to work though.
So now I will try it the way you mentioned using InputKey it seems like this way is better.

I won’t need to set up an Input Controller if I do it this way? I am just curious, is it correct that you can either use InputKeys OR set up and InputController in the PlayerController file?
Either one will work and we are just using InputKeys because of the simplicity for my goal?

Btw thank you for the help, I appreciate it :smiley:

So If I overwrite the virtual function of the InputKey it would look like this? I see you put void but wouldn’t it have to follow the parent class and return a bool?

bool AFPSPlayerController::InputKey(FKey Key, EInputEvent EventType, float AmountDepressed, bool bGamepad)
{
	Super::InputKey(Key, EventType, AmountDepressed, bGamepad);

<Rest of code here>


}

Also I do not think I can do the switch statement here as It gives me errors, The case needs to be a constant and Ekeys::E is not able to be used here. Also the switch expression must be an integral or enum type which key is not. I think I will have to just use If / else statements here to get this to work.

Either one will work and we are just using InputKeys because of the simplicity for my goal?

Yep! That’s the idea.

I see you put void but wouldn’t it have to follow the parent class and return a bool?

You’re exactly right. I wrote my version directly from the top of my head, and I made a mistake. Yes, it does need to return a bool. (It should also probably call its Super:: function, too.)

Also the switch expression must be an integral or enum type which key is not.

You’re completely right again. Thanks for correcting me. Halfway through writing my answer, I must have gotten mixed up and started typing EKey instead of FKey. (There is an EKeys enum, which maybe explains my confusion, but it’s not useful here.) So yeah, the function passes an FKey struct, not an enum, which means we cannot use a switch/case. Actually, you might not even need to use if/else statements — I hope you’ll see what I mean.

I finally got a chance to test this idea a bit, and I realized I forgot some other important lines. I’ve edited these improvements back into the example above, along with the corrections you’ve pointed out.

Good news is, even with the fixes that were necessary to my original attempt, now it’s perhaps even easier to set up.

Check out my edited example above one more time and let me know what you think.

Cool :smiley: I will take a look now

I was also wondering where is the best place to spawn the actor from in your opinion? Maybe from the FPSCharacter.cpp class which inherits from the ACharacter.cpp class. I don’t know if its ideal to be doing the spawning directly from the FPSPlayerController class.

You can spawn actors from any class that is able to access the game world —typically by calling GetWorld().

As for where you should spawn actors, that’s entirely up to you. I suggest, wherever it makes the most sense to you and the other developers on your project.

I wish I could give you a more concrete answer, but there’s just no single right way to do this.

Sorry for the basic question, but cant any class access the game world?

Most of the classes that we often deal with usually can access the world, yes. But not necessarily every class can — at least, not always directly. It’s a small point, but sometimes it’s worth mentioning.