Tal Soikis
Two weeks ago, I decided to get “back” into game dev. And I must admit that after 2 months of traveling and barely touching or even looking at code, I got a bit rusty; and I wish it was the kind of rust that gets you a job and impresses your friends, but unfortunately, it’s not. yet.
I started working on an fps game idea I had - more on that in a future post. But, since I don’t have any real recent experience with game dev, I’m learning the math, algorithms, and topics as I go.
Whether it’s an FPS, RTS, Walking Simulator, or a Card Game, the first thing you need is a way to control whatever you’re playing as. I think.
So, I started working on my first-person movement controller. I initially followed a basic tutorial, like all sane people learning a new topic should.
“Computers are good at following instructions, but not at reading your mind.”
— Donald Knuth
When I finished the tutorial, I decided to polish the movement by making it gradually slow down and speed up on user input.
For that, I needed to find another example code to learn from and apply that to my code. Easy peasy.
The only issue was that I couldn’t understand the code I found because it was using some math I didn’t quite get or a different version of gdscript from what I’m using or another language and engine altogether.
So, I had to either translate it, learn the math, or wing it. And even though my mom says I’m her little angel, I don’t really have wings. So of course, I went for winging it.
So, all I need to do is, based on movement input only, decrease or increase the character speed. My first attempts either completely reversed the character movement or broke it entirely.As time went on, I was able to make the D
key make the character move right which is perfect, and the W
key move diagonally, which is somewhat forward I guess?
Anyway, to fix the issues, I started using dot and cross products to get the angles and directions between my camera’s forward direction and the inputs to figure out whether I need to accelerate or decelerate.
Now, if that sounds wrong to you, then congratulations🥳! You found my initial mistake. But for me, it took a little longer to get it.
After some time debugging and growing more frustrated and tired, I started brute forcing my way through the mathematical operands in the formulas (which got me close to the solution, which is nice… I guess…? No! Bad Tal!). By this time it got pretty late at night, and I was getting hungry, which never helped me solve problems.
So, I decided to take a little break and go get myself some fries, which I heard from someone that there’s a good fries place near me.
On my way there, my thoughts were racing:
“What vector magic am I missing here?”
“Why the fuck is my player moving diagonally when I press W
?”
“And why the hell doesn’t it move when I press A
?”
Luckily, when I got there, the smell of fries in the air and the vintage diner look of the place distracted me from my “very important” problems.
When my brain got free, I was able to solve the real issues I faced, “which fries do I order”?
While I was waiting for my 1 kind of Peruvian potato out of the thousands(!) they have there to become perfectly golden fried, I suddenly had a thought:
“What if I’m overthinking and I can just see if the player is pressing on any input and just ignore the direction of the input altogether?”
I mean, do I really care whether the player moves in a specific direction or do I just need to care that the player was moving in the previous frame and now they don’t?
Thankfully, I brought my laptop with me, so I whipped it out (the laptop that is), and implemented my new solution. After about 1 minute of rearranging some code and inputting simpler values to a lerp function, I started my game and VOILA! it worked! I was ecstatic, and now I was ready to celebrate with some really good fries!
A couple of mornings later, after a good night’s sleep, I thought about my problem again when I realized - I had no idea what some of my variables mean; specifically in Godot, and generally in math.
After some thinking with myself, I understood I was using the camera’s local transform which is the direction my viewport is looking at, as my forward vector. Which sounds like a bug to me, since I could be moving backward and looking forward, but my direction of movement was backward. That “direction of movement” is also known as velocity, normalized.
When I used the dot product between the normalized velocity and the normalized input vector to find whether I needed to decelerate or accelerate everything worked flawlessly! Not only that, but I was able to implement a different deceleration for when no input is given which means the player should stop, and for when the player wants to change direction which I feel needs to be snappier. WOOHOO!
So, my point here is… well I actually have 2 points:
Those are things I knew, and I’m sure you also know. And yet, I personally kind of ignore it, so I guess I need to listen to myself a bit more. Either that or eat more fries.