A good First Person Controller

Hi! You maybe remember the tutorial I did on creating a basic First Person Controller some time ago. I sat down to finally remedy the problems that this setup had:

1.Instant acceleration - If you press/let go of a movement button the player immediately goes full speed into that direction/stops, which does not feel smooth.
2. Collisions with walls - Since there the Controller simply tells Armory to move the player forward, the physics engine does a sloppy job of dealing with running into walls. It feels jittery and the player can even clip through the wall under some circumstances.
3. Slopes - The worst case scenario of colliding with walls. The Controller moves the player into the sloped surface, only to then be pushed up by the physics engine. Super jittery, and with inconsistent movement speed.
4. Jumping- Not existent. The setup would have allowed for it to be added, but it wouldn’t have been good.

I accomplished all these goals while keeping using Logic Nodes, and I am going to show you the result and the things I learn along the way. This is not going to be a Tutorial, I think you will soon see why.

The funkiness of Armory
You probably know: Armory is not perfect. So there were quite a few unexpected hurdles I had to overcome during the creation of the new Controller. For example, did you know that the execution of Logic scripts is locked at 60 times per seconds? I did not. This results in the game showing you the same result of your Logic for a couple frames if you use on a Monitor with a higher refresh-rate than 60Hz, which I do, and you game runs at more than 60FPS as well. I think this was set up like this so the speed of the logic of the game would stay the same, regardless of its frame rate without any additional setup required. For my purpose I want to tie the “logic rate” to the frame rate, for which I needed to change a bit of Haxe code. Thanks to @BlackGoku36 for helping me find this bit.
In iron/Sources/iron/App.hx line 46 has to be deactivated:

line 46: // kha.Scheduler.addTimeTask(update, 0, iron.system.Time.delta);

and update(); added in line 113. This makes my installation of Armory different than anybody else’s, I hope someone can create a Pull request which adds UI functionality to switch between these two behaviors.
By the way, the value of iron.system.Time.delta is always 1/60. To get the real delta time of the program you need to use iron.system.Time.realDelta;. Of course the Time node uses .delta, so I have to change that as well.
For the program to work I needed to get the position where the Player collided with a wall, so I created a custom node for that. It will be available in logic_pack.

Another thing that left me scratching my head is that reroute knots, aside from being an incredibly useful tool to organize your nodes, sometimes have the side-effect of breaking your program. When using a reroute knot with the modified Time node the value returned by the knot was not the time between frames, no no, it was the time for how long the game has been running for. I have no idea why, all I could do is avoid this case. Similarly when using knots to route the Cast Physics Ray -> Normal output, it sometimes becomes NaN. Again no idea why, just don’t do it.
On the subject of Cast Physics Ray -> Normal, when using this output to calculate something multiple times in one go the time the program needs to calculate the logic drastically increases, the longer this calculation is done the worse it gets Kind of as it would recourse and add a loop every frame. To “fix” this I set the value of a Vector to the value of the Normal once, and then for then keep on calculating everything using this saved Vector.

Creating the Logic
My idea was to keep the whole thing as mathematically as possible, so I have full control over everything that is going on. But I still needed to apply a Rigidbody to the player-object to get information on collisions and to also handle minor bumps on the ground, for which the old method of letting the physics engine push up the Player still works. Every frame the Physics-velocity is set to 0, so any freak collision won’t cause the Player to slide away.
The Player’s input is calculated into a raw movement vector. This already includes smooth acceleration.

Then a ray is cast downwards to figure out if the Player is grounded. If he is, the jump input is looked at and movement takes place. If he is not, “fake gravity” will take place.

Next up the raw movement vector gets rotated so it is parallel to the face the Player is standing on and still pointing into the correct direction.

After that it looks for a collision with a wall and then looks if the movement vector is pointing at the wall. If that is the case, the movement vector is “squished” so it becomes parallel to the wall, and the Player is being moved by that Vector. If not, this the Player is translated by the previous movement vector. The logic also covers the case that the Player is not currently colliding with a wall but will be placed inside one if the current movement vector would be used, as well as a few other edge cases.


Because the vector gets “squished” against the wall its length -> the speed of the Player changes, which needs to be updated in the Raw movement Vector.

Of course the Player needs to be slowed down if he is not pressing any movement buttons. That is take care of here:

This also takes care of not slowing the Player down while he is in air.

Maybe you noticed that I multiply Values a bunch of times by Time -> Delta. I do this to keep the speed of the Player constant, regardless of the frame rate of the game.

Downsides of this Controller

  1. It currently requires a modified version of Armory.
  2. This setup is only suitable in very static environments. Because the Physics-velocity is set to zero every frame the Player can not be pushed around by moving objects, including moving platforms.

Here is the .blend if you want to take a look at it yourself. You can use it if you want to, just remember to modify your Armory installation. FPS.blend (1.5 MB) Video

5 Likes

Hello @Simonrazer,

As much as I like your good FPS node setup, It is quite complicated. Such an elaborate node-setup for a good FPS controller means there is something wrong with Armory3d, specifically the Physics engine. You almost do not use any physics at all in the whole setup, not even real gravity. Why is that the case? and why did you not use the “Set Velocity” node? I intend to rectify any physics related issues, so I need some pointers to know what exactly is wrong.

Thank you in advance.

1 Like

Unfortunately not providing a good character controller out-of-the-box is a running theme with Physics engines, at least with physx and bullet. They do provide some kind of kinematic character controller for starting up but usually they have a lot of issues and you basically end up rewriting your own to fit in your game.
What I meant by all of that is that is not unusual to write your controller from the ground up because they require a lot of refinement. And such requirements usually don’t fit rigid bodies right, because of collision resolution and other stuff. So you might end up using very little of the actual engine physics when creating a character controller for certain type of games.

bindings for a kinematic character controller existed in previous versions of armory but it had a few different issues that you couldn’t change easily because those were “inherited” from the original c++ version. I’ve seen that last years the kinematic controller has been updated in Bullet repo but it would require an update on armory part to check if it’s really worth it instead of just using very limited features of rigid bodies, or none at all.

3 Likes

I agree with what you say about “certain types of games”. But, for most of the usual FPS games, accurate FPS control must be possible with a lot simpler physics nodes, or at least that is what I think. By usual games I mean, character to be able to accelerate and decelerate, climb and decent on ramps/slopes, Jump and also step on and stay on moving platforms. This is all possible using very simple node setup, correct weights, gravity and friction setting of rigid bodies.

What exactly do you mean by “Collision Resolution” ?

By collision resolution I mean this https://en.wikipedia.org/wiki/Collision_response. The collision resolution of Bullet’s rigidbodies is very problematic with ramps/slopes, so even something so simple as going up / going down / jumping on a ramp can be quite tricky to pull off with the right feeling to it using rigidbodies.

1 Like

To make the whole thing much simpler by using only physics Nodes Armory would need to have a magically good Physics engine, which does not exist. I tried using Set Velocity and even Apply Force, but a) using Set Velocity does not make things simpler in this case at all b) Apply Force makes things even more complicated. This is the case because in the end it always feels better to calculate the direction the Player should be moving compared to brute-force pushing the Player the way he wants to go and the having the Physics engine make up something useful of that.

1 Like